【VC++技術雜談004】使用微軟TTS語音引擎實現文本朗讀

  本文主要介紹如何使用微軟TTS語音引擎實現文本朗讀,以及生成wav格式的聲音文件。編程

 

1.語音引擎及語音庫的安裝api

  TTS(Text-To-Speech)是指文本語音的簡稱,即經過TTS引擎把文本轉化爲語音輸出。ide

  微軟TTS語音引擎提供了Windows Speech SDK開發包供編程者使用。Windows Speech SDK包含語音合成SS引擎和語音識別SR引擎兩種,語音合成引擎用於將文字轉換成語音輸出,語音識別引擎用於識別語音命令。函數

  Windows Speech SDK能夠在微軟的官網上免費下載,下載地址爲:http://www.microsoft.com/download/en/details.aspx?id=10121工具

  在該下載界面中,選擇下載SpeechSDK51.exe、SpeechSDK51LangPach.exe和sapi.chm 便可。其中,SpeechSDK51.exe是簡體中文語音引擎,SpeechSDK51LangPach.exe是中文男生語音庫,sapi.chm是SAPI(The Microsoft Speech API)幫助文檔。spa

  下載完成後,先安裝語音引擎SpeechSDK51.exe,再安裝中文語音庫SpeechSDK51LangPach.exe。安裝完成後,能夠依次點擊【開始】/【控制面板】/【語言】打開圖1所示的語言屬性對話框。在該對話框的「文字-語音轉換」標籤頁下的「語音選擇」中可以看到當前系統安裝的所有可用的語音庫。指針

圖1 語言屬性對話框code

 

2.ISpVoice接口的成員函數orm

  文本朗讀的功能主要是經過使用ISpVoice接口的成員函數來實現的。該接口的經常使用成員函數有以下一些:對象

(1)HRESULT Speak(LPCWSTR *pwcs, DWORD dwFlags, ULONG *pulStreamNumber);  //朗讀文本

(2)HRESULT Pause ( void);                                   //暫停朗讀

(3)HRESULT Resume ( void);                                //恢復朗讀 

(4)HRESULT SetRate( long RateAdjust);                 //設置朗讀速度(取值範圍:-10到10)

(5)HRESULT GetRate(long *pRateAdjust);              //獲取朗讀速度

(6)HRESULT SetVoice(ISpObjectToken   *pToken);      //設置使用的語音庫

(7)HRESULT GetVoice(ISpObjectToken** ppToken);    //獲取語音庫

(8)HRESULT SetVolume(USHORT usVolume);          //設置音量(取值範圍:0到100)

(9)HRESULT GetVolume(USHORT *pusVolume);      //獲取音量

(10)HRESULT SetOutput(IUnknown *pUnkOutput,BOOL fAllowFormatChanges);     //設置輸出

(11)HRESULT SpeakStream(IStream *pStream, DWORD dwFlags, ULONG *pulStreamNumber);   //朗讀wav數據流

 

3.編程實例

  瞭解了以上一些ISpVoice接口的成員函數以後,咱們就能夠開始編寫程序來實現文本朗讀,以及生成wav格式聲音文件的功能了。

3.1環境配置

  首先,咱們須要將Windows Speech SDK開發包的頭文件和庫文件所在路徑添加到編譯器中,具體方法以下(這裏以VC++6.0爲例):

  依次點擊【工具】/【選項】,打開選項對話框,選擇【目錄】標籤,在【路徑】中加入「C:\Program Files\Microsoft Speech SDK 5.1\Include」和「C:\Program Files\Microsoft Speech SDK 5.1\Lib\i386」。如圖2所示。

圖2 選項對話框

  其次,還須要在工程中包含TTS語音引擎頭文件和庫文件,具體以下:

1 #include <sapi.h>                            //包含TTS語音引擎頭文件和庫文件
2 #include <sphelper.h>
3 #pragma comment(lib, "sapi.lib")

3.2枚舉語音庫

  枚舉語音庫須要使用到SpEnumTokens()函數,該函數原型以下:

1 inline HRESULT SpEnumTokens(
2    const WCHAR            *pszCategoryId,
3    const WCHAR            *pszReqAttribs,
4    const WCHAR            *pszOptAttribs,
5    IEnumSpObjectTokens   **ppEnum
6 );

  其中,參數ppEnum是IEnumSpObjectTokens類型的指針,用於存儲枚舉獲得的全部語音TokenIEnumSpObjectTokens的成員函數GetCount()用於獲得語音Token的總個數,而成員函數Item()則用於獲得具體的某一個語音Token

  以下的代碼示例如何枚舉獲得的全部語音Token,並將獲得的語音庫的名字添加到下拉組合框控件中,具體實現以下:

 1 /*
 2  * 函數功能 : 初始化語言包選擇組合框控件
 3  * 備    注 : 
 4  * 做    者 : 博客園 依舊淡然
 5  */
 6 void CTTSDemoDlg::InitVoicePackageSelComboxCtrl()
 7 {
 8     //初始化COM組件
 9     if(FAILED(::CoInitialize(NULL)))
10     {
11         MessageBox("初始化COM組件失敗!", "提示", MB_OK|MB_ICONWARNING);
12         return;
13     }
14 
15     //枚舉全部語音Token
16     if(SUCCEEDED(SpEnumTokens(SPCAT_VOICES, NULL, NULL, &m_pIEnumSpObjectTokens)))
17     {
18         //獲得全部語音Token的個數
19         ULONG ulTokensNumber = 0;
20         m_pIEnumSpObjectTokens->GetCount(&ulTokensNumber);
21         
22         //檢測該機器是否安裝有語音包
23         if(ulTokensNumber == 0)
24         {
25             MessageBox("該機器沒有安裝語音包!", "提示", MB_OK|MB_ICONWARNING);
26             return;    
27         }
28         
29         //將語音包的名字加入組合框控件
30         CString strVoicePackageName = _T("");
31         CString strTokenPrefixText = _T("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices\\Tokens\\");
32         for(ULONG i=0; i<ulTokensNumber; i++)
33         {
34             m_pIEnumSpObjectTokens->Item(i, &m_pISpObjectToken);
35             WCHAR* pChar;
36             m_pISpObjectToken->GetId(&pChar);
37             strVoicePackageName = pChar;
38             strVoicePackageName.Delete(0, strTokenPrefixText.GetLength());
39             m_ComboxVoiceSel.InsertString(i, strVoicePackageName);
40         }
41 
42         //設置默認的語音包選擇
43         m_ComboxVoiceSel.SetCurSel(0);
44     }
45 }

  經過以上的代碼能夠看到,首先,咱們經過調用CoInitialize()函數完成了對COM組件的初始化。而後,咱們調用SpEnumTokens()函數獲得了m_pIEnumSpObjectTokens對象,該對象存儲了枚舉獲得的全部語音Token。緊接着,咱們調用GetCount()函數獲得個數,並調用Item()函數獲得具體的每個語音Token對象m_pISpObjectToken。最後,咱們經過調用m_pISpObjectToken對象的GetId()函數便能獲得具體的某一個Token對象的ID,其形式爲「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\XXXXX」,去掉其前綴便能獲得具體的語音庫的名字了。

  該實例運行效果如圖3所示,點擊「語音包選擇」組合框下拉箭頭,可以看到與圖1中列出的語音包是一致的。

圖3 TTS示例運行效果

3.3文本朗讀

  點擊圖3所示界面中的「開始朗讀」按鈕,可以根據當前所選擇的語音包以及設定的語速和音量,對朗讀內容編輯框中的內容進行朗讀。其具體實現方法以下:

 1 /*
 2  * 函數功能 : 點擊"開始朗讀"按鈕時,該函數被調用
 3  * 備    注 : 
 4  * 做    者 : 博客園 依舊淡然
 5  */
 6 void CTTSDemoDlg::OnButtonStartRead() 
 7 {
 8     UpdateData(true);
 9 
10     //獲取ISpVoice接口
11     if(FAILED(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void**)&m_pISpVoice)))
12     {
13         MessageBox("獲取ISpVoice接口失敗!", "提示", MB_OK|MB_ICONWARNING);
14         return;
15     }
16 
17     //設置語言
18     m_pIEnumSpObjectTokens->Item(m_ComboxVoiceSel.GetCurSel(), &m_pISpObjectToken);
19     m_pISpVoice->SetVoice(m_pISpObjectToken);
20 
21     //設置播放速度
22     m_pISpVoice->SetRate(m_SliderVoiceSpeed.GetPos() - 10);
23 
24     //設置音量大小
25     m_pISpVoice->SetVolume(100 - m_SliderVoiceSize.GetPos());
26 
27     //檢測朗讀內容是否爲空
28     if(m_EditContent.IsEmpty())
29     {
30         MessageBox("朗讀內容不能爲空!", "提示", MB_OK|MB_ICONWARNING);
31         return;
32     }
33     
34     //開始進行朗讀
35     m_pISpVoice->Speak(m_EditContent.AllocSysString(), SPF_ASYNC, NULL);
36 }

  在以上代碼中能夠看到,使用了ISpVoice接口函數來完成語音庫的選擇、語速和音量大小的設定,以及經過調用Speak()函數進行文本朗讀。

3.4生成WAV格式的聲音文件

  要將文本朗讀的聲音保存爲WAV格式的聲音文件,主要是經過調用ISpVoice接口函數GetOutputStream()和SetOutput()來實現的。

如下的代碼段給出了實現該功能的示例:

 1     //生成WAV文件
 2     CComPtr<ISpStream> cpISpStream;
 3     CComPtr<ISpStreamFormat> cpISpStreamFormat;
 4     CSpStreamFormat spStreamFormat;
 5     m_pISpVoice->GetOutputStream(&cpISpStreamFormat);
 6     spStreamFormat.AssignFormat(cpISpStreamFormat);
 7     HRESULT hResult = SPBindToFile("C:\\Documents and Settings\\Administrator\\桌面\\TEST\\test.wav", 
 8         SPFM_CREATE_ALWAYS, 
 9         &cpISpStream, 
10         &spStreamFormat.FormatId(), 
11         spStreamFormat.WaveFormatExPtr());
12     if(SUCCEEDED(hResult))
13     {
14         m_pISpVoice->SetOutput(cpISpStream, TRUE);
15         m_pISpVoice->Speak(m_EditContent.AllocSysString(), SPF_DEFAULT, NULL);
16         MessageBox("生成WAV文件成功!", "提示", MB_OK);
17     }
18     else
19     {
20         MessageBox("生成WAV文件失敗!", "提示", MB_OK|MB_ICONWARNING);
21     }
相關文章
相關標籤/搜索