您的位置:首页 > 编程语言 > C#

用C#语音合成与识别 C#文章

2009-11-04 09:33 363 查看
 在.net中,对英文语音有较好的支持,但是对中文语音的支持还没有加入进来,我们要想实现中文发音或中文语音识别,必需先安装微软的speech application sdk(sasdk),它的最新版本是 sapi 5.1 他能够识别中、日、英三种语言,你可以在这里下载:http://www.microsoft.com/speech/download/sdk51/,需要安装这两个文件speech sdk 5.1和5.1 language pack,其中5.1 language pack可以选择安装支持的语言。

  安装好以后,我们就可以开始进行语音程序的开发了,当然,在这之前我们需要把sapi.dll通过如下图所示添加到引用中

  下面我们设计一个能够朗读中英文混合语言的类:

  我们将用单例模式实现该类,类的代码如下,我们将详细解释:

public class speach
{
 private static speach _instance = null ;
 private speechlib.spvoiceclass voice =null;
 private speach()
 {
  buildspeach() ;
 }

public static speach instance()
{
 if (_instance == null)
  _instance = new speach() ;
  return _instance ;
}

private void setchinavoice()
{
 voice.voice = voice.getvoices(string.empty,string.empty).item(0) ;
}

private void setenglishvoice()
{
 voice.voice = voice.getvoices(string.empty,string.empty).item(1) ;
}

private void speakchina(string strspeak)
{
 setchinavoice() ;
 speak(strspeak) ;
}

private void speakenglishi(string strspeak)
{
 setenglishvoice() ;
 speak(strspeak) ;
}

public void analysespeak(string strspeak)
{
 int icbeg = 0 ;
 int iebeg = 0 ;
 bool ischina = true ;
 for(int i=0;i<strspeak.length;i++)
 {
  char chr = strspeak[i] ;
  if (ischina)
  {
   if (chr<=122&&chr>=65)
   {
    int ilen = i - icbeg ;
    string strvalue = strspeak.substring(icbeg,ilen) ;
    speakchina(strvalue) ;
    iebeg = i ;
    ischina = false ;
   }
  }
  else
  {
   if (chr>122||chr<65)
   {
    int ilen = i - iebeg ;
    string strvalue = strspeak.substring(iebeg,ilen) ;
    this.speakenglishi(strvalue) ;
    icbeg = i ;
    ischina = true ;
   }
  }
 }//end for
 if (ischina)
 {
  int ilen = strspeak.length - icbeg ;
  string strvalue = strspeak.substring(icbeg,ilen) ;
  speakchina(strvalue) ;
 }
 else
 {
  int ilen = strspeak.length - iebeg ;
  string strvalue = strspeak.substring(iebeg,ilen) ;
  speakenglishi(strvalue) ;
 }
}

private void buildspeach()
{
 if (voice == null)
  voice = new spvoiceclass() ;
}

public int volume
{
 get
 {
  return voice.volume ;
 }
 set
 {
  voice.setvolume((ushort)(value)) ;
 }
}

public int rate
{
 get
 {
  return voice.rate ;
 }
 set
 {
  voice.setrate(value) ;
 }
}

private void speak(string strspeack)
{
 try
 {
  voice.speak(strspeack,speechvoicespeakflags.svsflagsasync) ;
 }
 catch(exception err)
 {
  throw(new exception(发生一个错误:+err.message)) ;
 }
}

public void stop()
{
 voice.speak(string.empty,speechlib.speechvoicespeakflags.svsfpurgebeforespeak) ;
}

public void pause()
{
 voice.pause() ;
}

public void continue()
{
 voice.resume() ;
}

}//end class

  在 private speechlib.spvoiceclass voice =null;这里,我们定义个一个用来发音的类,并且在第一次调用该类时,对它用buildspeach方法进行了初始化。

  我们还定义了两个属性volume和rate,能够设置音量和语速。

  我们知道,spvoiceclass 有一个speak方法,我们发音主要就是给他传递一个字符串,它负责读出该字符串,如下所示。

