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

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

 

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

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

  微軟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)幫助文檔。

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

圖1 語言屬性對話框

 

2.ISpVoice接口的成員函數

  文本朗讀的功能主要是通過使用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     }
複製代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章