“没声音,再好的戏也出不来。”这虽然是一句广告,但是也说出了一个道理,我们所开发的软件,特别是一些多媒体软件,要是能够发出声音,能说会道,将为我们的软件增添不少光彩。同时,我们面临的是一个老龄化的社会,将会有越来越多的视力不太好的老年人成为我们的用户,开始使用我们的软件,如果我们的软件能说会道,可以用语音的方式提示用户进行操作,这将大大增加软件的可用性,从而获得用户的喜爱。

那么如何才能让我们的软件能说会道呢?别着急,微软有解决办法,用微软提供的SAPI就可以让我们的软件能说会道。

什么是SAPI?

软件中的语音技术主要包括两方面的内容,一个是语音识别(speech recognition) ,另外一个是语音合成(speech synthesis),也即是文本语音转换系统(TTS)。TTS系统使用合成语音合成文本字符串和文件到声音音频流。而语音识别系统则是转换人类的声音语音流到可读的文本字符串或者文件。这两个工作,都是通过各种语音引擎来完成的。微软所提供的SAPI (全称The Microsoft Speech API),正是在应用程序和语音引擎之间提供一个高级别的接口,它实现了所有必需的对各种语音引擎的实时的控制和管理等低级别的细节。语音引擎通过DDI层(设备驱动接口)和SAPI进行交互,应用程序通过API层和SAPI通信。通过使用这些API,我们可以快速开发在语音识别或语音合成方面应用程序。SAPI 应用程序编程接口(API)明显的减少了构建一个使用语音识别和文本语音转换的应用程序所需要的高层代码,使语音技术更加容易使用并且更加扩大了应用的范围。虽然现在SAPI不是业界标准,但是应用非常广泛。

SAPI包括以下组件对象(接口):

(1)Voice Commands API。对应用程序进行控制,一般用于语音识别系统中。识别某个命令后,会调用相关接口是应用程序完成对应的功能。如果程序想实现语音控制,必须使用此组对象。

(2)Voice Dictation API。听写输入,即语音识别接口。

(3)Voice Text API。完成从文字到语音的转换,即语音合成。

(4)Voice Telephone API。语音识别和语音合成综合运用到电话系统之上,利用此接口可以建立一个电话应答系统,甚至可以通过电话控制计算机。

(5)Audio Objects API。封装了计算机发音系统。

其中Voice Text API,就是微软TTS引擎的接口,通过它我们可以很容易地建立功能强大的文本语音程序,金山词霸的单词朗读功能就用到了这些API,而目前几乎所有的文本朗读工具都是用SAPI开发的。在这里,我们使用的主要就是Voice Text API。

安装SAPI SDK

要使用SAPI让我们的软件能说会道,我们首先需要下载并安装SAPI SDK。首先从微软的网站上下载开发包: http://www.microsoft.com/speech/download/sdk51

下载完毕后,首先安装SpeechSDK51.exe,然后安装中文语言补丁包SpeechSDK51LangPack,If 如果我们想将SAPI作为我们软件的一部分,随着我们的软件重新发布,我们还需要安装SpeechSDK51MSM.exe。

安装好SAPI SDK后,即可开始在VS2010中使用SAPI让我们的软件能说会道了。

创建项目,添加SAPI的引用

这里,我们将创建一个普通的WinForm程序,它可以利用TTS朗读文本,也可以将文本文件通过TTS转换为声音文件,真正是一个“能说会道”的软件。首先,我们在VS2010中创建一个WinForm程序,并且将窗体设计如下:

中的Text Box用于显示我们要阅读的文本,而Combo Box控件用于显示系统中已经安装的所有语音,用户可以从中选择当前TTS使用的语音。

要在我们的项目中使用SAPI,我们还需要给项目添加SAPI的引用。用VS2010提供的添加引用功能,在添加引用对话框的COM标签页面中找到Microsoft Speech Object Library,将其添加到项目中。

SAPI所提供的各个类都在名字空间SpeechLib之下,所以在代码中我们还需要使用using SpeechLib,表示我们将使用这个名字空间。这样我们就可以使用SAPI所提供的各种类来实现语音合成或者是语音识别了。

创建SpVoice对象,初始化SAPI

SAPI的TTS都是通过SpVoice对象来完成的。SpVoice类是支持语音合成(TTS)的核心类。通过SpVoice对象调用TTS引擎,从而实现朗读功能。 SpVoice类有以下主要属性:

