使用VB.net 创建简单的TTS中英文混合语音朗读
最初的想法很简单,只是想弄个小程序可以实现单词朗读功能。我了解到TTS(Text-to-Speech)技术可以做到阅读文本文字,用的语音引擎是微软的Speech SAPI5.1SDK,搜索一下,网络上大把文章谈到这个,还会告诉你下载地址,大小在60M以上。我的运行环境是xpSP2不需要再去下载。打开你的“控制面板”,打开“语音”,是不是看到了2个语音引擎?一个叫"Microsoft Simplified Chinese",一个叫"MicrosoftSam",OK,让我们设置"Microsoft Simplified Chinese"为默认值。 接下来,当然是引用了
Imports
SpeechLib
现在开始重头戏了,我们在Form1_Load事件里面写上:
Dim
MyVoice
As
New
SpeechLib.SpVoice
Dim tmpStr As String tmpStr = " IloveChou! " MyVoice.Speak(tmpStr,SpeechVoiceSpeakFlags.SVSFlagsAsync) 按下F5运行,马上出来结果了,有声音了,耶!简单吧?
Dim
MyVoice
As
New
SpeechLib.SpVoice
Dim tmpStr As String tmpStr = " IloveChou! " MyVoice.Voice = MyVoice.GetVoices([ String ].Empty,[ String ].Empty).Item( 1 ) MyVoice.Speak(tmpStr,SpeechVoiceSpeakFlags.SVSFlagsAsync) 你再按F5运行一下。哇,真的可以耶~!太棒了!
Dim
language
As
String
=
"
MSSimplifiedChineseVoice
"
'
此处判断缺省语音引擎.英文为MSSam
MyVoice.Volume = 100 ' 设置音量,0到100 Dim cnVoice,enVoice As Integer 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 End If 似乎有点不对劲哦,如果我不止中文和英文这两个语音引擎怎么办? 呃,好吧,我承认我做的不够完美。你要想知道你都有哪些语音引擎,可以用枚举的办法,通过MyVoice.GetVoices.Count得到语音引擎的数量,再通过MyVoice.GetVoices.Item(i).Id得到每个语音引擎的名称(注意:此处id返回的是注册表里的值,也可以用MyVoice.GetVoices.Item(0).GetDescription得到语音引擎的描述,随便你喜欢哪一种)。只是这已经不在本文讨论范围内了,本文只想说说简单的效果。 你脑筋转得很快,又问:“如果我要中英文混合来读,该怎么办呢?” 这个问题问得好,首先,你必须懂得判断一个字符到底是中文字符,还是英文字符。 这里通过ascii来判断,我们另外写一个函数:
Private
FunctionisChinese(ByValasciivAsInteger)AsBoolean
Try IfLen(Hex$(asciiv))>2Then isChinese=True Else isChinese=False EndIf CatchexAsException EndTry EndFunction 举个例子,引用这个函数: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
As
String="你真是lucky.I服了you."
Dim strDestination As String=Mid(strSource,1,1) Dim i As Integer Dim strSelect As String="" Dim splitKey As String = " /HarryGlory/ " ' 这里可以改变临时分割用的关键词,这个关键词一定不能在文章中出现 ' 以下for语句功能是把中英文用splitKey分开 For i = 2 To Len (strSource) strSelect = Mid (strSource,i, 1 ) If isChinese( Asc (strSelect)) Then ' 如果是中文 If isChinese( Asc (Strings.Right(strDestination, 1 ))) Then ' 如果前一个字符是中文 strDestination = strDestination & Mid (strSource, 1 ) Else strDestination = strDestination & splitKey & Mid (strSource, 1 ) End If ' strDestination=strDestination+Mid(strSource,1) Else ' 如果不是中文 If isChinese( Asc (Strings.Right(strDestination, 1 ))) Then ' 前一个字符是中文 strDestination = strDestination & splitKey & Mid (strSource, 1 ) Else strDestination = strDestination & Mid (strSource, 1 ) End If End If Next i
Dim
a(),p
As
String
a = Split (strDestination,splitKey) 以下代码实现逐句朗读
Dim
OK
As
Boolean
=
True
'
OK为true的时候读中文
If isChinese( Asc (a( 0 ))) Then ' 如果第一个字符是中文 OK = True Else ' 如果第一个字符不是中文 OK = False End If ' 以下语句是逐句朗读 For Each 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 End If Next
在使用微软的tts的speak方法时,需要输入一个SpeechVoiceSpeakFlags参数,该类型有多个枚举。由于没有中文,自己翻译与共享之。
SVSFDefault 默认为:读取给定的文本,被SVSFlagsAsync(异步)重写。 在播放期间的请求不会被清空,被SVSFPurgeBeforeSpeak重写。 只有当指定的文本以“<”开头才会使用XML方式解析,被SVSFIsXML和SVSFIsNotXML重写。 不保留全局XML状态变化(此处翻译有压力)。。。,被SVSFPersistXML重写。 标点符号不扩展为单词,被SVSFNLPSpeakPunc重写。 (旁白:通过default大概了解了此枚举类型的大概) SVSFlagsAsync 播报调用为异步,所以播报请求一发送,就马上回应。 SVSFPurgeBeforeSpeak 在播报期间,不接受其他的播报请求。
SVSFIsXML 文本以XML形式解析。
SVSFIsNotXML 文本不以XML形式解析。
SVSFPersistXML 不会翻译
SVSFNLPSpeakPunc 把标点符号也读出来。
其他类型就不翻译了。 ~~~ 个人实操: 在前台的js用async:true,保证了网页顺利加载。 在后台的CS用 SpeechVoiceSpeakFlagsspFlags=SpeechVoiceSpeakFlags.SVSFDefault; SpVoicevoice=newSpVoice(); voice.Speak(strContent,spFlags); 保证了在网页端点击任何东西都不会停止播报——在播放期间的请求不会被清空。
??
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |