導讀:
語音類
1)在構造語音類之前,必須先設置好工程環境:
a、從微軟官方網站下載windows speech sdk並安裝,然後在Visual Studio 6.0中進行相關設置,在Project Setings選項的C++選項卡的“分類:預處理器”添加“,__WIN32_DCOM”(爲預先初始化COM組件成功);
b、將預處理頭文件選項選中“自動使用預補償頁眉”;
c、在常規選項卡中選擇“實用MFC靜態連接庫”;
入圖:(一)
2)封裝語音類
由於採用面向對象的編程理念,藉助UML(Unified Modeling Language統一建模語言)構造CSPEECH語音類如下
CSPEECH類
+ void InitSR(); //初始化語音
+void RecoEvent();//識別命令函數
+BOOL b_initSR;
+BOOL b_Cmd_Grammar;
//3個語音接口
+CComPtr m_cpRecocontxt;
+CComPtr m_cpRecoGrammar;
+CComPtr m_cpRecoEngine;
然後開始添加語音類,需要注意的是在定義語音類的頭文件中,包含〈sphelper.h〉並且自定義語音識別消息和類型
#define GID_CMD_GR 333333
#define WM_RECOEVENT WM_USER+102
剩下來就是對cpp文件的函數initSR()和RecoEvent()補充函數體
3)具體見下面代碼:
(1)void CSpeech::initSR()
{
HRESULT hr=S_OK;
hr=m_cpRecoEngine.CoCreateInstance(CLSID_SpInprocRecognizer);//創建識別引擎COM實例
if(SUCCEEDED(hr))
{
hr =m_cpRecoEngine->CreateRecoContext(&m_cpRecoCtxt );//創建識別上下文
}
else
MessageBox(hWnd,"error1","error",S_OK);
if(SUCCEEDED(hr))
{
hr = m_cpRecoCtxt->SetNotifyWindowMessage(hWnd, WM_RECOEVENT, 0, 0 );
}//消息機制設置,使計算機時刻監聽語音消息
else
MessageBox(hWnd,"error2","error",S_OK);
if (SUCCEEDED(hr))
{
ULONGLONG ullMyEvents = SPFEI(SPEI_RECOGNITION) | SPFEI(SPEI_HYPOTHESIS);
hr = m_cpRecoCtxt->SetInterest(ullMyEvents, ullMyEvents);
}
else
MessageBox(hWnd,"error3","error",S_OK);
//設置默認的音頻
CComPtr m_cpAudio;
hr=SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN,&m_cpAudio);//建立默認的音頻輸入對象
hr=m_cpRecoEngine->SetInput(m_cpAudio,TRUE);//設置識別引擎輸入源
hr=m_cpRecoCtxt->CreateGrammar(GID_CMD_GR,&m_cpCmdGrammar);//創建命令語法
b_Cmd_Grammar=TRUE;
if(FAILED(hr))
{
MessageBox(hWnd,"error 4","error",S_OK);
}
hr=m_cpCmdGrammar->LoadCmdFromResource(NULL,MAKEINTRESOURCEW(IDR_CMDCTRL),L"SRGRAMMAR",MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL), SPLO_DYNAMIC);//加載命令語法文件
if(FAILED(hr))
{
MessageBox(hWnd,"error5","error",S_OK);
}
b_initSR=TRUE;
}
(2)BOOL CSpeech::RecoEvent()
{
USES_CONVERSION;
CSpEvent event;
while(event.GetFrom(m_cpRecoCtxt)==S_OK)
{
switch(event.eEventId)
{
case SPEI_RECOGNITION:
{
static const WCHAR wszUnrecognized[]=L"";
CSpDynamicString dstrText;
if(FAILED(event.RecoResult()->GetText(SP_GETWHOLEPHRASE,SP_GETWHOLEPHRASE,TRUE,&dstrText,NULL)))
{
dstrText=wszUnrecognized;
}
dstrText.CopyToBSTR(&SRout);
Recstring.Empty();
Recstring=SRout;
if(b_Cmd_Grammar)
{
if(Recstring=="左")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"左轉",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->LEFT=1;
return TRUE ;
}
if(Recstring=="向下走")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"開始後退",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->BACK=1;
return TRUE ;
}
if(Recstring=="最小化")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"最小化",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
SendMessage(hWnd,WM_SYSCOMMAND, SC_MINIMIZE, MAKELPARAM(0, 0));
return TRUE;
}
if(Recstring=="右")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"開始右轉",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->RIGHT=1;
return TRUE ;
}
if(Recstring=="停下來")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"動作開始了",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->Move=0;
m_OpenGL->m_baiscobj->BACK=0;
m_OpenGL->m_baiscobj->LEFT=0;
m_OpenGL->m_baiscobj->RIGHT=0;
return TRUE ;
}
if(Recstring=="跑步")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"動作開始了",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->Move=1;
return TRUE ;
}
if(Recstring=="退出")
{
m_OpenGL->CleanUp(); // 結束處理
PostQuitMessage(0);
return TRUE;
}
}
}
}
}return TRUE;
}
要注意的是RecoEvent()必須能處理人物、攝像頭的漫遊,所以在人物、攝像機類的行爲函數中添加了控制變量Move、BACK、LEFT、RIGHT;並附了初值1,當在行爲函數中爲1時行爲函數體執行,所以也必須
#include "OpenGL.h"
#include "baiscobj.h"
其間我們藉助於指針變量,巧妙的使語音能控制行爲,卻不影響動畫的刷新,但不足的是由於opengl動畫md2模型的不能導入成功,使踢球,跳木箱等功能函數沒有完成,所以只要行爲函數出來,可通過上述同樣方法實現語音控制。
4)如何在winmain()函數中執行語音程序?
首先包含語音頭文件〈sapi.h〉
接着(#define CSpeech speech)定義語音類對象
INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,INT )// WinMain程序入口
{
::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);//初始化COM
……
char cc[]="tml";
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, (LPCTSTR)IDR_MENU1,
cc, NULL };
RegisterClassEx( &wc );
m_OpenGL=new OpenGL();//
hWnd = CreateWindowEx(NULL,cc,"智能精靈鍵盤(↑進↓退→右←左UP仰DOWM俯)",
dwStyle|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,nX,nY,Width, Height,NULL,NULL,hInst,NULL); // 創建窗口
ShowWindow( hWnd, SW_SHOWDEFAULT ); // 顯示窗口
UpdateWindow( hWnd ); // 刷新窗口
speech.b_Cmd_Grammar=FALSE;
speech.initSR();
GameLoop(); // 進入消息循環
return 0;
}
通過speech.initSR(),執行語音的初始化,爲了設置一個簡單的語音識別開關,簡單的添加一個任務欄,只有語音這一個菜單資源,然後利用消息機制,在消息處理函數裏Switch(message)裏添加:
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_SPEECH:speech.startcmd();
}
return 0;break;
即當單擊語音菜單時,則使語音功能完全激活,下面是這個函數的實體:
void CSpeech::startcmd()
{
if(b_initSR)
{
HRESULT hr=m_cpCmdGrammar->SetRuleState(NULL,NULL,SPRS_ACTIVE);
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return ;
}
hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"語法已經激活",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
}
}
5)在所有的工作完成之前,還必須先在項目工程下添加XML語法文件,通過initSR()中的LoadCmdFromResource()函數加載;XML文件可通過以記事本形式打開編輯。具體如下:
---
本文轉自
http://www.bigbigpan.blogbus.com/logs/8177740.html
語音類
1)在構造語音類之前,必須先設置好工程環境:
a、從微軟官方網站下載windows speech sdk並安裝,然後在Visual Studio 6.0中進行相關設置,在Project Setings選項的C++選項卡的“分類:預處理器”添加“,__WIN32_DCOM”(爲預先初始化COM組件成功);
b、將預處理頭文件選項選中“自動使用預補償頁眉”;
c、在常規選項卡中選擇“實用MFC靜態連接庫”;
入圖:(一)
2)封裝語音類
由於採用面向對象的編程理念,藉助UML(Unified Modeling Language統一建模語言)構造CSPEECH語音類如下
CSPEECH類
+ void InitSR(); //初始化語音
+void RecoEvent();//識別命令函數
+BOOL b_initSR;
+BOOL b_Cmd_Grammar;
//3個語音接口
+CComPtr m_cpRecocontxt;
+CComPtr m_cpRecoGrammar;
+CComPtr m_cpRecoEngine;
然後開始添加語音類,需要注意的是在定義語音類的頭文件中,包含〈sphelper.h〉並且自定義語音識別消息和類型
#define GID_CMD_GR 333333
#define WM_RECOEVENT WM_USER+102
剩下來就是對cpp文件的函數initSR()和RecoEvent()補充函數體
3)具體見下面代碼:
(1)void CSpeech::initSR()
{
HRESULT hr=S_OK;
hr=m_cpRecoEngine.CoCreateInstance(CLSID_SpInprocRecognizer);//創建識別引擎COM實例
if(SUCCEEDED(hr))
{
hr =m_cpRecoEngine->CreateRecoContext(&m_cpRecoCtxt );//創建識別上下文
}
else
MessageBox(hWnd,"error1","error",S_OK);
if(SUCCEEDED(hr))
{
hr = m_cpRecoCtxt->SetNotifyWindowMessage(hWnd, WM_RECOEVENT, 0, 0 );
}//消息機制設置,使計算機時刻監聽語音消息
else
MessageBox(hWnd,"error2","error",S_OK);
if (SUCCEEDED(hr))
{
ULONGLONG ullMyEvents = SPFEI(SPEI_RECOGNITION) | SPFEI(SPEI_HYPOTHESIS);
hr = m_cpRecoCtxt->SetInterest(ullMyEvents, ullMyEvents);
}
else
MessageBox(hWnd,"error3","error",S_OK);
//設置默認的音頻
CComPtr m_cpAudio;
hr=SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN,&m_cpAudio);//建立默認的音頻輸入對象
hr=m_cpRecoEngine->SetInput(m_cpAudio,TRUE);//設置識別引擎輸入源
hr=m_cpRecoCtxt->CreateGrammar(GID_CMD_GR,&m_cpCmdGrammar);//創建命令語法
b_Cmd_Grammar=TRUE;
if(FAILED(hr))
{
MessageBox(hWnd,"error 4","error",S_OK);
}
hr=m_cpCmdGrammar->LoadCmdFromResource(NULL,MAKEINTRESOURCEW(IDR_CMDCTRL),L"SRGRAMMAR",MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL), SPLO_DYNAMIC);//加載命令語法文件
if(FAILED(hr))
{
MessageBox(hWnd,"error5","error",S_OK);
}
b_initSR=TRUE;
}
(2)BOOL CSpeech::RecoEvent()
{
USES_CONVERSION;
CSpEvent event;
while(event.GetFrom(m_cpRecoCtxt)==S_OK)
{
switch(event.eEventId)
{
case SPEI_RECOGNITION:
{
static const WCHAR wszUnrecognized[]=L"";
CSpDynamicString dstrText;
if(FAILED(event.RecoResult()->GetText(SP_GETWHOLEPHRASE,SP_GETWHOLEPHRASE,TRUE,&dstrText,NULL)))
{
dstrText=wszUnrecognized;
}
dstrText.CopyToBSTR(&SRout);
Recstring.Empty();
Recstring=SRout;
if(b_Cmd_Grammar)
{
if(Recstring=="左")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"左轉",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->LEFT=1;
return TRUE ;
}
if(Recstring=="向下走")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"開始後退",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->BACK=1;
return TRUE ;
}
if(Recstring=="最小化")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"最小化",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
SendMessage(hWnd,WM_SYSCOMMAND, SC_MINIMIZE, MAKELPARAM(0, 0));
return TRUE;
}
if(Recstring=="右")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"開始右轉",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->RIGHT=1;
return TRUE ;
}
if(Recstring=="停下來")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"動作開始了",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->Move=0;
m_OpenGL->m_baiscobj->BACK=0;
m_OpenGL->m_baiscobj->LEFT=0;
m_OpenGL->m_baiscobj->RIGHT=0;
return TRUE ;
}
if(Recstring=="跑步")
{
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return FALSE;
}
HRESULT hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"動作開始了",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
m_OpenGL->m_baiscobj->Move=1;
return TRUE ;
}
if(Recstring=="退出")
{
m_OpenGL->CleanUp(); // 結束處理
PostQuitMessage(0);
return TRUE;
}
}
}
}
}return TRUE;
}
要注意的是RecoEvent()必須能處理人物、攝像頭的漫遊,所以在人物、攝像機類的行爲函數中添加了控制變量Move、BACK、LEFT、RIGHT;並附了初值1,當在行爲函數中爲1時行爲函數體執行,所以也必須
#include "OpenGL.h"
#include "baiscobj.h"
其間我們藉助於指針變量,巧妙的使語音能控制行爲,卻不影響動畫的刷新,但不足的是由於opengl動畫md2模型的不能導入成功,使踢球,跳木箱等功能函數沒有完成,所以只要行爲函數出來,可通過上述同樣方法實現語音控制。
4)如何在winmain()函數中執行語音程序?
首先包含語音頭文件〈sapi.h〉
接着(#define CSpeech speech)定義語音類對象
INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,INT )// WinMain程序入口
{
::CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);//初始化COM
……
char cc[]="tml";
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, (LPCTSTR)IDR_MENU1,
cc, NULL };
RegisterClassEx( &wc );
m_OpenGL=new OpenGL();//
hWnd = CreateWindowEx(NULL,cc,"智能精靈鍵盤(↑進↓退→右←左UP仰DOWM俯)",
dwStyle|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,nX,nY,Width, Height,NULL,NULL,hInst,NULL); // 創建窗口
ShowWindow( hWnd, SW_SHOWDEFAULT ); // 顯示窗口
UpdateWindow( hWnd ); // 刷新窗口
speech.b_Cmd_Grammar=FALSE;
speech.initSR();
GameLoop(); // 進入消息循環
return 0;
}
通過speech.initSR(),執行語音的初始化,爲了設置一個簡單的語音識別開關,簡單的添加一個任務欄,只有語音這一個菜單資源,然後利用消息機制,在消息處理函數裏Switch(message)裏添加:
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_SPEECH:speech.startcmd();
}
return 0;break;
即當單擊語音菜單時,則使語音功能完全激活,下面是這個函數的實體:
void CSpeech::startcmd()
{
if(b_initSR)
{
HRESULT hr=m_cpCmdGrammar->SetRuleState(NULL,NULL,SPRS_ACTIVE);
ISpVoice *pVoice=NULL;
if(FAILED(CoInitialize(NULL)))
{
MessageBox(hWnd,"Error to initialize COM","error",S_OK);
return ;
}
hr=CoCreateInstance(CLSID_SpVoice,NULL,CLSCTX_ALL,IID_ISpVoice,(void**)&pVoice);
if(SUCCEEDED(hr))
{
hr=pVoice->Speak(L"語法已經激活",0,NULL);
pVoice->Release();
pVoice=NULL;
}
CoUninitialize();
}
}
5)在所有的工作完成之前,還必須先在項目工程下添加XML語法文件,通過initSR()中的LoadCmdFromResource()函數加載;XML文件可通過以記事本形式打開編輯。具體如下:
---
下
左
右
向上走
向下走
跳
停下來
跑步
識別
語音
還原
文件
踢球
本文轉自
http://www.bigbigpan.blogbus.com/logs/8177740.html