• Voice:表示发音类型,相当于进行朗读的人,通常我们可以通过安装相应的语音引擎来增加相应的语音。

• Rate:语音朗读速度,取值范围为-10到+10。数值越大,速度越快。

• Volume:音量,取值范围为0到100。数值越大,音量越大。

SpVoice有以下主要方法:

• Speak():完成将文本信息转换为语音并按照指定的参数进行朗读,该方法有Text和Flags两个参数,分别指定要朗读的文本和朗读方式(同步或异步等)。

• GetVoices():获取系统中的语音,用于指定SpVoice的Voice属性。

• Pause():暂停使用该对象的所有朗读进程。该方法没有参数。

• Resume():恢复该对象所对应的被暂停的朗读进程。该方法没有参数。

所以我们在窗体的构造函数中,首先需要完成SpVoice对象的创建,然后才能使用这个对象来朗读文本。 因为系统中可能有多个语音可供选择,所以我们在创建窗体的时候,同时需要用一个Combo Box控件列举出系统中所有的语音,并且选中默认的第一个语音。当窗体创建后,用户可以在这个Combo Box选择自己喜欢的语音来朗读文本。

C#代码// SpVoice对象,我们将使用这个对象来朗读文本

privateSpVoice m_spVoice;

privatevoidInit()

{

// 创建SpVoice对象

m_spVoice = newSpVoice();

// 枚举出系统中已经安装的语音,并将其填充到Combo Box控件中

foreach(ISpeechObjectToken Tokeninm_spVoice.GetVoices(string.Empty,string.Empty))

{

this.cmbVoices.Items.Add(Token.GetDescription(49));

}

// 默认选中第一个语音

cmbVoices.SelectedIndex = 0;

}

朗读文本

完成窗体的初始化,创建SpVoice对象之后,接下来我们就可以利用这个对象的Speak()方法来阅读Text Box控件中的文本了。

C#代码privatevoidbtnSpeak_Click(objectsender, EventArgs e)

{

// 获取用户在Combo Box中选择的语音索引

intnVoiceIndex =this.cmbVoices.SelectedIndex;

// 根据语音索引指定SpVoice的Voice属性,也就是指定使用何种语音

m_spVoice.Voice = m_spVoice.GetVoices(string.Empty,string.Empty).Item(nVoiceIndex);

// 使用SpVoice的Speak()方法阅读Text Box中文本

m_spVoice.Speak(this.textPreview.Text, SpeechVoiceSpeakFlags.SVSFlagsAsync);

}

在这里我们使用了SpVoice对象的一个最重要的函数Speak(),它的第一个参数就是我们要朗读的文本,而第二个参数则是朗读的方式,有同步,异步,XML文件等等。 这样,通过SpVoice对象的一个简单函数,我们就可以朗读Text Box控件中的文本内容了。

朗读文本文件

更多时候,我们不是阅读Text Box控件中输入的文本,而是阅读某些文本文件中的文字,这样,读取文本文件并将文字填充到Text Box控件中就成为一种必要了。

C#代码privatevoidbtnFileSelect_Click(objectsender, EventArgs e)

{

// 使用打开文件对话框选择文本文件

OpenFileDialog openFileDialog1 = newOpenFileDialog();

openFileDialog1.InitialDirectory = "e:\\";

openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";

openFileDialog1.FilterIndex = 2;

openFileDialog1.RestoreDirectory = true;

if (openFileDialog1.ShowDialog() == DialogResult.OK)

{

// 读取文本文件并将其填充到Text Box控件

StreamReader objReader = new StreamReader( openFileDialog1.FileName);

string sLine = "";

string sPreview = "";

while(sLine !=null)

{

sLine = objReader.ReadLine();

if(sLine !=null)

{

// 这里需要添加Environment.NewLine表示换行

sPreview += sLine + Environment.NewLine;

}

}

// 将文本文件中的内容显示到Text Box控件

this.textPreview.Text = sPreview;

// 关闭文件读取器

objReader.Close();

}

}

这样,我们就可以通过读取文本文件中的内容,将其显示到Text Box控件中,然后SpVoice就可以阅读Text Box控件中的内容,也就是间接地朗读了文本文件。

将文本转换成声音文件

