1. 程式人生 > >一個整合微軟語音識別技術與語音朗讀的類,基於Microsoft SpeechAPI5.1的開發

一個整合微軟語音識別技術與語音朗讀的類,基於Microsoft SpeechAPI5.1的開發

               

//////////////////////////////////////////////////////////1,生成動態連線庫時,要#define USE_SPEECH_DLL,//     並且#define LANE_SPEECH_EXPORTS//2,使用動態連線庫時,要#define USE_SPEECH_DLL//3,聲稱和使用靜態連線庫時,什麼都不需要//4,另外主程式中靜態連線庫要呼叫的方式裡要呼叫CoInitialize( NULL )和CoUninitialize(),//     動態連線庫就不用呼叫了。////////////////////////////////////////////////////////#ifndef LANE_SPEECH_H#define LANE_SPEECH_H

#include <windows.h>#define _ATL_APARTMENT_THREADED#include <atlbase.h>extern CComModule _Module; //You may derive a class from CComModule and use it. if you want to override something,but do not change the name of _Module#include <atlcom.h>#include <sphelper.h>  //sapi需要的標頭檔案

//-----生成動態連線庫和靜態庫的處理----------------#ifdef USE_SPEECH_DLL //定義了USE_SPEECH_DLL,就按生成DLL,宣告匯出匯入類

 #ifdef LANE_SPEECH_EXPORTS  #define LANE_SPEECH_DLL __declspec(dllexport) #else  #define LANE_SPEECH_DLL __declspec(dllimport) #endif

 //這個警告我現在還沒鬧清楚是怎麼回事了,估計是DLL和com或atl有關 //暫時只能遮蔽掉它,在靜態庫裡就不會出現這個警告。 #pragma warning( disable : 4251 )

#else    //沒定義USE_SPEECH_DLL,則不宣告匯出或匯入類(LANE_SPEECH_DLL就為空) #define LANE_SPEECH_DLL

#endif //USE_SPEECH_DLL

//***************************常量***********************

/////////公共常量-----------------const DWORD  SP_CHINESE = 0x0000; //簡體中文.const DWORD  SP_ENGLISH = 0x0001; //英語.

/////////CTTS常量-----------------const UINT  WM_SPEAK = WM_USER + 4444; //觸發事件產生的訊息。

/////////SR常量-------------------const UINT  WM_RECOEVENT = WM_USER + 3333; //觸發事件產生的訊息。const DWORD  SR_INPROC = 0x0000; //獨享型別的SR.const DWORD  SR_SHARE  = 0x0001; //共享型別的SR.

//以下常量僅作例子用。#define VID_TopLevelRule 9000  //頂級規則ID#define VID_SubLevelRule1 9001  //子規則ID#define VID_SubLevelRule2 9002  //子規則ID#define VID_SubLevelRule3 9003  //子規則ID

//*************************類宣告************************

class CSR;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////        CTTS////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class LANE_SPEECH_DLL  CTTS{protected: HWND      m_hWnd;    // 關聯的視窗控制代碼。

 CComPtr<ISpVoice>   m_pVoice;   // 聲音物件的指標。 CComPtr<ISpObjectToken>  m_pToken;   // token物件的指標。 CComPtr<ISpAudio>   m_pAudio;   // 音訊物件的指標。(用來儲存原來預設的輸入流) CComPtr<ISpStream>   m_pOutputStream; // 輸出到檔案的流物件。

public://********************************初始化部分********************

 //////////////////////////////////////////////////////////////////// //功能: 儲存與識別引擎關聯的視窗控制代碼。 //引數: hWnd:要關聯的視窗控制代碼。 //返回值: 無。 //////////////////////////////////////////////////////////////////// CTTS ( const HWND  hWnd );

 //////////////////////////////////////////////////////////////////// //功能: 釋放所有的物件。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// ~CTTS ();

 //////////////////////////////////////////////////////////////////// //功能: 建立一個voice物件。設定要是別的語言種類,訊息,通知事件。 //引數: dwLanguage:要朗讀的語言種類,SP_CHINESE為中文, //   SP_ENGLISH為英文。 //返回值: HRESULT型別。 //////////////////////////////////////////////////////////////////// HRESULT Create( const DWORD dwLanguage = SP_CHINESE );

 //////////////////////////////////////////////////////////////////// //功能: 從一個SR引擎建立一個voice物件。設定要是別的語言種類,訊息, //   通知事件。 //引數: pSRContext:SR引擎的指標。dwLanguage:要朗讀的語言種類, //   SP_CHINESE為中文,SP_ENGLISH為英文。 //返回值: HRESULT型別。 //////////////////////////////////////////////////////////////////// HRESULT Create (  const CSR * pSR,      const DWORD dwLanguage = SP_CHINESE );

//********************************設定部分***************************************

 //////////////////////////////////////////////////////////////////// //功能: 設定朗讀聲音的語言種類。 //引數: dwLanguage:語言種類。SP_CHINESE為中文,SP_ENGLISH為英文。 //返回值: HRESULT型別。 //////////////////////////////////////////////////////////////////// HRESULT SetLanguage ( const DWORD dwLanguage );

 //////////////////////////////////////////////////////////////////// //功能: 設定要處理的的事件。 //引數: ullInterest:來自enum SPEVENTENUM,要用SPFEI()轉化為64bit的, //   設定多個事件用運算子" | "。 用SPFEI_ALL_SR_EVENTS表示全部事 //   件都會收到通知。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT SetInterest ( const  ULONGLONG   ullInterest );

 //////////////////////////////////////////////////////////////////// //功能: 設定朗讀聲音的音量。 //引數: usVolume:音量數值應該從0到100 //返回值: 無。 //////////////////////////////////////////////////////////////////// void SetVolume ( USHORT usVolume );

 //////////////////////////////////////////////////////////////////// //功能: 得到朗讀聲音的音量。 //引數: 無。 //返回值: 音量數值,應該從0到100。 //////////////////////////////////////////////////////////////////// USHORT GetVolume ( );

 //////////////////////////////////////////////////////////////////// //功能: 設定朗讀聲音的音速。 //引數: RateAdjust:音速,引數範圍從-10到10。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void SetRate ( LONG  RateAdjust );

 //////////////////////////////////////////////////////////////////// //功能: 得到朗讀聲音的音速。 //引數: 無。 //返回值: 音速,引數範圍從-10到10。 //////////////////////////////////////////////////////////////////// LONG GetRate ( );

 //////////////////////////////////////////////////////////////////// //功能: 設定朗讀的聲音流到.wav檔案,如果不呼叫此函式則預設從音箱輸出。 //引數: pszFileName:.wav檔案的檔名。要用" L"" "轉換。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT SetOutputWithWav ( const WCHAR *pszFileName = L"TtsOut.wav");

 //////////////////////////////////////////////////////////////////// //功能: 設定朗讀的聲音從音箱輸出。 //引數: 無。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT UnSetOutputWithWav ();

//**********************播放語音,文字到語音轉換部分*****************************

 //////////////////////////////////////////////////////////////////// //功能: 停止朗讀。如果朗讀為同步方式,則不能停止。 //引數: pwcs:要朗讀的字串,需用" L"" "轉換,可以是包含xml標記 //   的字串。dwFlags:朗讀方式。SPF_ASYNC為非同步,SVSFDefault為同步, //   SVSFIsXML為朗讀帶xml標記的文字。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT Speak ( const WCHAR *pwcs, const DWORD dwFlags = SPF_ASYNC );

 //////////////////////////////////////////////////////////////////// //功能: 停止朗讀。如果朗讀為同步方式,則不能停止。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void Stop ( );

 //////////////////////////////////////////////////////////////////// //功能: 暫停朗讀。如果朗讀為同步方式,則不能暫停。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void Pause ();

 //////////////////////////////////////////////////////////////////// //功能: 從暫停的地方繼續朗讀。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void Resume ();

//********************************處理事件部分***********************************

public: //////////////////////////////////////////////////////////////////// //功能: 處理髮生的事件。系統自動呼叫,不需要使用者自己處理。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void ProcessTTSEvent ();

 //////////////////////////////////////////////////////////////////// //功能: 為虛擬函式。當輸出流結束時要觸發的動作,需要在派生類過載。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// virtual void OnStreamStart ();

 //////////////////////////////////////////////////////////////////// //功能: 為虛擬函式。當輸出流結束時要觸發的動作,需要在派生類過載。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// virtual void OnStreamEnd ();};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////        CSR////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class LANE_SPEECH_DLL  CSR{

protected: HWND m_hWnd;

public: CComPtr<ISpRecognizer>  m_pSREngine; // 語音識別引擎(recognition)的介面。 CComPtr<ISpRecoContext>  m_pSRContext; // 識別引擎上下文(context)的介面。 CComPtr<ISpRecoGrammar>  m_pSRGrammar; // 識別文法(grammar)的介面。 CComPtr<ISpStream>   m_pInputStream; // 流()的介面。 CComPtr<ISpObjectToken>  m_pToken;  // 語音特徵的(token)介面。 CComPtr<ISpAudio>   m_pAudio;  // 音訊(Audio)的介面。(用來儲存原來預設的輸入流)public: static ULONGLONG   ullGrammerID; // Grammer的識別符號, 64位無符號整型 每建立一個Grammar,加一。

protected://***************************輔助功能部分****************************************

 //////////////////////////////////////////////////////////////////// //GrammarID加一,每個GrammerID必須不同。 //////////////////////////////////////////////////////////////////// static void UpdateGrammerID ( );

public: //////////////////////////////////////////////////////////////////// //功能: 友員。TTS中的從SR引擎中建立voice物件。 //引數: pSRContext:SR上下文物件的指標。 //返回值: HRESULT型別。 //////////////////////////////////////////////////////////////////// friend HRESULT CTTS::Create (  const CSR * pSR,         const DWORD dwLanguage );

//****************************初始化部分*****************************************

 //////////////////////////////////////////////////////////////////// //功能: 儲存與識別引擎關聯的視窗控制代碼,更新GrammarID。 //引數: hWnd:要關聯的視窗控制代碼。 //返回值: 無。 //////////////////////////////////////////////////////////////////// CSR ( HWND hWnd );

 //////////////////////////////////////////////////////////////////// //功能: 釋放所有的物件。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// ~CSR ( );

 //////////////////////////////////////////////////////////////////// //功能: 建立各個介面的物件。設定要是別的語言種類,訊息,通知事件, //   載入文法檔案。 //引數: SRType:識別引擎的型別,SR_INPROC為獨享型別,SR_SHARE共享型別。 //   pwcGramFileName:文法檔案的檔名,要用" L"" "轉換為WCHAR型。 //   dwLanguage:要是別的語言種類,SP_CHINESE為中文,SP_ENGLISH為英文。 //返回值: HRESULT型別。 //////////////////////////////////////////////////////////////////// HRESULT Create (const DWORD   SRType,     const WCHAR   *pwcGramFileName = L"grammar.xml",     const DWORD   dwLanguage = SP_CHINESE );

//**********************************設定部分*************************************

 //////////////////////////////////////////////////////////////////// //功能: 設定要處理的上下文接受的事件。 //引數: ullInterest:來自enum SPEVENTENUM,要用SPFEI()轉化為64bit的, //   設定多個事件用運算子" | "。 用SPFEI_ALL_SR_EVENTS表示全部事 //   件都會收到通知。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT SetInterest ( const  ULONGLONG   ullInterest );

 //////////////////////////////////////////////////////////////////// //功能: 設定某個規則的狀態(啟用或者取消啟用)。 //引數: pszName:規則名,要用" L"" "轉換。bFlag:TRUE表示啟用, //   FALSE表示取消啟用。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT SetRuleState ( const WCHAR   *pszName, const BOOL   bFlag );

 //////////////////////////////////////////////////////////////////// //功能: 設定識別引擎從.wav檔案識別語音,如果不呼叫此函式則預設從麥克 //   風輸入。 //引數: pszFileName:.wav檔案的檔名。要用" L"" "轉換。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT SetInputWithWav ( const WCHAR *pszFileName = L"sr.wav" );

 //////////////////////////////////////////////////////////////////// //功能: 取消從.wav檔案識別。恢復從麥克風識別。 //引數: 無。 //返回值: HRESULT。 //////////////////////////////////////////////////////////////////// HRESULT UnSetInputWithWav ( );

//***********************識別開始,結束,識別結果的處理**************************

 //////////////////////////////////////////////////////////////////// //功能: 識別開始(將所有規則啟用)。 //引數: 無 //返回值: 無。 //////////////////////////////////////////////////////////////////// void StartRecognize ( );

 //////////////////////////////////////////////////////////////////// //功能: 識別結束(將所有規則取消啟用)。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void EndRecognize ( );

public: //////////////////////////////////////////////////////////////////// //功能: 處理髮生的事件。系統自動呼叫,不需要使用者自己處理。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void ProcessRecoEvent ( );

protected: //////////////////////////////////////////////////////////////////// //功能: 識別成功時要呼叫的函式。系統自動呼叫,不需要使用者自己處理。 //引數: pPhrase:ISpPhrase型別。 //返回值: 無。 //////////////////////////////////////////////////////////////////// void OnRecoSuccess ( ISpPhrase *pPhrase );

public: //////////////////////////////////////////////////////////////////// //功能: 識別成功後,根據規則的ID決定動作。系統自動呼叫。虛擬函式, //   需要在派生類過載。規則ID必須以常量形式預先定義。 //引數: ulRuleID:頂級規則的ID。ulVal:子規則的ID。 //返回值: 無。 //////////////////////////////////////////////////////////////////// virtual void ExecuteCommand (   const  ULONG ulRuleID,         const ULONG ulVal );

 //////////////////////////////////////////////////////////////////// //功能: 識別失敗時的動作,系統自動呼叫。虛擬函式,需要在派生類過載。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// virtual void OnRecoFail ();

 //////////////////////////////////////////////////////////////////// //功能: 為虛擬函式。當輸入流開始時要觸發的動作,需要在派生類過載。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// virtual void OnStreamStart ();

 //////////////////////////////////////////////////////////////////// //功能: 為虛擬函式。當輸入流結束時要觸發的動作,需要在派生類過載。 //引數: 無。 //返回值: 無。 //////////////////////////////////////////////////////////////////// virtual void OnStreamEnd ();

};

#endif   //LANE_SPEECH_DLL_H

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////// 檔案:LaneSpeech.cpp// 功能:封裝的speech sdk5.1 的文字語音合成(TTS)和語音識別(SR)功能//   語音識別只支援命令模式,不支援連續模式// 作者:呂寶虹(Lane), msn: [email protected], qq: 3619908// 日期: 2004.10// 版本:1.2// //////////////////////////////////////////////////////////

#include "LaneSpeech.h"

//-----生成動態連線庫和靜態庫的處理----------------#ifdef USE_SPEECH_DLL //定義了USE_SPEECH_DLL,就按生成DLL,宣告匯出匯入類

BOOL APIENTRY DllMain( HANDLE hModule,                        DWORD  ul_reason_for_call,                        LPVOID lpReserved      ){    switch (ul_reason_for_call) {  case DLL_PROCESS_ATTACH:   CoInitialize(NULL);   break;    case DLL_THREAD_ATTACH:   break;    case DLL_THREAD_DETACH:   break;    case DLL_PROCESS_DETACH:   CoUninitialize();   break;    }    return TRUE;}

#endif //USE_SPEECH_DLL

///////////////////////////////////////////////////////////////

 //////////////////////////////////////////////////////////////////// //功能: 彈出一個資訊框。 //引數: lpText:是對話方塊資訊。lpCaption:對話方塊標題。 //返回值: 無。 //////////////////////////////////////////////////////////////////// inline void ShowError ( const LPCTSTR lpText = "ERROR",       const LPCTSTR lpCaption = "ERROR" ) {  ::MessageBox( NULL, lpText, lpCaption, MB_OK | MB_ICONERROR ); }

 //////////////////////////////////////////////////////////////////// //功能: 檢查一個HRESULT型別的值,如果是錯誤的值則,彈出資訊框提示錯誤。 //引數: hr:要檢查的HRESULT的引用。 lpText:是對話方塊資訊。 //   lpCaption:對話方塊標題。 //返回值: 有錯則為FALSE,沒錯則返回TRUE。 //////////////////////////////////////////////////////////////////// inline BOOL CheckHr (  const HRESULT &hr,       const LPCTSTR lpText = "ERROR",       const LPCTSTR   lpCaption = "ERROR" ) {  if ( FAILED( hr ) ) {   ShowError ( lpText, lpCaption );   return FALSE;  }  return TRUE; }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////        CTTS////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////儲存關聯視窗控制代碼。初始化COM。////////////////////////////////////////////////////////////////////CTTS::CTTS ( const HWND hWnd ){ m_hWnd   = hWnd; m_pVoice  = NULL; m_pToken  = NULL; m_pOutputStream = NULL; m_pAudio  = NULL;}

//////////////////////////////////////////////////////////////////////釋放所有物件。////////////////////////////////////////////////////////////////////CTTS::~CTTS (){ if( m_pToken) {  m_pToken.Release();  m_pToken = NULL; } if( m_pAudio ) {  m_pAudio.Release();  m_pAudio = NULL; } if ( m_pOutputStream ) {  m_pOutputStream.Release();  m_pOutputStream = NULL; } if( m_pVoice ) {  m_pVoice.Release();  m_pVoice = NULL; }}

//////////////////////////////////////////////////////////////////////從SR的上下文中得到voice物件。此函式在CSR中被宣告一個友員。////////////////////////////////////////////////////////////////////HRESULT CTTS::Create(  const CSR * pSR,      const DWORD dwLanguage ){ HRESULT hr; hr = pSR->m_pSRContext->GetVoice ( &m_pVoice ); if ( !::CheckHr ( hr, "pSRContext->GetVoice()" ) ) {  return hr; }

 SetLanguage ( dwLanguage );

 hr = SpCreateDefaultObjectFromCategoryId ( SPCAT_AUDIOIN, &m_pAudio );//建立一個預設音訊流 if ( !::CheckHr ( hr, "CreateDefaultObjectFodd()" ) ) {   return hr; }

 //SPEI_START_INPUT_STREAM表示輸出物件開始接受流輸出SPEI_START_INPUT_STREAM //SPEI_END_INPUT_STREAM 表示完成流輸出。 hr = m_pVoice->SetInterest( SPFEI( SPEI_START_INPUT_STREAM ) |        SPFEI( SPEI_END_INPUT_STREAM ),           SPFEI( SPEI_START_INPUT_STREAM ) |           SPFEI( SPEI_END_INPUT_STREAM ) ); if ( !::CheckHr ( hr, "m_pVoice->SetInterest()" ) ) {   return hr; }

 //設定通知訊息 hr = m_pVoice->SetNotifyWindowMessage( m_hWnd, WM_SPEAK, 0, 0 ); if ( !::CheckHr ( hr, "m_pVoice->SetNotifyWindowMessage()" ) ) {   return hr; }

 return hr;}

//////////////////////////////////////////////////////////////////////單獨(相對於從SR的上下文中得到voice物件)建立一個voice物件。//並設定興趣,設定通知事件。////////////////////////////////////////////////////////////////////HRESULT CTTS::Create( const DWORD dwLanguage ){ HRESULT hr; hr = m_pVoice.CoCreateInstance ( CLSID_SpVoice ); if ( !::CheckHr ( hr, "m_pVoice.CoCreateInstance()" ) ) {  return hr; }

 SetLanguage ( dwLanguage );

 hr = SpCreateDefaultObjectFromCategoryId ( SPCAT_AUDIOIN, &m_pAudio );//建立一個預設音訊流 if ( !::CheckHr ( hr, "CreateDefaultObjectFodd()" ) ) {   return hr; }

 //SPEI_START_INPUT_STREAM表示輸出物件開始接受流輸出SPEI_START_INPUT_STREAM //SPEI_END_INPUT_STREAM 表示完成流輸出。 hr = m_pVoice->SetInterest( SPFEI( SPEI_START_INPUT_STREAM ) |        SPFEI( SPEI_END_INPUT_STREAM ),           SPFEI( SPEI_START_INPUT_STREAM ) |           SPFEI( SPEI_END_INPUT_STREAM ) ); if ( !::CheckHr ( hr, "m_pVoice->SetInterest()" ) ) {   return hr; }

 //設定通知訊息 hr = m_pVoice->SetNotifyWindowMessage( m_hWnd, WM_SPEAK, 0, 0 ); if ( !::CheckHr ( hr, "m_pVoice->SetNotifyWindowMessage()" ) ) {   return hr; }

 return hr;}

//////////////////////////////////////////////////////////////////////設定語言,預設的語言為中文。SP_CHINESE為中文,SP_ENGLISH為英文////////////////////////////////////////////////////////////////////HRESULT CTTS::SetLanguage ( const DWORD dwLanguage ){ HRESULT hr; switch ( dwLanguage ) {  case SP_CHINESE:   hr = SpFindBestToken( SPCAT_VOICES, L"language=804",         NULL, &m_pToken );   if ( !::CheckHr ( hr, "SpFindBestToken()錯誤",       "CTTS::SetLanguage" ) ) {     return hr;   }   hr = m_pVoice->SetVoice( m_pToken );   if ( !::CheckHr ( hr, "SpFindBestToken()錯誤",       "CTTS::SetLanguage" ) ) {     return hr;   }   break;

  case SP_ENGLISH:   hr = SpFindBestToken( SPCAT_VOICES, L"language=409",         NULL, &m_pToken );   if ( !::CheckHr ( hr, "SpFindBestToken()錯誤",       "CTTS::SetLanguage" ) ) {     return hr;   }   hr = m_pVoice->SetVoice( m_pToken );   if ( !::CheckHr ( hr, "SpFindBestToken()錯誤",       "CTTS::SetLanguage" ) ) {     return hr;   }   break;  default:   ::ShowError ( "設定中文請用SP_CHINESE,設定英文請用SP_ENGLISH",      "CTTS::SetLanguage()引數錯誤" ); }

 return hr;}

//////////////////////////////////////////////////////////////////////設定要處理的事件。////////////////////////////////////////////////////////////////////HRESULT CTTS::SetInterest ( const  ULONGLONG   ullInterest ){ HRESULT hr; //  設定pvoice感興趣的事件。 hr = m_pVoice->SetInterest( ullInterest, ullInterest ); if ( !::CheckHr ( hr, "m_pVoice->SetInterest()", "CTTS::SetInterest()" ) ) {  return hr; } /*//設定通知訊息 hr = m_pVoice->SetNotifyWindowMessage( hWnd, WM_SPEAK, 0, 0 ); if ( !::CheckHr ( hr, "m_pVoice->SetNotifyWindowMessage()",     "CTTS::SetInterest()" ) ) {  return hr; }*/ return hr;}

//////////////////////////////////////////////////////////////////////設定朗讀音量。音量數值應該從0到100////////////////////////////////////////////////////////////////////void CTTS::SetVolume ( USHORT usVolume ){ if ( (usVolume > 100) || (usVolume<0)  ) {  ::ShowError ( "CTTS::SetVolume音量範圍應該從0到100" );  return; } m_pVoice->SetVolume( usVolume );}

//////////////////////////////////////////////////////////////////////取得音量的值。////////////////////////////////////////////////////////////////////USHORT CTTS::GetVolume ( ){ USHORT usVolume; m_pVoice->GetVolume ( &usVolume ); return usVolume;}

//////////////////////////////////////////////////////////////////////設定語速。引數範圍從-10到10////////////////////////////////////////////////////////////////////void CTTS::SetRate ( LONG  RateAdjust ){ if ( (RateAdjust < -10) || (RateAdjust > 10) ) {  ::ShowError ( "SetRate()設定的數值必須在 -10到10之間" );  return; } m_pVoice->SetRate ( RateAdjust );}

//////////////////////////////////////////////////////////////////////得到當前語速的數值。////////////////////////////////////////////////////////////////////LONG CTTS::GetRate ( ){ LONG RateAdjust; m_pVoice->GetRate( &RateAdjust ); return RateAdjust;}

//////////////////////////////////////////////////////////////////////設定朗讀的聲音流到.wav檔案,如果不呼叫此函式則預設從音箱輸出。//並設定要處理的事件,應該包含對流的開始和結束。在Create()中已經設定好了。////////////////////////////////////////////////////////////////////HRESULT CTTS::SetOutputWithWav ( const WCHAR *pszFileName )         //,LONG Format = PSF_22kHz16BitStereo){ HRESULT hr;

 CSpStreamFormat sOutputFormat;

 CComPtr<ISpStreamFormat> cpOldStream;

 m_pVoice->GetOutputStream( &cpOldStream ); sOutputFormat.AssignFormat( SPSF_22kHz16BitStereo ); //sOutputFormat.AssignFormat(cpOldStream);

 hr = SPBindToFile(  pszFileName,      SPFM_CREATE_ALWAYS,      //SPFM_CREATE,      //SPFM_OPEN_READWRITE,      &m_pOutputStream,      &sOutputFormat.FormatId(),      sOutputFormat.WaveFormatExPtr() ); if ( !::CheckHr ( hr, "SPBindToFile" ) ) {  return hr; }

 hr = m_pVoice->SetOutput ( m_pOutputStream, TRUE ); if ( !::CheckHr ( hr, "m_pVoice->SetOutput()" ) ) {   return hr; } return hr;}

//////////////////////////////////////////////////////////////////////設定朗讀的聲音從音箱輸出。////////////////////////////////////////////////////////////////////HRESULT CTTS::UnSetOutputWithWav (){ HRESULT hr; hr = m_pVoice->SetOutput ( m_pAudio, FALSE ); ::CheckHr ( hr, "UnSetOutputWithWav ()" ); m_pOutputStream->Close (); return hr;}

//////////////////////////////////////////////////////////////////////朗讀。dwFlags為SPF_ASYNC時,指非同步朗讀。SPF_DEFAULT為同步。//SPF_IS_XML指pwcs中包含xml標籤。按xml標籤的設定朗讀。////////////////////////////////////////////////////////////////////HRESULT CTTS::Speak ( const WCHAR *pwcs, const DWORD dwFlags ){ //WCHAR WTX[] = L"<VOICE REQUIRED=''NAME=Microsoft Mary''/>text to wave"; HRESULT hr; hr = m_pVoice->Speak ( pwcs, dwFlags, NULL); ::CheckHr ( hr, "CTTS::Speak" ); return hr;}

//////////////////////////////////////////////////////////////////////停止播放。Speak()為同步朗讀時不能停止。////////////////////////////////////////////////////////////////////void CTTS::Stop ( ){ m_pVoice->Speak ( NULL, SPF_ASYNC, NULL );}

//////////////////////////////////////////////////////////////////////暫停朗讀。////////////////////////////////////////////////////////////////////void CTTS::Pause (){ m_pVoice->Pause ();}

//////////////////////////////////////////////////////////////////////從暫停處繼續朗讀////////////////////////////////////////////////////////////////////void CTTS::Resume (){ m_pVoice->Resume ();}

//////////////////////////////////////////////////////////////////////從事件佇列取得事件並處理。根據相應的事件呼叫相應的函式。////////////////////////////////////////////////////////////////////void CTTS::ProcessTTSEvent (){ CSpEvent event;  // 事件助手類

    // 迴圈處理事件當事件佇列裡有事件的時候。    while ( event.GetFrom(m_pVoice) == S_OK )    {        // 察看識別成功事件和識別失敗事件        switch (event.eEventId)        {            case SPEI_START_INPUT_STREAM:                OnStreamStart ();                break;

   case SPEI_END_INPUT_STREAM:    OnStreamEnd ();    break;

   case SPEI_VOICE_CHANGE:    //OnVoiceChange ();    break;

   case SPEI_TTS_BOOKMARK:    //OnBookMark ();    break;   case SPEI_WORD_BOUNDARY:    //OnWordBoundAry ();    break;        }    }}

//////////////////////////////////////////////////////////////////////流輸出到檔案開始時要觸發的事件。////////////////////////////////////////////////////////////////////void CTTS::OnStreamStart (){ ShowError ("朗讀開始");}

//////////////////////////////////////////////////////////////////////流輸出到檔案結束時要觸發的事件。////////////////////////////////////////////////////////////////////void CTTS::OnStreamEnd (){ ShowError ("朗讀完畢");}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////        CSR////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////儲存視窗控制代碼,初始化介面指標,呼叫UpdateGrammerID()。//如果要建立多個Grammar,Grammar必須不同。/////////////////////////////////////////////////////////CSR::CSR ( HWND hWnd ){ m_hWnd  = hWnd; m_pSREngine = NULL; m_pSRContext = NULL; m_pSRGrammar = NULL; m_pInputStream = NULL; m_pToken = NULL; m_pAudio = NULL;

 UpdateGrammerID ( );}

///////////////////////////////////////////////////////////更新GrammerID:GrammerID+1。為static函式。/////////////////////////////////////////////////////////void CSR::UpdateGrammerID ( ){ ullGrammerID ++;}

///////////////////////////////////////////////////////////建立引擎ISpRecognizer,設定識別語言。//建立引擎上下文ISpRecoContext,設定感興趣的事件及發生事件要通知視窗的訊息。//建立上下文的文法ISpRecoGrammar。從.xml檔案載入文法。/////////////////////////////////////////////////////////HRESULT CSR::Create (  const DWORD   dwSRType,      const WCHAR   *pwcGramFileName,      const DWORD   dwLanguage ){ HRESULT  hr = S_OK;

 //容錯. if ( (dwSRType != SR_INPROC) && (dwSRType != SR_SHARE) ) {  ::ShowError ( "指定要建立的SR型別錯誤,請用SR_INPROC或SR_SHARE呼叫" );  return 0x3333; } if ( (dwLanguage != SP_CHINESE) && (dwLanguage != SP_ENGLISH) ) {  ::ShowError ( "請選擇要建立的SR的語言的種類:SP_CHINESE,SP_ENGLISH" );  return 0x3434; }

 if ( dwSRType == SR_INPROC ) { //建立一個獨享的識別引擎,這裡必須呼叫SetInput()  hr = m_pSREngine.CoCreateInstance ( CLSID_SpInprocRecognizer );  if ( !::CheckHr ( hr, "m_pSREngine.CoCreateInstance()" ) ) {   return hr;  }

  hr = SpCreateDefaultObjectFromCategoryId ( SPCAT_AUDIOIN, &m_pAudio );//建立一個預設音訊流  if ( !::CheckHr ( hr, "CreateDefaultObjectFodd()" ) ) {   return hr;  }

  hr = m_pSREngine->SetInput ( m_pAudio, TRUE );//為識別引擎設定音訊輸入  if ( !::CheckHr ( hr, "m_pSREngine->SetInput()" ) ) {   return hr;  } } else {  hr = m_pSREngine.CoCreateInstance ( CLSID_SpSharedRecognizer );//建立一個共享的SR引擎。  if ( !::CheckHr ( hr, "m_pSREngine.CoCreateInstance()" ) ) {   return hr;  } }

 //設定識別的語言。 if ( dwLanguage == SP_CHINESE ) {  hr = SpFindBestToken ( SPCAT_RECOGNIZERS, L"language=804",    NULL, &m_pToken ); } else {  hr = SpFindBestToken ( SPCAT_RECOGNIZERS, L"language=409",    NULL, &m_pToken ); } if ( !::CheckHr ( hr, "SpFindBestToken()" ) ) {   return hr; } hr = m_pSREngine->SetRecognizer ( m_pToken ); if ( !::CheckHr ( hr, "m_pSREngine->SetRecognizerI()" ) ) {   return hr; }

 //為引擎建立一個上下文介面 hr = m_pSREngine->CreateRecoContext ( &m_pSRContext ); if ( !::CheckHr ( hr, "m_pSREngine->CreateRecoContext()" ) ) {   return hr; }

 //設定通知視窗的訊息 hr = m_pSRContext->SetNotifyWindowMessage ( m_hWnd, WM_RECOEVENT, 0, 0 ); if ( !::CheckHr ( hr, "m_pSRContext->SetNotifyWindowMessage()" ) ) {   return hr; }

 //設定興趣。 //hr = m_pSRContext->SetInterest ( SPFEI_ALL_SR_EVENTS, SPFEI_ALL_SR_EVENTS ); hr = m_pSRContext->SetInterest ( SPFEI( SPEI_RECOGNITION ) | SPFEI( SPEI_FALSE_RECOGNITION ),     SPFEI( SPEI_RECOGNITION ) | SPFEI( SPEI_FALSE_RECOGNITION ) ); if ( !::CheckHr ( hr, "m_pSRContext->SetInterest()" ) ) {   return hr; }

 //建立一個Grammar hr = m_pSRContext->CreateGrammar ( ullGrammerID, &m_pSRGrammar ); if ( !::CheckHr ( hr, "m_pSRContext->CreateGrammar()" ) ) {   return hr; }

 //從檔案載入識別文法.檔名為WCHAR型別。 hr = m_pSRGrammar->LoadCmdFromFile ( pwcGramFileName, SPLO_DYNAMIC ); if ( !::CheckHr ( hr, "m_pSRGrammar->LoadCmdFromFile" ) ) {   return hr; }

 return hr;}

