使用VB.net 建立簡單的TTS中英文混合語音朗讀
阿新 • • 發佈:2019-02-02
最初的想法很簡單,只是想弄個小程式可以實現單詞朗讀功能。我瞭解到TTS(Text-to-Speech)技術可以做到閱讀文字文字,用的語音引擎是微軟的Speech SAPI5.1 SDK,搜尋一下,網路上大把文章談到這個,還會告訴你下載地址,大小在60M以上。我的執行環境是xpSP2不需要再去下載。開啟你的“控制面板”,開啟“語音”,是不是看到了2個語音引擎?一個叫"Microsoft Simplified Chinese",一個叫"Microsoft Sam",OK,讓我們設定"Microsoft Simplified Chinese"為預設值。
一切就緒,我們先在工程裡引用saip.dll,這個檔案在我的電腦里路徑是C:/Program Files/Common Files/Microsoft Shared/Speech/saip.dll (Written by HarryGlory .)
接下來,當然是引用了
Imports SpeechLib現在開始重頭戲了,我們在Form1_Load事件裡面寫上:
Dim MyVoice AsNew SpeechLib.SpVoiceDim tmpStr AsString
tmpStr ="I love Chou!"
MyVoice.Speak(tmpStr, SpeechVoiceSpeakFlags.SVSFlagsAsync)
按下F5執行,馬上出來結果了,有聲音了,耶!簡單吧?
什麼?你聽到的是一個一個字母讀出來?試試把tmpStr改成中文 "我愛周星星!
但是你很執著,想讀英文單詞,那怎麼辦?
OK,讓我們稍微改一下程式碼,如下: Dim MyVoice AsNew SpeechLib.SpVoice
Dim tmpStr AsString
tmpStr ="I love Chou!"
MyVoice.Voice = MyVoice.GetVoices([String].Empty, [String].Empty).Item(1)
MyVoice.Speak(tmpStr, SpeechVoiceSpeakFlags.SVSFlagsAsync)
你再按F5執行一下。哇,真的可以耶~!太棒了!
你很聰明,知道了這裡Item(0)表示中文朗讀,Item(1)表示英文朗讀。可是,怎麼判斷語音引擎呢?順便設定一下音量啊。呵呵,可以這樣做的:
MyVoice.Volume =100'設定音量,0到100
Dim cnVoice, enVoice AsInteger
If Strings.Right(MyVoice.GetVoices.Item(0).Id, language.Length) = language Then'如果Item(0)是中文
cnVoice =0
enVoice =1
Else'如果Item(0)是英文
cnVoice =1
enVoice =0
EndIf
似乎有點不對勁哦,如果我不止中文和英文這兩個語音引擎怎麼辦?
呃,好吧,我承認我做的不夠完美。你要想知道你都有哪些語音引擎,可以用列舉的辦法,通過MyVoice.GetVoices.Count得到語音引擎的數量,再通過MyVoice.GetVoices.Item(i).Id得到每個語音引擎的名稱 (注意:此處id返回的是登錄檔裡的值,也可以用MyVoice.GetVoices.Item(0).GetDescription得到語音引擎的描述,隨便你喜歡哪一種)。只是這已經不在本文討論範圍內了,本文只想說說簡單的效果。
你腦筋轉得很快,又問:“如果我要中英文混合來讀,該怎麼辦呢?”
這個問題問得好,首先,你必須懂得判斷一個字元到底是中文字元,還是英文字元。
這裡通過ascii來判斷,我們另外寫一個函式: PrivateFunction isChinese(ByVal asciiv AsInteger) AsBoolean
Try
IfLen(Hex$(asciiv)) >2Then
isChinese =True
Else
isChinese =False
EndIf
Catch ex As Exception
EndTry
End Function
舉個例子,引用這個函式:isChinese(Asc("我")),對了,這個函式我們只用來判斷一個字元,千萬不要寫多,不能把"我愛周星星!"全部寫進去哦。
寫完了這個函式,記得返回Form1_load事件裡面,我們繼續。
你努力想了想,問:“那我要讀一句中英文混合的話,只要用strings.mid語句把這句話一個字元一個字元地讀出來,然後判斷是中文還是英文字元,最後交給語音去朗讀就可以了,對不對?”
我哈哈大笑,說:“你的作法沒錯,可以實現朗讀功能,而且也是準確地區分了語音引擎,可是,逐個字元讀的話,一個完整的單詞也會讓你讀成字母啊!而且每個字元切換一次語音引擎,很消耗系統資源的,這樣做有什麼意義呢?”
最好的辦法是,將中英文區分開來,並且用自定義的關鍵詞把它們連接出來,最後通過split語句將它分成陣列,這樣就OK了。
比如,一句"你真是lucky. I 服了 you.",我們先用關鍵詞"/HarryGlory/"將它們分成
"你真是"/HarryGlory/lucky. I "/HarryGlory/服了"/HarryGlory/ you."
最終通過split語句用陣列儲存起來,將其分成
a(0)="你真是"
a(1)="lucky. I "
a(2)="服了"
a(3)="you."
明白了嗎?中英文是間隔地出來的,這是關鍵!這樣我們可以很方便地根據陣列的序號,設定當其為偶數時,用中文語音朗讀,奇數時用英文語音朗讀了!
這個功能也可以拓展開來,如果你只要判斷、讀取中文,那就只取序號為偶數的陣列就可以了,哈哈,方便吧?
當然,關鍵詞這一步驟顯得多餘和麻煩了點,你可以自己去試試直接用陣列來分開儲存的,呵呵,就當是作業吧。
以下程式碼通過關鍵詞將中英文分開:
Dim strSource AsString="你真是lucky. I 服了 you."
Dim strDestination AsString=Mid(strSource, 1, 1)
Dim i AsInteger
Dim strSelect AsString=""
Dim splitKey AsString="/HarryGlory/"'這裡可以改變臨時分割用的關鍵詞,這個關鍵詞一定不能在文章中出現
'以下for語句功能是把中英文用splitKey分開
For i =2ToLen(strSource)
strSelect =Mid(strSource, i, 1)
If isChinese(Asc(strSelect)) Then'如果是中文
If isChinese(Asc(Strings.Right(strDestination, 1))) Then'如果前一個字元是中文
strDestination = strDestination &Mid(strSource, i, 1)
Else
strDestination = strDestination & splitKey &Mid(strSource, i, 1)
EndIf
'strDestination = strDestination + Mid(strSource, i, 1)
Else'如果不是中文
If isChinese(Asc(Strings.Right(strDestination, 1))) Then'前一個字元是中文
strDestination = strDestination & splitKey &Mid(strSource, i, 1)
Else
strDestination = strDestination &Mid(strSource, i, 1)
EndIf
EndIf
Next i
以下程式碼是實現陣列儲存剛才生成的結果
a =Split(strDestination, splitKey)
以下程式碼實現逐句朗讀
Dim OK AsBoolean=True'OK為true的時候讀中文
If isChinese(Asc(a(0))) Then'如果第一個字元是中文
OK =True
Else'如果第一個字元不是中文
OK =False
EndIf
'以下語句是逐句朗讀
ForEach p In a
If OK Then
MyVoice.Voice = MyVoice.GetVoices([String].Empty, [String].Empty).Item(cnVoice)
MyVoice.Speak(p, SpeechVoiceSpeakFlags.SVSFlagsAsync)
OK =False
Else
MyVoice.Voice = MyVoice.GetVoices([String].Empty, [String].Empty).Item(enVoice)
MyVoice.Speak(p, SpeechVoiceSpeakFlags.SVSFlagsAsync)
OK =True
EndIf
Next
整個過程就完成了,很簡單,是吧?趕緊執行一下啦,哈哈。
還可以進一步開發出更多功能,如放一個文字框輸入字串來朗讀,或者拖放文字檔案來朗讀,或者讀xml檔案,還有將朗讀的結果輸出為wav聲音檔案等等,這個就靠你自己發揮想象力啦!