除了直接朗读文本之外,更多的时候,我们还需要将文本转换成声音文件。这样我们可以将这些声音文件随身携带,想听就听。要将文本转换为声音文件,我们需要用到SpVoice的另外一个重要的函数SetOutput(),我们可以利用它将SpVoice的语音输出某个WAV文件,从而实现将文本文件转换为声音文件。

因为 将一段比较长的文本转换成声音文件,通常是一个比较长的过程,所以在这里我们创建一个专门的工作者线程来负责文本的转换,而界面线程则负责显示转换的进度。

C#代码// 工作者线程类

publicclassWorkerThread

{

// 用户选择的语音

privateintnVoiceIndex;

// 保存的文件名

privatestringstrFileName;

// 需要转换的文本

privateArrayList arrText;

// 构造函数,利用构造函数向线程传递参数

publicWorkerThread(intnIndex, ArrayList aText,stringsFileName )

{

nVoiceIndex = nIndex;

arrText = aText;

strFileName = sFileName;

}

// 线程开始事件

publiceventEventHandler threadStartEvent;

// 线程执行时的事件

publiceventEventHandler threadEvent;

// 线程结束事件

publiceventEventHandler threadEndEvent;

// 线程函数

publicvoidrunMethod()

{

// 创建SpVoice对象,并选择用户选中的语音

SpVoice voice = newSpVoice();

voice.Voice = voice.GetVoices(string.Empty,string.Empty).Item(nVoiceIndex);

try

{

// 创建流媒体文件

SpeechStreamFileMode SpFileMode =

SpeechStreamFileMode.SSFMCreateForWrite;

SpFileStream SpFileStream = newSpFileStream();

// 这里我们设置输出的频率,这样可以决定输出文件的大小

SpFileStream.Format.Type = SpeechAudioFormatType.SAFTCCITT_ALaw_8kHzMono;

// 还可以选择更高品质的格式,不过产生的文件体积更大

// SpFileStream.Format.Type = SpeechAudioFormatType.SAFT11kHz16BitMono;

// 创建文件,并将SpVoice的输出流指定为当前文件

SpFileStream.Open(strFileName, SpFileMode, false);

voice.AudioOutputStream = SpFileStream;

// 发送线程开始事件,通知主界面,设定进度条的最大值为Count

threadStartEvent.Invoke(arrText.Count, newEventArgs());

// 开始将文本输出到音频文件

intnCount = 0;

foreach(stringsOutputinarrText)

{

voice.Speak(sOutput, SpeechVoiceSpeakFlags.SVSFlagsAsync);

// 发送线程运行时事件,移动进度条的位置

threadEvent.Invoke(nCount, newEventArgs());

voice.WaitUntilDone(-1);

++nCount;

}

// 关闭音频文件

SpFileStream.Close();

}

catch

{

}

// 发送线程结束事件,通知主界面关闭进度条

threadEndEvent.Invoke(newobject(),newEventArgs());

}

}

跟直接朗读文本相似,我们仍旧使用SpVoice的Speak()函数朗读文本,只是我们通过指定SpVoice的AudioOutputStream属性,将语音输出到一个音频文件,这样就完成了文本文件到音频文件的转换。

完成转换工作者线程的创建后,我们就可以利用它来完成具体的转换工作。在窗体的保存按钮的单击响应函数中,我们创建相应的工作者线程来进行文本的转换。

C#代码privatevoidbtnSavetoWAV_Click(objectsender, EventArgs e)

{

stringstrWAVFile ="";

try

{

// 使用保存文件对话框,选择保存的文件

SaveFileDialog sfd = newSaveFileDialog();

sfd.Filter = "All files (*.*)|*.*|wav files (*.wav)|*.wav";

sfd.Title = "Save to a wave file";

sfd.FilterIndex = 2;

sfd.RestoreDirectory = true;

if(sfd.ShowDialog() == DialogResult.OK)

{

// 获取用户输入的文件名

strWAVFile = sfd.FileName;

// 从Text Box控件获取要转换的文本

ArrayList arrText = newArrayList();

foreach(String sLineinthis.textPreview.Lines)

arrText.Add(sLine);

// 显示进度条

progressForm = newForm2();

progressForm.Show();

// 创建工作者线程,并向工作者线程传递要转换的文本

WorkerThread myThreadFun = newWorkerThread(

this.cmbVoices.SelectedIndex, arrText, strWAVFile);

// 注册线程事件

myThreadFun.threadStartEvent += newEventHandler(method_threadStartEvent);

myThreadFun.threadEvent += newEventHandler(method_threadEvent);

myThreadFun.threadEndEvent += newEventHandler(method_threadEndEvent);

// 创建线程,执行工作者线程

Thread thread = newThread(newThreadStart(myThreadFun.runMethod));

// 启动线程

thread.Start();

}

}

catch

{

}

}

