.net4.0 动态类型和动态编程之3行搞定一个语音朗读器

今天无意中在 mop 上闲逛发现一个帖子,点了进去帖子内容不多,但学到一个东西。
大概是:
CreateObject("SAPI.SpVoice").Speak "I LOVE YOU"  

用文本文件编写 ( 开始 - 程序 - 附件 - 记事本 ) 后保存为 .VBS
点击这个 vbs 运行你的电脑就会将  I LOVE YOU 朗读出来,不过不同的操作系统朗读出来声音不一样, xp 是一位大叔的声音, win7 确实以为小萝莉的声音。
下面来看一下这个 SAPI.SpVoice 到底是什么东东。。
 
如此一来便有了自己造一个轮子的想法,然后就开始到 msdn 上查找相关资料。

文档来源
http://msdn.microsoft.com/en-us/library/ms723602(VS.85).aspx

SpVoice

SpVoice 对象带来了文字到应用程序使用的 SAPI 自动化语音转换( TTS )引擎功能。  
应用程序可以创建无数 SpVoice 对象,每个独立和与人交往的能力。   一个 SpVoice 对象,通常简称为一个声音,是创建具有默认属性设置,以便它已准备好立即发言。
 
SpVoice 自动化对象有下列内容:
下面是是SAPI.SpVoice 对象的一些说明 (自己整理的有些地方可能跟官方的有差异) 

 

属性列表说明
属性
描述
AlertBoundary
获取并设置警戒范围,它指定如何说话的声音暂停警报本身。
AllowAudioOutputFormatChangesOnNextSet
获取并设置标志,指定是否允许调整声音输出格式的音频自动。
AudioOutput
获取并设置当前的音频输出对象的声音使用。
AudioOutputStream
获取并设置当前音频流对象使用的声音。
EventInterests
获取并设置了语音接收到的事件的类型。
Priority
获取并设置优先级的声音。
Rate
获取和设置声音说话速度。
Status
返回当前的发言和事件的声音地位1 ISpeechVoiceStatus对象。
SynchronousSpeakTimeout
获取并设置时间间隔,以毫秒为单位,在这之后的声音的同步发言和SpeakStream调用将超时当它的输出设备不可用。
Voice  
获取和设置当前活动的声音集合的成员。
Volume
获取并设置相应的体积(响度)的语音水平。
 
方法列表说明
方法
参数
返回值
描述
DisplayUI(
     hWndParent As Long,
     Title As String,
     TypeOfUI As String,
     [ExtraData As Variant = Nothing]
)
 

参数

hWndParent
指定的窗口句柄所属的窗口。
标题
指定使用的用户界面窗口的标题。
TypeOfUI
A String specifying the name of the UI to display. For a list of available SAPI 5 UI, see  Engine User Interfaces.
ExtraData
[ 可选 ] 指定 ExtraData   此信息是独一无二的应用程序,可以用来提供额外的或更具体的信息到用户界面。   默认情况下,没有任何价值,并指出使用的用户界面不使用任何额外的信息用这种方法提供的。
 
启动指定的用户界面显示。
SpVoice .GetAudioOutputs(
     [RequiredAttributes As String = ""],
     [OptionalAttributes As String = ""]
) As ISpeechObjectTokens
 

参数

RequiredAttributes
[ 可选 ] 指定 RequiredAttributes   要返回 GetAudioOutputs ,音频输出令牌必须包含所有属性的具体要求。   如果没有标记匹配的选择,选择返回的将不包含任何元素。   默认情况下,没有属性是必需的,因此该方法返回所有的标记发现。
OptionalAttributes
[ ] 指定 OptionalAttributes   返回令牌包含 RequiredAttributes 是由 OptionalAttributes 排序。   如果 OptionalAttributes 指定,令牌所列 OptionalAttributes 第一。   默认情况下,没有属性指定的讲话,从配置数据库返回的列表属性的顺序被发现的。
 
一个 ISpeechObjectTokens 集合包含选定的产出。
 
可用的音频输出令牌返回一个选择。
SpVoice .GetVoices(
     [RequiredAttributes As String = ""],
     [OptionalAttributes As String = ""]
)  As ISpeechObjectTokens
 

参数

RequiredAttributes
[ 可选 ] 指定 RequiredAttributes   挑选符合这些规格的声音。   如果没有匹配的声音选择,选择将返回包含任何声音。   默认情况下,没有属性是必需的,所以列表返回所有的标记发现。
OptionalAttributes
[ ] 指定 OptionalAttributes   这些规范相匹配的声音将返回在选择面前。   默认情况下,没有属性指定的讲话,从配置数据库返回的列表属性的顺序被发现的。
 
返回值: 一个 ISpeechObjectTokens 变量包含了语音收集令牌选中。
返回一个声音可供选择的声音。
SpVoice .IsUISupported(
     TypeOfUI As String,
     [ExtraData As Variant = Nothing]
) As Boolean
 

参数

TypeOfUI
A String specifying the name of the UI to display. For a list of available SAPI 5 UI, see  Engine User Interfaces.
ExtraData
[ 可选 ] 指定 ExtraData   此信息是独一无二的应用程序,可以用来提供额外的或更具体的信息到用户界面。   默认情况下,没有任何价值,并表明使用的用户界面不使用任何额外的信息用这种方法提供的。
 
返回值: 一个布尔变量指示是否支持指定的用户界面。   它返回 True ,如果支持,如果不支持或 False
如果指定的用户界面是支持的确定。
SpVoice .Resume()
 
原因恢复说话的声音时暂停。
SpVoice .Pause()
 
暂停的声音在最近的警报和关闭边界的输出设备,允许它被用于其他的声音。
SpVoice .Skip(
     Type As String,
     NumItems As Long
)  As Long
 

参数

类型:
该项目类型被跳过。   目前,一句是唯一一种支持。
NumItems
该项目的数目,跳过了在语音输入流。   负的值指定跳绳落后。
 
返回值: 一个长整型变量包含的项目数跳过。
导致声音向前或向后跳过由内当前输入文本流项规定的数量。
SpVoice .Speak(
     Text As String,
     [Flags AsSpeechVoiceSpeakFlags = SVSFDefault]
)  As Long

Text  要说的内容

返回值: 一个长整型变量包含事件处理。
启动一个文本字符串,文本文件或波形文件的声音说话
SpVoice .SpeakCompleteEvent()As Long
 

返回值: 一个长整型变量包含事件处理。
获取事件处理将要完成的声音信号时,说话的声音。
SpVoice .SpeakStream(
     Stream AsISpeechBaseStream,
     [Flags AsSpeechVoiceSpeakFlags = SVSFDefault]
) As Long
 

参数:Stream指定一个ISpeechBaseStream对象,包含流。Flags [可选]指定的标记。 默认值是SVSFDefault

 

返回值:一个长整型变量包含流的数目。 当一个声音enqueues通过讲多个异步流,流的数目要与相应的流关联的事件。

 
启动一个文本流或声音文件上的声音。
SpVoice .WaitUntilDone(
     msTimeout As Long
) As Boolean
 

参数

msTimeout
指定以毫秒为单位的超时。   如果 -1 ,时间间隔被忽略,方法简单的语音等待把话说完。

 

返回值

一个布尔变量,说明这种情况下,终止了通话。   如果为 True ,声音发言完毕 ; 若假,时间间隔时间。
阻止对方的声音,直到发言完毕或在指定的时间间隔已过。
 
此时了解了这个东西的基本信息之后于是就开始动工了。
由于这个是一个com对象,操作起来会有很多问题,之前,也就是最近吧,项目中出现了一个需要生成word的功能,那dcom对象把我搞得蛋疼,写代码没有提示,那时之痛苦实属罕见。
下面介绍个新东西
具体这里不做深入描述和讲解,主要针对这个朗读其相关进行介绍
C# 4.0 中的动态类型和动态编程:
dynamic  的使用范围
由于 dynamic 它本身就是一个类型,因此可以应用在任何需要类型的地方。
这些地方包括:
1 、变量声明;
2 、函数、委托、Lambda 表达式的参数类型,或者具备泛型的类型参数;
3 TypeOf 运算;
4 、类型转换以及 is, as 运算。
下面的代码动态的获取一个 COM 对象类型,并通过该类型创建这个 COM 对象的实例,并准备调用该实例上的一个方法实现我们需要的功能。
这个例子引用了 Speech API 中的 SAPI.SpVoice 对象,并调用了其 Speak() 方法。编译并运行此示例,我们通过计算机的音箱得到了正确的语音
 1: using System;
 3: Type type = Type.GetTypeFromProgID("SAPI.SpVoice");
 4: dynamic spVoice = Activator.CreateInstance(type);
 5: spVoice.Speak(" 我要说话")
优点:可以将返回不同模型类型的Action来使用同一个模板,只要你调用了它们都存在的属性或方法即可。
缺点:如果你调用了一个该类型中不存在属性或方法时,就会抛出一个RuntimeBinderException,所以在使用动态类型时我们要做好约束。 

 

搞懂了实现原理那么现在就开工吧

