WINDOWS語音編程初步–(轉自iwaswzq)

來源:互聯網
上載者:User

轉自:iwaswzq

Windows 語音編程初步

一、SAPI簡介

軟體中的語音技術包括兩方面的內容,一個是語音辨識(speech recognition) 和語音合成(speech synthesis)。這兩個技術都需要語音引擎的支援。微軟推出的應用編程介面API,雖然現在不是業界標準,但是應用比較廣泛。

SAPI全稱 The Microsoft Speech API.相關的SR和SS引擎位於Speech SDK開發包中。這個語音引擎支援多種語言的識別和朗讀,包括英文、中文、日文等。

SAPI包括以下組件對象(介面):

(1)Voice Commands API。對應用程式進行控制,一般用於語音辨識系統中。識別某個命令後,會調用相關介面是應用程式完成對應的功能。如果程式想實現語音控制,必須使用此組對象。
(2)Voice Dictation API。聽寫輸入,即語音辨識介面。
(3)Voice Text API。完成從文字到語音的轉換,即語音合成。
(4)Voice Telephone API。語音辨識和語音合成綜合運用到電話系統之上,利用此介面可以建立一個自動答錄服務系統,甚至可以通過電話控制電腦。
(5)Audio Objects API。封裝了電腦發音系統。

SAPI是架構在COM基礎上的,微軟還提供了ActiveX控制項,所以不僅可用於一般的windows程式,還可以用於網頁、VBA甚至EXCEL的圖表中。如果對COM感到陌生,還可以使用微軟的C++ WRAPPERS,它用C++類封裝了語音SDK COM對象。

二、安裝SAPI SDK。

首先從這個網站下載開發包:http://www.microsoft.com/speech/download/sdk51

Microsoft Speech SDK 5.1添加了Automation支援。所以可以在VB,ECMAScript等支援Automation的語言中使用。

版本說明:
Version: 5.1
發布日期: 8/8/2001
語音: English
下載尺寸: 2.0 MB - 288.8 MB

這個SDK開發包還包括了可以隨便發布的英文和中文的語音合成引擎(TTS),和英文、中文、日文的語音辨識引擎(SR)。

系統要求98以上版本。編譯開發包中的例子程式需要vc6以上環境。

******下載說明******:
(1)如果要下載例子程式,說明文檔,SAPI以及用於開發的美國英語語音引擎,需要下載SpeechSDK51.exe,大約68M。
(2)如果想要使用簡體中文和日文的語音引擎,需要下載SpeechSDK51LangPack.exe。大約82M。
(3)如果想要和自己的軟體一起發布語音引擎,需要下載SpeechSDK51MSM.exe,大約132M。
     (在這個地址,我未能成功下載)。
(4)如果要擷取XP下的 Mike 和 Mary 語音,下載Sp5TTIntXP.exe。大約3.5M。
(5)如果要擷取開發包的文檔說明,請下載sapi.chm。大約2.3M。這個在sdk51裡面已經包含。

下載完畢後,首先安裝SpeechSDK51.exe,然後安裝中文語言補丁包SpeechSDK51LangPack,然後展開
msttss22l,自動將所需dll安裝到系統目錄。

三、配置vc環境

在vc6.0的環境下編譯語音工程,首先要配置編譯環境。假設sdk安裝在d:\Microsoft Speech SDK 5.1\路徑下,開啟工程設定對話方塊,在c/c++欄中選擇Preprocessor分類,然後在"附加元件封裝含路徑"中輸入
d:\Microsoft Speech SDK 5.1\include
告訴vc編譯器所需的SAPI標頭檔的位置。
然後切換到LINK欄,在Input分類下的附加庫路徑中輸入:
d:\Microsoft Speech SDK 5.1\lib\i386
使vc在連結的時候能夠找到sapi.lib。

四、語音合成的應用。即使用SAPI實現TTS(Text to Speech)。

1、首先要初始化語音介面,一般有兩種方式:
   ISpVoice* pVoice;
   ::CoInitialize(NULL);
   HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice,
               (void **)&pVoice);
   然後就可以使用這個指標調用SAPI函數了,例如
   pVoice->SetVolume(50);//設定音量
   pVoice->Speak(str.AllocSysString(),SPF_ASYNC,NULL);

   另外也可以使用如下方式:
    CComPtr<ISpVoice>   m_cpVoice;
    HRESULT  hr = m_cpVoice.CoCreateInstance( CLSID_SpVoice );
   在下面的例子中都用這個m_cpVoice變數。

   CLSID_SpVoice的定義位於SPAI.H中。