除了创建线程进行文本的转换之外,为了让我们的软件更加易用,更加人性化,我们还需要响应线程事件,移动进度条的位置以反映转换的进度,免得用户以为软件在比较长的转换过程中死掉了。

C#代码// 线程开始的时候调用的委托

privatedelegatevoidmaxValueDelegate(intmaxValue);

// 线程执行中调用的委托

privatedelegatevoidnowValueDelegate(intnowValue);

// 线程结束的时候调用的委托

privatedelegatevoidhideProgressDelegate(intn);

/// 线程完成事件,隐藏进度条窗口

// 但是我们不能直接操作进度条,需要一个委托来替我们完成

voidmethod_threadEndEvent(objectsender, EventArgs e)

{

hideProgressDelegate hide = newhideProgressDelegate(hideProgress);

this.Invoke(hide, 0);

}

/// 线程执行中的事件,设置进度条当前进度

/// 这里的sender,是WorkerThread 函数中传过来的当前值

voidmethod_threadEvent(objectsender, EventArgs e)

{

intnowValue = Convert.ToInt32(sender);

nowValueDelegate now = newnowValueDelegate(setNow);

this.Invoke(now, nowValue);

}

/// 线程开始事件,设置进度条最大值

/// 但是我不能直接操作进度条,需要一个委托来替我完成

///  这里的sender,是WorkerThread 函数中传过来的最大值

voidmethod_threadStartEvent(objectsender, EventArgs e)

{

intmaxValue = Convert.ToInt32(sender);

maxValueDelegate max = newmaxValueDelegate(setMax);

this.Invoke(max, maxValue);

}

///  被委托调用的函数,专门操作进度条

privatevoidsetMax(intmaxValue)

{

progressForm.progressBar1.Maximum = maxValue;

}

privatevoidsetNow(intnowValue)

{

progressForm.progressBar1.Value = nowValue;

}

privatevoidhideProgress(intn)

{

progressForm.Hide();

}

控制SpVoice的阅读

到这里,一个能说会道的软件基本上已经完成了,但是,为了让我们的软件更加易用,我们还可以通过SpVoice提供的函数对SpVoice的行为进行控制,让她更加符合我们的心意。例如,我们可以控制SpVoice的暂停和继续。

C#代码privatevoidbtnPause_Click(objectsender, EventArgs e)

{

if(this.btnPause.Text =="暂停")

{

// 让SpVoice暂停朗读

m_spVoice.Pause();

this.btnPause.Text ="继续";

}

else

{

// 让SpVoice继续朗读

m_spVoice.Resume();

this.btnPause.Text ="暂停";

}

}

通过SpVoice提供的函数,对SpVoice的行为进行控制就是这么简单。除了阅读的暂停和继续之外,我们还可以通过SetRate()函数设置声音的语调,通过SetVolume()函数设置声音的音量等等。这些函数就不在这里一一介绍了,留给大家自己去尝试。

现在,使用SAPI,即刻让你的软件能说会道。

除非特别注明,鸡啄米文章均为原创

2016年7月30日

作者:鸡啄米

浏览:

speech开源框架_微软SAPI(The Microsoft Speech API):让你的软件能说会道相关推荐

  1. 好的物联网开源框架_通过开源文化实现更好的物联网

    好的物联网开源框架 开源的影响力远远超出了共享代码的范围,但是有时这方面却未被重视. 例如,我之前曾写过关于与开源相关的开发和协作的特殊方式如何反映出许多DevOps最佳实践的信息,从透明性到迭代式快 ...

  2. 开源框架_跨平台开源框架对比介绍

    知识库  夕阳下你的背影 轻轻嗅探你诱人的气息 幻想远方的你就在身边 这的空气也已不再污浊 若隐若现 知识库主要记录生活,工作不断归纳总结的经验,能时刻指导我不断清空自我,处于空杯状态去面对未来和过去 ...

  3. wpf 开源框架_.NET Core跨平台基础框架:10 篇热文汇总

    (给DotNet加星标,提升.Net技能) 本文精选了DotNet 2019年12月份的10篇热门文章.其中有技术分享.技术资源. 注:以下文章,点击标题即可阅读 <C#异步编程 > Ta ...

  4. netcore开源框架_.NET Core开发精选文章目录,持续更新,欢迎投稿!

    收集的一些.NET Core开发的文章,持续更新,欢迎投稿! 0.文章目录 布莱恩特:@.NET程序员,请了解这8种.NET 内存泄露方式! 布莱恩特:ASP.NET Core 性能优化22条最佳实践 ...

  5. 软件著作权 开源框架_开源软件分享-基于.net core 3.1的快速开发框架

    曾几何时.NET们很羡慕JAVA的生态,java开源生态里面你用得着的几乎都有开源的实现.比如大数据.微服务.以及各种各样的快速开发框架,特别是spring boot出来以后,简化了SSM那套繁琐的配 ...

  6. 收集bug开源框架_划重点 | 小程序框架全面测评

    文章来源 | 凹凸实验室 最近前端届多端框架频出,相信很多有代码多端运行需求的开发者都会产生一些疑惑:这些框架都有什么优缺点?到底应该用哪个? 作为 Taro 开发团队一员,笔者想在本文尽量站在一个客 ...

  7. net core mysql开源框架_.NetCore开源集成框架

    (感兴趣的Fork给个小星星吧~) AspNetCoreScaffolding 本框架在.netCore和.netStandard的基础上,集成了多种中间件 .NetCore集成框架,即开即用 如果对 ...

  8. java工作流开源框架_【程序源代码】Springboot开源工作流开发框架

    正文 | 内容 01 - [介绍] platform-plus是一个轻量级的,前后端分离的Java快速开发平台,基于Springboot2.X.Beetl.Mybatis-Plus.Shiro.Red ...

  9. asp easp 开源框架_国内ASP开源建站系统一览

    开源建站程序让编程高手和只懂打字上网的人都可以快速建立一个功能强大.界面漂亮的网站.不管你是想建一个博客.论坛.CMS.电子商务网站,或是Wiki.相册管理.RSS聚合和类Digg网站.你都可以通过这 ...

最新文章

  1. songCMS 3.15 cookie SQLINJ
  2. bgp选路原则【第二部】
  3. James Fee’s 5 Predictions Geo for 2010 and 5 Things That Won’t Happen
  4. cocos2dx 3.2之Lua打飞机项目
  5. qt android 应用程序图标大小,vs+qt 设置应用程序图标
  6. Google 纪念万维网 30 年:没有 HTTP 协议就没有互联网
  7. oracle暂停索引,Oracle索引被抑制情况
  8. 一、基础篇--1.3进程和线程-CountDownLatch、CyclicBarrier 和 Semaphore
  9. .NET Framework 中的并行编程
  10. 北京市行政边界划分矢量图
  11. krc转换lrc java_win7将酷狗音乐krc歌词转换成lrc歌词文件的方法
  12. st7789屏幕使用方法
  13. idea git 各种颜色代表的含义
  14. 漫步者lollipods如何调节音量_Edifer 漫步者 Lolli pods 评测及对一些问题的实际体验...
  15. IDEA(Java Web 开发) 实时代码模板合集
  16. iQOONeo6SE和红米k40区别 哪个好 iQOONeo6SE和红米k40哪个值得买 两者配置对比
  17. Excel如何批量将中文名字翻译为英文
  18. 计算机网络—网络安全
  19. 华为设备配置策略路由命令
  20. 南加大计算机游戏专业,南加州大学游戏设计项目有哪些课程?

热门文章

  1. js中substr与substring的差别
  2. pwnable.tw startorw
  3. spring 配置异步要点
  4. XPATH获取USER列用户ID的小方法
  5. 最简单的Asp.Net 2.0 TreeView的Checkbox级联操作
  6. MFC创建MDI程序一个Doc对应多个View
  7. Netty工作笔记0073---Neety的出站和入站机制
  8. STM32工作笔记0070---图片显示实验
  9. 大数据之_SCALA工作笔记001---Centos7.3安装scala
  10. Web前端工作笔记004---js--webSocket简单介绍和使用方法