與上一篇相比,這篇是用的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