2、擷取/設定輸出頻率。

   SAPI朗讀文字的時候,可以採用多種頻率方式輸出聲音,比如:
   8kHz 8Bit Mono、8kHz 8Bit Stereo、44kHz 16Bit Mono、44kHz 16Bit Stereo等。在音調上有所差別。具體可以參考sapi.h。

   可以使用如下代碼擷取當前的配置:
   CComPtr<ISpStreamFormat> cpStream;
   HRESULT hrOutputStream = m_cpVoice->GetOutputStream(&cpStream);
   if (hrOutputStream == S_OK)
   {
       CSpStreamFormat Fmt;
       hr = Fmt.AssignFormat(cpStream);
       if (SUCCEEDED(hr))
       {
           SPSTREAMFORMAT eFmt = Fmt.ComputeFormatEnum();
       }
   }
    SPSTREAMFORMAT 是一個ENUM類型,定義位於SPAI.H中。每一個值對應了不同的頻率設定。例如 SPSF_8kHz8BitStereo  = 5

    通過如下代碼設定當前朗讀頻率:
    CComPtr<ISpAudio>   m_cpOutAudio; //聲音輸出介面
    SpCreateDefaultObjectFromCategoryId( SPCAT_AUDIOOUT, &m_cpOutAudio ); //建立介面

    SPSTREAMFORMAT eFmt = 21; //SPSF_22kHz 8Bit Stereo

    CSpStreamFormat Fmt;
    Fmt.AssignFormat(eFmt);
    if ( m_cpOutAudio )
    {
 hr = m_cpOutAudio->SetFormat( Fmt.FormatId(), Fmt.WaveFormatExPtr() );
    }
    else  hr = E_FAIL;

    if( SUCCEEDED( hr ) )
   {
       m_cpVoice->SetOutput( m_cpOutAudio, FALSE );
   }

3、擷取/設定播放所用語音。

   引擎中所用的語音資料檔案一般儲存在SpeechEngines下的spd或者vce檔案中。安裝sdk後,在註冊表中儲存了可用的語音,比如英文的男/女,簡體中文的男音等。位置是:
   HKEY_LOCAL_MACHINE\Software\Microsoft\Speech\Voices\Tokens
如果安裝在中文作業系統下,則預設所用的朗讀語音是簡體中文。SAPI的缺點是不能支援中英文混讀,在朗讀中文的時候,遇到英文,只能逐個字母讀出。所以需要程式自己進行語音切換。

(1) 可以採用如下的函數把當前SDK支援的語音填充在一個組合框中:
    // SAPI5 helper function in sphelper.h
    HWND hWndCombo = GetDlgItem( hWnd, IDC_COMBO_VOICES ); //組合框控制代碼
    HRESULT hr = SpInitTokenComboBox( hWndCombo , SPCAT_VOICES );
    這個函數是通過IEnumSpObjectTokens介面枚舉當前可用的語音介面,把介面的解說文字添加到組合框中,並且把介面的指標作為LPARAM
    儲存在組合框中。
    一定要記住最後程式退出的時候,釋放組合框中儲存的介面:
    SpDestroyTokenComboBox( hWndCombo );
    這個函數的原理就是逐個取得combo裡面每一項的LPARAM資料,轉換成IUnknown介面指標,然後調用Release函數。
(2) 當組合框選擇變化的時候,可以用下面的函數擷取使用者選擇的語音:
    ISpObjectToken* pToken = SpGetCurSelComboBoxToken( hWndCombo );

(3) 用下面的函數擷取當前正在使用的語音:
    CComPtr<ISpObjectToken> pOldToken;
    HRESULT hr = m_cpVoice->GetVoice( &pOldToken );
(4) 當使用者選擇的語音和當前正在使用的不一致的時候,用下面的函數修改:
    if (pOldToken != pToken)
    {       
         // 首先結束當前的朗讀,這個不是必須的。
         HRESULT hr = m_cpVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0);
         if (SUCCEEDED (hr) )
        {
            hr = m_cpVoice->SetVoice( pToken );
         }
    }
(5) 也可以直接使用函數SpGetTokenFromId擷取指定voice的Token指標,例如:
      WCHAR pszTokenId[] = L"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Speech\\Voices\\Tokens\\MSSimplifiedChineseVoice";
    SpGetTokenFromId(pszTokenID , &pChineseToken);

4、開始/暫停/恢複/結束當前的朗讀
  
   要朗讀的文字必須位於寬字元串中,假設位於szWTextString中,則:
   開始朗讀的代碼:
   hr = m_cpVoice->Speak( szWTextString, SPF_ASYNC | SPF_IS_NOT_XML, 0 );
   如果要解讀一個XML文本,用:
   hr = m_cpVoice->Speak( szWTextString, SPF_ASYNC | SPF_IS_XML, 0 );

   暫停代碼:   m_cpVoice->Pause();
   恢複的代碼:   m_cpVoice->Resume();
   結束的代碼:(上面的例子中已經給出了)
   hr = m_cpVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0);

