NUANCE 語(yǔ)音識(shí)別客戶端
RCEngine 實(shí)現(xiàn)總結(jié)
編寫目的:
本文只是一個(gè)純技術(shù)性的文檔,主要從編程角度敘述了利用 RCEngine 開發(fā)語(yǔ)音識(shí)別的過(guò)程與步驟,具體語(yǔ)音識(shí)別的理論,請(qǐng)參考 Nuance 的相關(guān)技術(shù)材料。另外閱讀本文是最好是配合瀏覽 Nuance 的例子程序,以便加深理解。
1. 基礎(chǔ)概念:
RCEngine :
是一個(gè)封裝了語(yǔ)音識(shí)別,語(yǔ)音文件操作,電話控制的類,它派生自 RCEngineInterface 抽象基類。所以要在程序中調(diào)用 Nuance 的語(yǔ)音識(shí)別功能你就必須實(shí)例化 RCEngine 。
NotifiableAdapter :
RCEngine 的所有函數(shù)都是異步函數(shù),它使用確認(rèn) --- 通知形式與用戶程序通信,要獲取到這些確認(rèn)和通知消息你必須建立一個(gè)消息處理類,而這個(gè)類必須派生自 NotifiableAdapter ,并且在實(shí)例化 RCEngine 時(shí)把本類指針交給 RCEngine 。
Application object :
通常 Nuance 把一個(gè)派生自 NotifiableAdapter 的且與一個(gè) RCEngine 對(duì)象對(duì)應(yīng)得實(shí)例化對(duì)象稱為一個(gè) Application object 。一個(gè)應(yīng)用程序可以根據(jù)自己有多少個(gè) license 來(lái)創(chuàng)建多個(gè) Application object 。在 Nuance 的例子和我寫的客戶端中 RCAPP 就是一個(gè) Application object 。
Dispatcher object :
他是個(gè)事件分發(fā)對(duì)象,他一直都在不斷的作把識(shí)別事件分發(fā)給各個(gè) RCEngine 的循環(huán),當(dāng)所有的 RCEngine 都摧毀時(shí)他便自動(dòng)結(jié)束事件循環(huán)。
Triggerable :
觸發(fā)器,你若要讓 Dispatcher 自動(dòng)在某觸發(fā)事件放生時(shí)調(diào)用你的處理函數(shù),那么你的處理函數(shù)實(shí)現(xiàn)的類必須要派生于 Triggerable 。所以我的代碼中 RCAPP 也派生于這個(gè)類。
2. 本客戶端組成:
RCAPP : 擔(dān)當(dāng) Application object 和 Triggerable 角色。
AudioSampleFetcher : 一個(gè)為 RCEngine 提供識(shí)別數(shù)據(jù)的輔助類。
CRCDispatcher : 擔(dān)當(dāng) Dispatcher object 角色。
3. 本程序中各個(gè)類之間的關(guān)系:
每個(gè) RCAPP 包含一個(gè) AudioSampleFetcher 為它在識(shí)別時(shí)提供數(shù)據(jù)。
系統(tǒng)中可根據(jù) license 個(gè)數(shù)創(chuàng)建多個(gè) RCAPP 。各個(gè) RCAPP 的消息需要由 CRCDispatcher 分發(fā)。而 CRCDispatcher 是個(gè)消息分發(fā)的循環(huán)體,它只有在所有 RCAPP 都被刪除時(shí)才退出循環(huán)。 CRCDispatcher 在系統(tǒng)中只可以有一個(gè)。
4. 識(shí)別客戶端初始化流程:
一個(gè)客戶端從創(chuàng)建到開始可以進(jìn)行識(shí)別需要一系列對(duì)象創(chuàng)建過(guò)程,這個(gè)過(guò)程很重要,而且也比較復(fù)雜。下面我將一步步地把這個(gè)過(guò)程描述出來(lái):
4.1. Dispatcher object 的創(chuàng)建:
這是所有操作的開始點(diǎn)。我們需要一些準(zhǔn)備工作來(lái)創(chuàng)建這個(gè) Dispatcher 對(duì)象:
4.1.1. 創(chuàng)建一個(gè) NuanceConfig 對(duì)象:
對(duì)于單獨(dú)語(yǔ)法包的客戶端,我們可以用函數(shù) NuanceConfigBuild ()來(lái)創(chuàng)建,只要向它提供語(yǔ)法包路徑就可以了。對(duì)于多語(yǔ)法包的客戶端我們要用 NuanceConfigBuildFromCommandLine ()函數(shù)來(lái)創(chuàng)建,創(chuàng)建時(shí)把所有參數(shù)作為一個(gè)存放字符串?dāng)?shù)組 (char**) 放到它的第二個(gè)參數(shù)里,它第一個(gè)參數(shù)是參數(shù)個(gè)數(shù)。這里必須要注意第二個(gè)參數(shù)的數(shù)據(jù)的格式和空格大小寫等,任何一個(gè)錯(cuò)誤都會(huì)引起創(chuàng)建失敗。我的做法是用一個(gè)配置文件存儲(chǔ)所有的參數(shù),然后逐一讀出,組裝成一個(gè)字符串指針數(shù)組。下面是我的配置文件的部分:
packagedir=H:\GHT\ICA\CVP_M
packagedir=H:\GHT\ICA\CVP_C
audio.Provider=mem
client.Behaviors=calllog,timeout
。。。。
讀出整理后要求的格式是:
-package
H:\GHT\ICA\CVP_M
–package
H:\GHT\ICA\CVP_M
audio.Provider=mem
client.Behaviors=calllog,timeout
。。。。
上面每一行作為字符串( char* )分別存儲(chǔ)到以下的 punit 數(shù)組中:
typedef char* _tCmdLnUnit;
_tCmdLnUnit punit[256];
然后再調(diào)用 NuanceConfigBuildFromCommandLine ()
4.1.2. 創(chuàng)建一個(gè) Dispatcher :
這部分比較簡(jiǎn)單只要把上一步創(chuàng)建的 NuanceConfig 作為參數(shù)傳入 Dispatcher 的構(gòu)造函數(shù)即可。
4.2. 創(chuàng)建 Application object :
4.2.1. 創(chuàng)建 RCAPP :
本客戶端的 RCAPP 對(duì)象就是 Application object 對(duì)象。它派生于 NotifiableAdapter 和 Triggerable ,并且它有一個(gè) RCEngine * 的內(nèi)部成員。
4.2.2. 創(chuàng)建 RCEngine :
其構(gòu)造函數(shù)為: RCEngine(NuanceConfig const* config, DispatcherInterface & dispatcher, Notifiable & notifiable, NuanceStatus & status) ;把剛才創(chuàng)建的 NuanceConfig 對(duì)象、 Dispatcher 對(duì)象、 RCAPP 對(duì)象的指針作為參數(shù)即可。
4.3. 啟動(dòng) Dispatcher 的消息循環(huán):
4.3.1. 創(chuàng)建一個(gè)線程:
Dispatcher 的消息循環(huán)需要獨(dú)占一個(gè)線程。
4.3.2. 執(zhí)行消息循環(huán):
只要執(zhí)行 Dispatcher 的 Dispatch ()函數(shù)即可。該函數(shù)不會(huì)退出,除非所有 RCEngine 都被刪掉。當(dāng)它退出時(shí),就是這個(gè) Dispatcher 應(yīng)該被刪除的時(shí)候了。
4.4. HandleInitializationCompleted 被調(diào)用:
當(dāng)你的 Application object 的 HandleInitializationCompleted 被調(diào)用時(shí)且通告狀態(tài)值是 NUANCE_OK 時(shí),說(shuō)明你的 RCEngine 已初始化成功了。但注意這里并不是表示你可以進(jìn)行識(shí)別了,你還需要做以完一下工作:
4.4.1. 設(shè)置播音為外部:
因?yàn)槲覀兪褂玫氖亲约旱牟シ乓羝脚_(tái),所以必須設(shè)定是外部播音。
4.4.2. 打開數(shù)據(jù)庫(kù)
我們要用到動(dòng)態(tài)語(yǔ)法所以必須要打開數(shù)據(jù)庫(kù)。用函數(shù) OpenDatabase ()打開數(shù)據(jù)庫(kù),這里要提供 odbc 數(shù)據(jù)源名稱,用戶帳號(hào),數(shù)據(jù)庫(kù)類型的信息。
4.4.3. 打開 calllog 通道
調(diào)用 OpenCalllogChannel ()函數(shù)打開 callog 通道讓 Nuance 把 callog 放到 NuanceConfig 對(duì)象創(chuàng)建時(shí)參數(shù)指定的位置,否則 callog 會(huì)放到客戶端程序同樣路徑下。
4.4.4. 創(chuàng)建 AudioSampleFetcher :
這是個(gè)為識(shí)別提供數(shù)據(jù)的輔助類,在這里創(chuàng)建比較合適。
4.5. HandleNuanceDBOpened :
通告狀態(tài)值是 NUANCE_OK 時(shí),說(shuō)明你的數(shù)據(jù)庫(kù)打開成功。這個(gè)時(shí)候,你的初始化成功完成了。你可以進(jìn)入下一步,開始識(shí)別了。
4.6. 啟動(dòng)識(shí)別:
4.6.1. 設(shè)定識(shí)別閥值:
當(dāng)?shù)淖R(shí)別得分,低于這個(gè)值時(shí),識(shí)別結(jié)果就會(huì)被拒絕。
4.6.2. 設(shè)定 NoSpeechTimeoutSecs 值:
當(dāng) RCEngine 啟動(dòng)超后在該值時(shí)間內(nèi)沒(méi)有人聲輸入,系統(tǒng)就會(huì)結(jié)束識(shí)別并返回 NoSpeechTimeout 信息。
4.6.3. 預(yù)定義輸出結(jié)果格式:
當(dāng)需要格式化的識(shí)別結(jié)果時(shí),要在這里設(shè)定好結(jié)果的輸出格式。比如我們輸入的格式是: <&confidence>spelling:<spelling> 則輸出的結(jié)果可以是: 69 spelling:chai4 shan1 shan1 . 表示識(shí)別分?jǐn)?shù) 69, 識(shí)別出來(lái)的 slot (這里是 <spelling> )對(duì)應(yīng)的值是 chai4 shan1 shan1 。
4.6.4. 啟動(dòng)識(shí)別:
使用 RCEngine 的 RecognizeUtterance ()函數(shù)啟動(dòng)識(shí)別。這里要提供一個(gè) Top grammar ,也就是靜態(tài)語(yǔ)法中的 top grammar. 識(shí)別過(guò)程需要一定的時(shí)間等待結(jié)果,若你要在被過(guò)程中啟動(dòng)超時(shí)則可以通過(guò)設(shè)定 behavior.timeout.ExternalPromptDone 為 TRUE ,讓之前設(shè)定的 NoSpeechTimeoutSecs 生效。
4.6.5. 啟動(dòng)錄音:
由 AudioSampleFetcher 的 StartPlatformDependentRecording 函數(shù)調(diào)用外部錄音平臺(tái)錄音。 AudioSampleFetcher 會(huì)創(chuàng)建觸發(fā)器,該觸發(fā)器會(huì)每 100 毫秒(該值可以在啟動(dòng)觸發(fā)器時(shí)自己定義,推薦用默認(rèn)的 100 毫秒)進(jìn)行一次錄音數(shù)據(jù)的輸入。
4.6.6. 發(fā)現(xiàn)人音 HandleStartOfSpeech :
正常的話,當(dāng)在音頻數(shù)據(jù)中發(fā)現(xiàn)人聲時(shí),你的 application object 的 HandleStartOfSpeech 被調(diào)用。這時(shí)你可以停掉外部的平臺(tái)放音。
4.6.7. 發(fā)現(xiàn)語(yǔ)音結(jié)束點(diǎn) HandleEndOfSpeech :
當(dāng)識(shí)別系統(tǒng)認(rèn)為人聲結(jié)束時(shí),你的 application object 的 HandleEndOfSpeech 會(huì)被調(diào)用。
4.6.8. 發(fā)現(xiàn)語(yǔ)音結(jié)束點(diǎn) HandleRecognitionStopped :
當(dāng)系統(tǒng)識(shí)別結(jié)束時(shí)這個(gè) application object 的 HandleRecognitionStopped 會(huì)被調(diào)用。這時(shí)你要做的是用 AudioSampleFetcher 的 StopPlatformDependentRecording 停掉外部平臺(tái)錄音。用 RecResultGetType ()獲取識(shí)別結(jié)束原因,除了成功外,其中還飽含識(shí)別失敗的原因等,用 RecResultGetTextResult 獲取識(shí)別的格式化結(jié)果。至此一次識(shí)別結(jié)束。
5. 識(shí)別客戶端的關(guān)閉:
識(shí)別客戶端關(guān)閉的具體步驟是:
5.1. 停止所有識(shí)別任務(wù):
用 RCEngine 的 Abort ()函數(shù)終止一切操作。
5.2. 關(guān)閉動(dòng)態(tài)語(yǔ)法數(shù)據(jù)庫(kù):
用 RCEngine 的 CloseDatabase ()關(guān)閉語(yǔ)法數(shù)據(jù)庫(kù)。
5.3. 刪除所有 Application object( 在它釋構(gòu)時(shí)刪除它的 RCEngine 對(duì)象成員 ) :
即刪除本客戶端的 RCAPP 對(duì)象。
5.4. Dispatcher 退出消息循環(huán)時(shí)刪除 Dispatcher object 對(duì)象:
這里一定要等到 Dispatcher 自動(dòng)退出循環(huán)才刪掉這個(gè)對(duì)象,不然會(huì)引起錯(cuò)誤。
lyman
2005.12.30
posted on 2006-06-22 11:43
名羽 閱讀(1020)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
project sum-up