代码
  1  using  System;
  2  using  System.Collections.Generic;
  3  using  System.ComponentModel;
  4  using  System.Data;
  5  using  System.Drawing;
  6  using  System.Linq;
  7  using  System.Text;
  8  using  System.Windows.Forms;
  9  using  System.Threading;
 10  using  System.Diagnostics;
 11 
 12  namespace  Speak
 13  {
 14       public   partial   class  FrmSpeak : Form
 15      {
 16           public  FrmSpeak()
 17          {
 18              InitializeComponent();
 19          }
 20           // 动态创建的对象
 21           public   static  dynamic spVoice  =   null ;
 22           // 朗读要用的线程
 23           public  Thread speak  =   null ;
 24           // 要朗读的内容
 25           public   static   string  Content  =   string .Empty;
 26           ///   <summary>
 27           ///  开始朗读按钮事件
 28           ///   </summary>
 29           ///   <param name="sender"></param>
 30           ///   <param name="e"></param>
 31           private   void  btnSpeak_Click( object  sender, EventArgs e)
 32          {
 33               if  (txtContent.Text  !=   string .Empty)
 34              {
 35                   // 接受输入的文字
 36                  Content  =  txtContent.Text;
 37                   // 创建朗读的线程
 38                  speak  =   new  Thread( new  ThreadStart(Speak));
 39                  
 40                  speak.Start();
 41              }
 42               else
 43              {
 44                  Speak( " 请填写内容,以便朗读 " );
 45              }
 46               this .btnSpeak.Enabled  =   false ;
 47          }
 48           ///   <summary>
 49           ///  朗读方法
 50           ///   </summary>
 51           public   static   void  Speak()
 52          {
 53               try
 54              {
 55                   //
 56                  Type t  =  Type.GetTypeFromProgID( " SAPI.SpVoice " );
 57                  spVoice  =  Activator.CreateInstance(t);
 58                  spVoice.Speak(Content);
 59              }
 60               finally  
 61              {
 62                  MessageBox.Show( " 朗读完毕 " ); 
 63              }
 64          }
 65           ///   <summary>
 66           ///  朗读的方法
 67           ///   </summary>
 68           ///   <param name="speak"> 要朗读的内容 </param>
 69           public   static   void  Speak( string  speak)
 70          {
 71               try
 72              {
 73                  Type t  =  Type.GetTypeFromProgID( " SAPI.SpVoice " );
 74                  spVoice  =  Activator.CreateInstance(t);
 75                  spVoice.Speak(speak);
 76              }
 77               finally  { MessageBox.Show( " 有些细节没处理好 " ); }
 78          }
 79           ///   <summary>
 80           ///  暂停
 81           ///   </summary>
 82           ///   <param name="sender"></param>
 83           ///   <param name="e"></param>
 84           private   void  btnStop_Click( object  sender, EventArgs e)
 85          {
 86               // speak.Suspend();
 87               try
 88              {
 89                  spVoice.Pause();
 90                   this .btnSpeak.Enabled  =   true ;
 91              }
 92               finally
 93              {
 94                 
 95              }
 96          }
 97           ///   <summary>
 98           ///  继续朗读
 99           ///   </summary>
100           ///   <param name="sender"></param>
101           ///   <param name="e"></param>
102           private   void  btnContinue_Click( object  sender, EventArgs e)
103          {
104               // speak.Resume();
105               try
106              {
107                  spVoice.Resume();
108                   this .btnSpeak.Enabled  =   false ;
109              }
110               finally  {  }
111          }
112           ///   <summary>
113           ///  关闭窗口时关闭进程
114           ///   </summary>
115           ///   <param name="sender"></param>
116           ///   <param name="e"></param>
117           private   void  FrmSpeak_FormClosing( object  sender, FormClosingEventArgs e)
118          {
119              Process p  =  Process.GetCurrentProcess();
120              p.Kill();
121          }
122 
123      }
124  }
125 

 

 .net4.0 动态类型和动态编程之3行搞定一个语音朗读器_第1张图片

  

 

 
基本功能已经搞定,不过有很多问题没搞明白。
高端人士给解决一下
问题如下:
1 、使用 SAPI.SpVoice 对象里面的方法时方法执行完后必然会报错。
2 、关闭程序后 SAPI.SpVoice   调用 speak 的方法依然在朗读无法停止。(被逼无奈 closing 时结束进程)。
3 、线程执行时及时将线程停止或挂起   调用的 com 对象依然执行。
4. 在没有使用多线程之前,这个窗体点击开始说话后程序无法继续响应。
 
基本出现的问题就这些别的想不起来了。
  /Files/shan333chao/Speak.7z

 

你可能感兴趣的:(.net4.0 动态类型和动态编程之3行搞定一个语音朗读器)