///////////////////////////////////////////////////////////釋放所有物件。/////////////////////////////////////////////////////////CSR::~CSR( ){ if ( m_pSRGrammar ) {  m_pSRGrammar.Release();  m_pSRGrammar = NULL; } if ( m_pSRContext ) {  m_pSRContext->SetNotifySink(NULL);  m_pSRContext.Release();  m_pSRContext = NULL; } if ( m_pToken) {  m_pToken.Release();  m_pToken = NULL; } if ( m_pAudio ) {  m_pAudio.Release();  m_pAudio = NULL; } if ( m_pInputStream ) {  m_pInputStream.Release();  m_pInputStream = NULL; } if ( m_pSREngine ) {  m_pSREngine.Release();  m_pSREngine = NULL; }}

///////////////////////////////////////////////////////////設定要處理的事件。即上下文要捕捉的事件。//ullInterest 必須是用SPFEI()轉化每個事件,然後用"|"運算得來。//事件的型別是 enum SPEVENTENUM/////////////////////////////////////////////////////////HRESULT CSR::SetInterest ( const  ULONGLONG   ullInterest ){ HRESULT hr; hr = m_pSRContext->SetInterest ( ullInterest, ullInterest ); ::CheckHr ( hr, "CSR::SetInterest" );

 //設定通知視窗的訊息 /*hr = m_pSRContext->SetNotifyWindowMessage ( m_hWnd, WM_RECOEVENT, 0, 0 ); if ( !::CheckHr ( hr, "m_pSRContext->SetNotifyWindowMessage()" ) ) {   return hr; }*/ return hr;}

///////////////////////////////////////////////////////////啟用或者取消某個啟用規則。//m_pSRGrammar->SetRuleState的第三個引數為一個enum SPRULESTATE型別,//常用的為SPRS_INACTIVE,SPRS_ACTIVE。/////////////////////////////////////////////////////////HRESULT CSR::SetRuleState ( const WCHAR *pszName, const BOOL bFlag ){ HRESULT hr;

 if ( bFlag ){  hr = m_pSRGrammar->SetRuleState ( pszName, NULL, SPRS_ACTIVE ); } else {  hr = m_pSRGrammar->SetRuleState ( pszName, NULL, SPRS_INACTIVE ); } ::CheckHr ( hr, "CSR::SetRuleState()" );

 return hr;}

///////////////////////////////////////////////////////////設定.wav檔案的聲音取樣格式要用到enum SPSTREAMFORMAT型別/////////////////////////////////////////////////////////HRESULT CSR::SetInputWithWav ( const WCHAR *pszFileName ){ HRESULT hr;

 //取消規則啟用先 hr = m_pSRGrammar->SetRuleState ( NULL, NULL, SPRS_INACTIVE ); if ( !::CheckHr ( hr, "m_pSRGrammar->SetRuleState" ) ) {   return hr; }

 // 建立基本的sapi流物件。用SpBindToFile繫結到檔案 hr = m_pInputStream.CoCreateInstance(CLSID_SpStream); if ( !::CheckHr ( hr, "m_pInputStream.CoCreateInstance" ) ) {  return hr; }

 //建立WaveFormatEx結構,wav格式是22kHz, 16-bit, Stereo CSpStreamFormat sInputFormat; hr = sInputFormat.AssignFormat(SPSF_22kHz16BitStereo); if ( !::CheckHr ( hr, "sInputFormat.AssignFormat" ) ) {  return hr; }

 //用wav檔案pszFileName設定流物件,只讀 hr = m_pInputStream->BindToFile ( pszFileName,          SPFM_OPEN_READONLY,          &sInputFormat.FormatId(),          sInputFormat.WaveFormatExPtr(),          SPFEI_ALL_EVENTS  ); if ( !::CheckHr ( hr, "m_pInputStream->BindToFile" ) ) {  return hr; }

 // 連線wav輸入到SR. hr = m_pSREngine->SetInput(m_pInputStream, TRUE); if ( !::CheckHr ( hr, "m_pSREngine->SetInput()" ) ) {  return hr; }

 //檢查 識別和流結束 事件 hr = m_pSRContext->SetInterest (SPFEI(SPEI_RECOGNITION) | SPFEI( SPEI_RECOGNITION ) |         SPFEI(SPEI_END_SR_STREAM) | SPFEI(SPEI_START_SR_STREAM),         SPFEI(SPEI_RECOGNITION) | SPFEI( SPEI_RECOGNITION ) |         SPFEI(SPEI_END_SR_STREAM) | SPFEI(SPEI_START_SR_STREAM) );

 //設定通知訊息。 hr = m_pSRContext->SetNotifyWindowMessage ( m_hWnd, WM_RECOEVENT, 0, 0 ); if ( !::CheckHr ( hr, "m_pSRContext->SetNotifyWindowMessage()" ) ) {   return hr; }

 return hr;}

