与上一篇相比,这篇是用的C#.net开发,讲述的更加清晰
1. TTS概述 随着语音技术的发展,微软也推出了相应的语音开发工具,即Microsoft Speech SDK,这个SDK中包含了语音应用设计接口(SAPI)、微软的连续语音识别引擎(MCSR)以及微软的语音合成(TTS)引擎等等。它其中的TTS(text-to-speech)引擎可以用于实现语音合成,我们通过TTS引擎可以分析文本内容并且将其朗读出。实现TTS技术的方法有很多种,现在主要采用三种:连词技术、语音合成技术、子字连接技术。目前的5.1版本的SDK一共可以支持3种语言的识别 (英语,汉语和日语)以及2种语言的合成(英语和汉语)。其中还包括对于低层控制和高度适应性的直接语音管理、训练向导、事件、语法编译、资源、语音识别(SR)管理以及TTS管理等强大的设计接口。 2. 实现原理 以下是SpeechAPI的总体结构: 从图中我们可以看出语音引擎则通过DDI层(设备驱动接口)和SAPI(SpeechAPI)进行交互,应用程序通过API层和SAPI通信。通过使用这些API,用户可以快速开发在语音识别或语音合成方面应用程序。 应用程序使用ISpVoice接口来控制TTS,通过调用其中的Speak方法可以朗读出文本内容,通过调用SetVoice / GetVoice方法(在.NET中已经转变成Voice属性)来获取或设置朗读的语音,而通过调用GetVolume / SetVolume、GetRate / SetRate等方法(在.NET中已经转变成Volume和Rate属性)来获取或设置朗读的音量和语速。 功能强大之处在于TTS能识别XML标记,通过给文本加上XML标记,我们让TTS朗读出更加符合语言阅读习惯的句子。例如: l <volume level=” l <rate absspeed=” l <pitch absmiddle=” l <emph></emph> 在他们之间的句子被视为强调; l <spell></spell> 可以将单词逐个字母的拼写出来; l <silence msec=” l <context id=”date_mdy”> l <voice required="Language=409"></voice> 用于设置朗读所用的语言,其中409表示使用英语,804表示使用汉语,而411表示日语。 3. 软件的开发 3.1. 开发环境的搭建 由于Microsoft Speech SDK是以COM组件的形式提供给我们的,因此在使用.NET开发时必须引入Interop.SpeechLib.dll文件,如图: 在引入DLL文件后,我们就可以通过添加“using SpeechLib;”引入命名空间,或直接使用SpeechLib前缀来使用SpeechLib空间下的所有类。 3.2. 二次封装TTS类 我们将使用Singleton设计模式来对TTS进行封装,首先声明一个SpVoice接口,并用SpVoiceClass 对象来实例化,这个接口是实现文本朗读的核心。接着提供用于朗读文本的方法,例如: /// <summary> /// 读出Xml文件内容 /// </summary> /// <param name="xml">Xml文件内容</param> public void SpeakXml(string xml) { voice.Speak(xml, SpeechVoiceSpeakFlags.SVSFIsXML | SpeechVoiceSpeakFlags.SVSFlagsAsync); } 并且使用Pause()、Resume()、Stop()等方法来控制朗读暂停、继续和停止。至于保存音频文件,我们可以使用以下方法,将音频输出流指向一个文件流,来完成保存工作。 /// <summary> /// 保存音频到文件 /// </summary> /// <param name="xml">要读的Xml格式的内容</param> /// <param name="fileName">要保存的文件名</param> public void Save(string xml, string fileName) { SpFileStream stream = new SpFileStream(); stream.Open(fileName, SpeechStreamFileMode.SSFMCreateForWrite, false); voice.AudioOutputStream = stream; voice.Speak(xml, SpeechVoiceSpeakFlags.SVSFlagsAsync | SpeechVoiceSpeakFlags.SVSFIsXML); voice.WaitUntilDone(Timeout.Infinite); stream.Close(); } 3.3. 实现中英文的混合朗读 如果我们直接调用SpVoice接口中Speak方法来朗读文本,那么在朗读过程中,要么使用英文朗读引擎,要么使用中文朗读引擎,这样就只能朗读纯英文文本或纯中文文本。要怎样才能朗读混合的文本呢?第一种方法,我们可以在朗读过程中,根据文本的内容来切换朗读所用的引擎,即调用SetChinaVoice()和SetEnglishVoice()方法。第二种方法,我们在朗读文本之前,先分析文本,将属于英文的句子加上英文语音XML标记,即<voice required=”Language= 在这里我选择第二种方法,在类中增加静态方法:AddXmlLangTag,返回添加过标记得文本内容。 /// <summary> /// 设置中文语音 /// </summary> public void SetChinaVoice() { voice.Voice = voice.GetVoices(string.Empty, string.Empty).Item(0); } /// <summary> /// 设置英文语音 /// </summary> public void SetEnglishVoice() { voice.Voice = voice.GetVoices(string.Empty, string.Empty).Item(1); } 3.4. 界面的实现 在打开文件时,可以选择打开文本文件(*.Txt)和XML文件(*.Xml),如果打开的是XML文件,将不对内容作任何修改,并且也不允许调节音量、语速、语调,因为这些都应该在XML文件中写好;如果打开的是文本文件,则在朗读前,会调用AddXmlLangTag方法给文本加上语言标记,调用AddXmlPitchTag方法给文本加上语调标记,同时也允许调节音量、语速、语调。 4. 总结 通过为普通文本内容设置语音XML标记,并调用SpVoice接口的Speak方法,可以实现中英文文本的混合朗读。如果要使朗读的效果更佳,就必须手工为每一个句子设置相应的XML标记,这样可使朗读更接近人性化。 【参考文献】 1.Microsoft Speech SDK 帮助 (sapi.chm) 2.http://www.codeproject.com/vb/net/TTSinVBpackage.asp 3.http://www.c-sharpcorner.com/SpeechNet.asp 4.http://www.supinfo-projects.com/cn/2006/xing_jin_inter_2006/ 5.http://www.microsoft.com/china/community/program/originalarticles/TechDoc/Cnspeech.mspx 6.http://www.microsoft.com/speech/default.mspx 【源码】 Talker.cs
VoiceForm.cs
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.IO;
- using System.Windows.Forms;
- namespace VoiceTalker
- {
- public partial class VoiceForm : Form
- {
- private bool isXml = false;
- private Talker talker = Talker.Instance();
- public VoiceForm()
- {
- InitializeComponent();
- }
- private void openButton_Click(object sender, EventArgs e)
- {
- DialogResult dr = openFileDialog.ShowDialog();
- if (dr == DialogResult.OK)
- {
- FileInfo fi = new FileInfo(openFileDialog.FileName);
- //判断是否为Xml格式的文件
- if (fi.Extension.ToLower() == ".xml")
- {
- controlBox.Enabled = false;
- isXml = true;
- }
- else
- {
- controlBox.Enabled = true;
- }
- fileNameText.Text = fi.FullName;
- contentText.Text = "";
- //读取文件内容
- StreamReader sr = new StreamReader(openFileDialog.OpenFile(), Encoding.Default);
- contentText.Text = sr.ReadToEnd();
- }
- }
- private void speakButton_Click(object sender, EventArgs e)
- {
- try
- {
- if (isXml)
- {
- talker.SpeakXml(contentText.Text);
- }
- else
- {
- talker.Volume = volumeBar.Value;
- talker.Rate = rateBar.Value;
- String readText = Talker.AddXmlLangTag(contentText.Text);
- readText = Talker.AddXmlPitchTag(readText, pitchBar.Value);
- talker.SpeakXml(readText);
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- private void StopButton_Click(object sender, EventArgs e)
- {
- try
- {
- talker.Stop();
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- private void pauseButton_Click(object sender, EventArgs e)
- {
- try
- {
- if (pauseButton.Text == "暂停")
- {
- talker.Pause();
- pauseButton.Text = "继续";
- }
- else
- {
- talker.Resume();
- pauseButton.Text = "暂停";
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- private void saveButton_Click(object sender, EventArgs e)
- {
- try
- {
- DialogResult dr = saveFileDialog.ShowDialog();
- if (dr == DialogResult.OK)
- {
- string fileName = saveFileDialog.FileName;
- string content = contentText.Text;
- if (!isXml)
- {
- talker.Volume = volumeBar.Value;
- talker.Rate = rateBar.Value;
- content = Talker.AddXmlLangTag(content);
- content = Talker.AddXmlPitchTag(content, pitchBar.Value);
- }
- talker.Save(content, fileName);
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- private void volumeBar_Scroll(object sender, EventArgs e)
- {
- try
- {
- talker.Volume = volumeBar.Value;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- private void rateBar_Scroll(object sender, EventArgs e)
- {
- try
- {
- talker.Rate = rateBar.Value;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
- private void aboutButton_Click(object sender, EventArgs e)
- {
- new AboutForm().ShowDialog();
- }
- private void exitButton_Click(object sender, EventArgs e)
- {
- Application.Exit();
- }
- }
- }
出处:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1529844