private void speak(string strspeack)
{
  try
 {
  voice.speak(strspeack,speechvoicespeakflags.svsflagsasync) ;
 }
 catch(exception err)
 {
  throw(new exception(发生一个错误:+err.message)) ;
 }
}
  其中speechvoicespeakflags.svsflagsasync表示异步发音。



<script>zmbbs=1;</script>

  但是,这个方法本身并不知道你给的字符串是什么语言,所以需要我们它这个字符串用什么语言读出。spvoiceclass 类的voice 属性就是用来设置语种的,我们可以通过spvoiceclass 的getvoices方法得到所有的语种列表,然后在根据参数选择相应的语种,比如设置语种为汉语如下所示:

private void setchinavoice()
{
 voice.voice = voice.getvoices(string.empty,string.empty).item(0) ;
}
  0表示是汉用,1234都表示英语,就是口音不同。

  这样,我们就设置了语种,如果结合发音方法,我们就可以设计出一个只发汉语语音的方法

private void speakchina(string strspeak)
{
 setchinavoice() ;
 speak(strspeak) ;
}
  只发英语语音的方法也是类似的,上面程序里有。

  对于一段中英文混合的语言,我们让程序读出混合语音的方法就是:编程把这段语言的中英文分开,对于中文调用speakchina方法,英文调用speakenglishi方法;至于怎样判断一个字符是英文还是中文,我采用的是判断asc码的方法,具体的类方法是通过analysespeak实现的。

  这样,对于一段中英文混合文字,我们只需把它作为参数传递给analysespeak就可以了,他能够完成中英文的混合发音。

  当然,对于发音的暂定、继续、停止等操作,上面也给出了简单的方法调用,很容易明白。

  下面简单介绍一下中文语音识别的方法:

  先把该语音识别的类源代码贴在下面,然后再做说明:

public class sprecognition
{
 private static sprecognition _instance = null ;
 private speechlib.ispeechrecogrammar isrg ;
 private speechlib.spsharedrecocontextclass ssrcontex =null;
 private system.windows.forms.control cdisplay ;
 private sprecognition()
 {
  ssrcontex = new spsharedrecocontextclass() ;
  isrg = ssrcontex.creategrammar(1) ;
  speechlib._ispeechrecocontextevents_recognitioneventhandler rechandle = new _ispeechrecocontextevents_recognitioneventhandler(contexrecognition) ;
  ssrcontex.recognition += rechandle ;
 }

 public void beginrec(control tbresult)
 {
  isrg.dictationsetstate(speechrulestate.sgdsactive) ;
  cdisplay = tbresult ;
 }
 public static sprecognition instance()
 {
  if (_instance == null)
   _instance = new sprecognition() ;
   return _instance ;
 }

 public void closerec()
 {
  isrg.dictationsetstate(speechrulestate.sgdsinactive) ;
 }
 private void contexrecognition(int iindex,object obj,speechlib.speechrecognitiontype type,speechlib.ispeechrecoresult result)
 {
  cdisplay.text += result.phraseinfo.gettext(0,-1,true) ;
 }
}
  我们定义了ssrcontex 和isrg为语音识别的上下文和语法,通过设置isrg的dictationsetstate方法,我们可以开始或结束识别,在上面的程序中是beginrec和closerec方法。cdisplay 是我们用来输出识别结果的地方,为了能够在大部分控件上都可以显示结果,我用了一个control 类来定义它。当然,每次语音识别后都会触发ispeechrecocontextevents_recognitioneventhandler 事件,我们定义了一个这样的方法contexrecognition来响应事件,并且在这个方法里输出识别结果。

  这样,中文语音处理的一些最基本的问题就有了一个简单的解决方法,当然,这种方法还有很多不完善的地方,希望大家多提出批评意见,共同提高。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息