///////////////////////////////////////////////////////////取消從.wav檔案識別,恢復從麥克風識別。/////////////////////////////////////////////////////////HRESULT CSR::UnSetInputWithWav ( ){ HRESULT hr;

 //取消規則啟用先 hr = m_pSRGrammar->SetRuleState ( NULL, NULL, SPRS_INACTIVE ); if ( !::CheckHr ( hr, "m_pSRGrammar->SetRuleState" ) ) {   return hr; }

 hr = m_pSREngine->SetInput ( m_pAudio, TRUE );//為識別引擎設定音訊輸入 if ( !::CheckHr ( hr, "m_pSREngine->SetInput()" ) ) {   return hr; }

 //更新上下文 hr = m_pSRContext->GetRecognizer ( &m_pSREngine ); if ( !::CheckHr ( hr, "m_pSRContext->GetRecognizer()" ) ) {  return hr; }

 //設定通知視窗的訊息 hr = m_pSRContext->SetNotifyWindowMessage ( m_hWnd, WM_RECOEVENT, 0, 0 ); if ( !::CheckHr ( hr, "m_pSRContext->SetNotifyWindowMessage()" ) ) {   return hr; }

 //設定興趣。 hr = m_pSRContext->SetInterest ( SPFEI( SPEI_RECOGNITION ) | SPFEI( SPEI_FALSE_RECOGNITION ),     SPFEI( SPEI_RECOGNITION ) | SPFEI( SPEI_FALSE_RECOGNITION ) ); if ( !::CheckHr ( hr, "m_pSRContext->SetInterest()" ) ) {   return hr; }

 //釋放流 hr = m_pInputStream->Close(); if ( !::CheckHr ( hr, "m_pInputStream->Close" ) ) {   return hr; } //規則全部啟用。 hr = m_pSRGrammar->SetRuleState ( NULL, NULL, SPRS_INACTIVE ); if ( !::CheckHr ( hr, "m_pSRGrammar->SetRuleState" ) ) {   return hr; }

 return hr;}

///////////////////////////////////////////////////////////開始識別(啟用所有規則)。/////////////////////////////////////////////////////////void CSR::StartRecognize ( ){ HRESULT hr; //啟用文法規則,第一個NULL說明啟用全部規則。 hr = m_pSRGrammar->SetRuleState ( NULL, NULL, SPRS_ACTIVE ); ::CheckHr ( hr, "m_pSRGrammar->SetRuleState" );}

///////////////////////////////////////////////////////////識別結束(取消啟用所有規則)。/////////////////////////////////////////////////////////void CSR::EndRecognize ( ){ HRESULT hr; //取消啟用文法規則,第一個NULL說明取消啟用全部規則。 hr = m_pSRGrammar->SetRuleState ( NULL, NULL, SPRS_INACTIVE ); ::CheckHr ( hr, "m_pSRGrammar->SetRuleState" ); return ;}

///////////////////////////////////////////////////////////從事件佇列取得事件並處理。根據相應的事件呼叫相應的函式。/////////////////////////////////////////////////////////void CSR::ProcessRecoEvent( ){ CSpEvent event;  // 事件助手類

    // 迴圈處理事件當事件佇列裡有事件的時候。    while ( event.GetFrom(m_pSRContext) == S_OK )    {        // 察看識別成功事件和識別失敗事件        switch (event.eEventId)        {            case SPEI_RECOGNITION: //識別成功                OnRecoSuccess ( event.RecoResult() );                break;

   case SPEI_FALSE_RECOGNITION://識別失敗    OnRecoFail ();    break;

   case SPEI_START_SR_STREAM:    OnStreamStart ();    break;

   case SPEI_END_SR_STREAM:    OnStreamEnd ();    break;        }    }}

///////////////////////////////////////////////////////////識別成功,把識別成功的短語的所屬的規則頂級ID和子規則的ID傳遞給//ExecuteCommand()。/////////////////////////////////////////////////////////void CSR::OnRecoSuccess ( ISpPhrase *pPhrase ){ SPPHRASE *pElements;

    //得到短語元素,如果其中一個規則id (rule id )是我們在文法中指定的,    //在switch中判斷出是哪一個命令被識別。    if (SUCCEEDED(pPhrase->GetPhrase(&pElements)))    {  ExecuteCommand (  pElements->Rule.ulId,       pElements->pProperties->vValue.ulVal );

        //釋放我們分配的pElements記憶體空間        ::CoTaskMemFree(pElements);    }}

///////////////////////////////////////////////////////////根據識別的短語執行相應的動作。規則ID必須以常量形式預先定義。/////////////////////////////////////////////////////////void CSR::ExecuteCommand ( const  ULONG ulRuleID, const ULONG ulVal ){ switch ( ulRuleID ) //Rule.ulID型別是:  ULONG {  case VID_TopLevelRule://這裡為頂級規則。   switch ( ulVal )   {    case VID_SubLevelRule1://這裡為VID_TopLevelRule規則下的子規則。     ::ShowError ( "子規則1" );     break;    case VID_SubLevelRule2:     ::ShowError ( "子規則2" );     break;    case VID_SubLevelRule3:     ::ShowError ( "子規則3" );     break;    }    break;

  default:   break; }}

///////////////////////////////////////////////////////////識別失敗時觸發的動作。/////////////////////////////////////////////////////////void CSR::OnRecoFail ( ){ ::ShowError ( "識別失敗", "識別失敗" );}

///////////////////////////////////////////////////////////開始從檔案讀入流開始時要觸發的事件。/////////////////////////////////////////////////////////void CSR::OnStreamStart (){ //::ShowError("識別開始");}

///////////////////////////////////////////////////////////開始從檔案讀入流結束時要觸發的事件。/////////////////////////////////////////////////////////void CSR::OnStreamEnd (){ //::ShowError("識別結束");}

ULONGLONG CSR::ullGrammerID = 1000;

需要的留下Email,我給大家發