5、跳過部分朗讀的文字

   在朗讀的過程中,可以跳過部分文字繼續後面的朗讀,代碼如下:
   ULONG ulGarbage = 0;
   WCHAR szGarbage[] = L"Sentence";
   hr = m_cpVoice->Skip( szGarbage, SkipNum, &ulGarbage );
   SkipNum是設定要跳過的句子數量,值可以是正/負。
   根據sdk的說明,目前SAPI僅僅支援SENTENCE這個類型。SAPI是通過標點符號來區分句子的。

6、播放WAV檔案。SAPI可以播放WAV檔案,這是通過ISpStream介面實現的:

   CComPtr<ISpStream>       cpWavStream;
   WCHAR                    szwWavFileName[NORM_SIZE] = L"";;

   USES_CONVERSION;
   wcscpy( szwWavFileName, T2W( szAFileName ) );//從ANSI將WAV檔案的名字轉換成寬字元串

   //使用sphelper.h 提供的這個函數開啟 wav 檔案,並得到一個 IStream 指標
   hr = SPBindToFile( szwWavFileName, SPFM_OPEN_READONLY, &cpWavStream );
   if( SUCCEEDED( hr ) )
   {
        m_cpVoice->SpeakStream( cpWavStream, SPF_ASYNC, NULL );//播放WAV檔案
   }
7、將朗讀的結果儲存到wav檔案
   TCHAR szFileName[256];//假設這裡面儲存著目標檔案的路徑
   USES_CONVERSION;
   WCHAR m_szWFileName[MAX_FILE_PATH];
   wcscpy( m_szWFileName, T2W(szFileName) );//轉換成寬字元串

   //建立一個輸出資料流,綁定到wav檔案
   CSpStreamFormat OriginalFmt;
   CComPtr<ISpStream>  cpWavStream;
   CComPtr<ISpStreamFormat>    cpOldStream;
   HRESULT hr = m_cpVoice->GetOutputStream( &cpOldStream );
   if (hr == S_OK) hr = OriginalFmt.AssignFormat(cpOldStream);
   else  hr = E_FAIL;
   // 使用sphelper.h中提供的函數建立 wav 檔案
   if (SUCCEEDED(hr))
   {
      hr = SPBindToFile( m_szWFileName, SPFM_CREATE_ALWAYS, &cpWavStream,
                         &OriginalFmt.FormatId(), OriginalFmt.WaveFormatExPtr() );
    }
   if( SUCCEEDED( hr ) )
   {
      //設定聲音的輸出到 wav 檔案,而不是 speakers
      m_cpVoice->SetOutput(cpWavStream, TRUE);
    }
    //開始朗讀
    m_cpVoice->Speak( szWTextString, SPF_ASYNC | SPF_IS_NOT_XML, 0 );

    //等待朗讀結束
    m_cpVoice->WaitUntilDone( INFINITE );
    cpWavStream.Release();

    //把輸出重新置放到原來的流
    m_cpVoice->SetOutput( cpOldStream, FALSE );
  
8、設定朗讀音量和速度
   m_cpVoice->SetVolume((USHORT)hpos); //設定音量,範圍是 0 - 100
   m_cpVoice->SetRate(hpos);  //設定速度,範圍是 -10 - 10

   hpos的值一般位於

9、設定SAPI通知訊息。SAPI在朗讀的過程中,會給指定視窗發送訊息,視窗收到訊息後,可以主動擷取SAPI的事件,
   根據事件的不同,使用者可以得到當前SAPI的一些資訊,比如正在朗讀的單詞的位置,當前的朗讀口型值(用於顯
   示動畫口型,中文語音的情況下並不提供這個事件)等等。

   要擷取SAPI的通知,首先要註冊一個訊息:
   m_cpVoice->SetNotifyWindowMessage( hWnd, WM_TTSAPPCUSTOMEVENT, 0, 0 );
   這個代碼一般是在主視窗初始化的時候調用,hWnd是主視窗(或者接收訊息的視窗)控制代碼。WM_TTSAPPCUSTOMEVENT
   是使用者自訂訊息。

   在視窗響應WM_TTSAPPCUSTOMEVENT訊息的函數中,通過如下代碼擷取sapi的通知事件:

    CSpEvent        event;  // 使用這個類,比用 SPEVENT結構更方便

    while( event.GetFrom(m_cpVoice) == S_OK )
    {
        switch( event.eEventId )
        {
           。。。
        }
    }

   eEventID有很多種,比如SPEI_START_INPUT_STREAM表示開始朗讀,SPEI_END_INPUT_STREAM表示朗讀結束等。
   可以根據需要進行判斷使用。

四、結束語
  
   SAPI的功能很多,比如語音辨識、使用文法分析等,由於條件和精力有限,我未能一一嘗試,感興趣的朋友可以自己安裝一個研究一下。
   另外提供一個簡單例子程式的下載,位置是:
   http://www.cnblogs.com/buffer/admin/ftp://vckbase:vckbase@210.192.111.117/user/iwaswzq/Universe.rar
   再次感謝砸玻璃。

 感謝原作者:iwaswzq

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.