`

一个集成微软语音识别技术与语音朗读的类,基于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 DWORDSP_CHINESE = 0x0000;//简体中文.
const DWORDSP_ENGLISH = 0x0001;//英语.

/////////CTTS常量-----------------
const UINTWM_SPEAK = WM_USER + 4444;//触发事件产生的消息。

/////////SR常量-------------------
const UINTWM_RECOEVENT = WM_USER + 3333;//触发事件产生的消息。
const DWORDSR_INPROC = 0x0000;//独享类型的SR.
const DWORDSR_SHARE = 0x0001;//共享类型的SR.

//以下常量仅作例子用。
#define VID_TopLevelRule9000//顶级规则ID
#define VID_SubLevelRule19001//子规则ID
#define VID_SubLevelRule29002//子规则ID
#define VID_SubLevelRule39003//子规则ID


//*************************类声明************************


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

classLANE_SPEECH_DLLCTTS
{
protected:
HWNDm_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
//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

classLANE_SPEECH_DLLCSR
{

protected:
HWNDm_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 ULONGLONGullGrammerID;// 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。
////////////////////////////////////////////////////////////////////
HRESULTSetInputWithWav ( const WCHAR *pszFileName = L"sr.wav" );

////////////////////////////////////////////////////////////////////
//功能:取消从.wav文件识别。恢复从麦克风识别。
//参数:无。
//返回值:HRESULT。
////////////////////////////////////////////////////////////////////
HRESULTUnSetInputWithWav ( );

//***********************识别开始,结束,识别结果的处理**************************

////////////////////////////////////////////////////////////////////
//功能:识别开始(将所有规则激活)。
//参数:无
//返回值:无。
////////////////////////////////////////////////////////////////////
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: lkjx82@msn.com,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 )
{
HRESULThr = 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类型
/////////////////////////////////////////////////////////
HRESULTCSR::SetInputWithWav ( const WCHAR *pszFileName )
{
HRESULThr;

//取消规则激活先
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文件识别,恢复从麦克风识别。
/////////////////////////////////////////////////////////
HRESULTCSR::UnSetInputWithWav ( )
{
HRESULThr;

//取消规则激活先
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("识别结束");
}


ULONGLONGCSR::ullGrammerID = 1000;

需要的留下Email,我给大家发

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics