夏俊杰,楊青,趙剛
(1.四川大學(xué)四川成都610064;2.成都中醫(yī)藥大學(xué)四川成都611130)
在設(shè)計(jì)問診系統(tǒng)時(shí),使用Authorware開發(fā)工具進(jìn)行開發(fā),并且使用語(yǔ)音識(shí)別技術(shù)模擬醫(yī)生問的過程。語(yǔ)音識(shí)別采用微軟的語(yǔ)音開發(fā)包。微軟語(yǔ)音開發(fā)包中語(yǔ)音識(shí)別引擎是以COM為基礎(chǔ)構(gòu)成的組件[1],但在Authorware中不能直接調(diào)用,而Authorware中使用控件是非常方便的。因此將語(yǔ)音識(shí)別接口編寫成控件的形式,然后在Authorware中調(diào)用。這樣就避免了編寫語(yǔ)音識(shí)別的程序,減少編程的代碼量,提高開發(fā)效率。文中就以語(yǔ)音識(shí)別組件為例來說明如何將COM組件轉(zhuǎn)化成控件。
COM組件和控件有一定的相似之處,都是基于COM原理[2]。COM組件和ActiveX控件都是模塊程序供其它程序調(diào)用。如圖1所示,COM組件的數(shù)據(jù)成員和控件中的方法類似;消息和事件類似。對(duì)于控件中的屬性則可能與組件中數(shù)據(jù)成員和函數(shù)成員都相關(guān),需根據(jù)情況而定。它們之間可以相互轉(zhuǎn)化。
圖1 COM組件和activex控件的對(duì)比Fig.1 Comparison of COMcomponent and ActiveX control
語(yǔ)音識(shí)別組件轉(zhuǎn)化成控件的流程如圖2所示。由于組件接口比較多,調(diào)用起來不方便,因此先將組件接口封裝成一個(gè)C++類,這樣只要調(diào)用C++的幾個(gè)函數(shù)成員和數(shù)據(jù)成員就能調(diào)用引擎接口,使用比較方便。然后用VC設(shè)計(jì)一個(gè)語(yǔ)音識(shí)別控件。通過調(diào)用C++類的函數(shù)成員、數(shù)據(jù)成員和消息,在控件中添加相應(yīng)的屬性、方法和事件。對(duì)于控件中的方法可以調(diào)用類中的函數(shù)成員。對(duì)于控件中的事件可類中的消息關(guān)聯(lián)起來。這樣就可完成語(yǔ)音識(shí)別控件的設(shè)計(jì)。
圖2 設(shè)計(jì)流程Fig.2 Process of designing
SAPI的語(yǔ)音識(shí)別引擎SR提供了語(yǔ)音識(shí)別功能的一系列函數(shù),封裝在多個(gè)接口中。實(shí)現(xiàn)語(yǔ)音識(shí)別功能,主要使用ISpRecognizer、ISpRecoContext、ISpRecoGrammer等接口。Isp-Recognizer主要用于語(yǔ)音識(shí)別,將語(yǔ)音信號(hào)識(shí)別轉(zhuǎn)換成文本信息。IspRecoContext主要用于發(fā)送和接受消息。IspRecoGrammer主要用于加載語(yǔ)法規(guī)則。實(shí)現(xiàn)語(yǔ)音識(shí)別步驟為[3]:
1)初始化COM
2)建立IspRecognizer對(duì)象,通常建立COM對(duì)象有2種方法,一種是使用COM庫(kù)函數(shù)建立對(duì)象,使用CoCreateInstance()函數(shù)。另一種是使用智能指針建立COM對(duì)象,這種方法較常用。以建立IspRecognizer對(duì)象為例來說明。使用CcomPtr<IspRecognizer>m_pReco建立一個(gè)智能指針對(duì)象m_pReco,然后CcomPtr類中CoCreateInstance()函數(shù)創(chuàng)建IspRecognizer對(duì)象,即m_pReco.CoCreateInstance(…),然后就可使用m_pReco指針調(diào)用IspRecognizer接口中函數(shù)了。
3)創(chuàng)建IspRecoContext對(duì)象,設(shè)置消息的發(fā)送和接受。通過IspRecoContex接口中的SetNotifyWindowMessage()函數(shù)將消息傳遞到指定的窗口。并且調(diào)用其中的SetInterest()函數(shù)指定需要的某類特定消息。
4)建立IspRecoGrammer對(duì)象,加載語(yǔ)法規(guī)則。用Load Dictation()函數(shù)設(shè)置語(yǔ)音輸入方式進(jìn)行識(shí)別。
5)調(diào)用IspRecognizer接口函數(shù),比如停止識(shí)別、暫停識(shí)別、語(yǔ)音訓(xùn)練、麥克風(fēng)設(shè)置等。
為了調(diào)用方便,將語(yǔ)音識(shí)別接口寫成一個(gè)類CMyReco,類中包括了語(yǔ)音識(shí)別接口的所有功能。
class CMyReco{
……
BOOL Initialize(HWND hWnd=NULL,BOOL bIsShared=TRUE);//初始化函數(shù)
BOOL Start();//開始識(shí)別
BOOL Stop();//停止識(shí)別
//獲取識(shí)別出的文本
void GetRecoText(WCHAR**ppszCoMemText,ULONG ulStart=0,ULONG nlCount=-1);
CComPtr<ISpRecognizer>m_pREng;//創(chuàng)建智能指針
CComPtr<ISpRecoContext>m_pRecoCtxt;//創(chuàng)建智能指針
CComPtr<ISpRecoGrammar>m_pDictationGrammar;//創(chuàng)建智能指針
}
初始化函數(shù)將各種對(duì)象接口都建立了。初始化后就可以調(diào)用其他的如暫停、開始等函數(shù)。
控件一般有方法、屬性和事件3個(gè)組成成分[4]。將語(yǔ)音識(shí)別接口函數(shù)中的開始、停止、麥克風(fēng)設(shè)置等函數(shù)作為控件中的方法;而識(shí)別出來的文本作為控件的屬性;通知用戶已產(chǎn)生文本的消息作為控件中的事件。下面說明制作語(yǔ)音識(shí)別控件的步驟:
1)利用VC++工具建立一個(gè)控件工程SREngine,將上面的CMyReco類文件加入到控件工程中。
2)初始化語(yǔ)音識(shí)別引擎
在CSREngineCtrl中添加WM_CREATE消息類型的消息響應(yīng)函數(shù)OnCreate()。在該函數(shù)中實(shí)現(xiàn)語(yǔ)音識(shí)別初始化。
int CSREngineCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct){
……..
m_SpeechReco.Initialize(this->GetSafeHwnd());
…….
}
其中m_SpeechReco是類CMyReco的對(duì)象。
3)添加方法
實(shí)現(xiàn)停止語(yǔ)音識(shí)別、開始語(yǔ)音識(shí)別、麥克風(fēng)設(shè)置、是否語(yǔ)音識(shí)別引擎等功能可以使用控件的方法實(shí)現(xiàn)。例如,用類向?qū)虺绦虼a中添加方法SpStart。在CSREngineCtrl類的函數(shù)SpStart()中調(diào)用類CMyReco的Start()函數(shù)即可。在外部拖過要開始語(yǔ)音識(shí)別引擎,就可調(diào)用SpStart方法實(shí)現(xiàn)。其他功能的設(shè)計(jì)和開始語(yǔ)音識(shí)別功能的設(shè)計(jì)一樣。
4)添加屬性
為了獲取識(shí)別的結(jié)果,在控件中添加一個(gè)屬性用來保存識(shí)別出的文本。用類向?qū)砑訉傩許Rtext,同時(shí)添加了GetSRtext()和SetSRtext()兩個(gè)函數(shù)。當(dāng)外部程序讀屬性時(shí),調(diào)用GetSRtext()函數(shù)。當(dāng)設(shè)置屬性是調(diào)用SetSRtext()函數(shù)。因此,在GetSRtext函數(shù)中添加獲取語(yǔ)音識(shí)別結(jié)果的代碼。
BSTR CSREngineCtrl::GetSRtext(){
CString strResult;strResult=m_strText;
return strResult.AllocSysString();
}
其中m_strText是一個(gè)CString類的對(duì)象,保存語(yǔ)音識(shí)別引擎識(shí)別出來的字符串。對(duì)SetSRText函數(shù)不需加代碼。
5)添加事件
為了知道什么時(shí)候產(chǎn)生了識(shí)別出的文字,需要添加事件。用類向?qū)砑邮录RResult,并且在CSREngineCtrl類中產(chǎn)生了FireSRResult()函數(shù)。在控件內(nèi)部調(diào)用FireSRResult()函數(shù),F(xiàn)ireSRResult()函數(shù)調(diào)用FireEvent函數(shù),從而對(duì)外部產(chǎn)生SRResult事件。另外當(dāng)產(chǎn)生識(shí)別的文本時(shí),語(yǔ)音識(shí)別引擎通過CMyReco類中自定義的消息WM_SREVENT進(jìn)行通知。因此在CSREngineCtrl類中添加WM_SREVENT消息對(duì)應(yīng)的消息響應(yīng)函數(shù)OnSREvent()。在該函數(shù)中獲取識(shí)別出的文本,并調(diào)用FireSRResult()函數(shù)。
LRESULT CSREngineCtrl::OnSREvent(WPARAM,LPARAM){
WCHAR*pwzText;
m_SpeechReco.GetRecoText(&pwzText);
m_strText=CString(pwzText);
FireSRResult();
……
}
這樣當(dāng)有文本被識(shí)別出來后,保存在m_strText中。然后調(diào)用FireSRResult()函數(shù)產(chǎn)生SRResult事件通知外部程序有識(shí)別出的文本,外部程序根據(jù)事件獲取SRtext屬性值,就可以獲取語(yǔ)音識(shí)別出來的文本。
最后編譯生成控件SREngine.ocx,那么在其他開發(fā)工具中就可調(diào)用了。
在Authorware中,使用“插入”菜單插入SREng控件。使用GetSpriteProperty()函數(shù)獲取SRtext屬性值,即獲取從語(yǔ)音中識(shí)別出的文本。用CallSprite函數(shù)設(shè)置語(yǔ)音識(shí)別控件的開始、暫停等功能[5]。用一個(gè)交互圖標(biāo)進(jìn)行對(duì)SRResult事件的響應(yīng),并對(duì)事件進(jìn)行處理,即獲取SRtext屬性值,并顯示在文本框中。最后界面如圖3所示,輸入語(yǔ)音即可識(shí)別輸出文本。
圖3 語(yǔ)音識(shí)別控件測(cè)試Fig.3 Test of speech recognition control test
文中介紹了COM組件和ActiveX控件的轉(zhuǎn)化方法。通過一個(gè)語(yǔ)音識(shí)別的例子詳細(xì)說明轉(zhuǎn)化流程和方法。先將語(yǔ)音識(shí)別引擎接口封裝成一個(gè)C++類,這是方便對(duì)語(yǔ)音引擎接口的調(diào)用。然后添加控件的屬性、方法和事件設(shè)計(jì)控件。在控件方法和事件中,對(duì)類的函數(shù)成員或數(shù)據(jù)成員進(jìn)行相應(yīng)調(diào)用。最后,將控件在Authorware中運(yùn)行得到較好效果。對(duì)于Authorware這樣的專用開發(fā)工具可以利用COM與其他應(yīng)用程序進(jìn)行通信[6-7],也可提高開發(fā)效率。
[1] Microsoft Corporation.Microsoft Speech SDK[EB/OL].(2009-3-3)[2012-4-20].http://download.microsoft.com/download/B/4/3/B4314928-7B71-4336-9DE7-6FA4CF00B 7B3/sapi.chm.
[2] 潘愛民.COM原理與應(yīng)用[M].北京:清華大學(xué)出版社,1999.
[3] 史俊.語(yǔ)音數(shù)控機(jī)床的研究與實(shí)現(xiàn)[D].沈陽(yáng):沈陽(yáng)航空工業(yè)學(xué)院,2007.
[4] 孫鑫,余安萍.VC++深入詳解[M].北京:電子工業(yè)出版社,2006.
[5] 孫偉.Authorware與Activex控件的高級(jí)通訊[J].集寧師專學(xué)報(bào),2009,31(4):57-60.SUN Wei.A senior communication of authorware to the ActiveX control[J].Journal of Jining Teachers College,2009,31(4):57-60.
[6] 鄭楠,徐良賢.COM組件技術(shù)在多媒體軟件開發(fā)中的應(yīng)用[J].計(jì)算機(jī)工程,2002,28(10):81-83.ZHENG Nan,XU Liang-xian.The application of COMin the development of mutimedia software[J].Computer Engineering,2002,28(10):81-83.
[7] Szyperski C.Component Software Beyond Object-oriented Programming[M].ACMPress,1998.