1.引言
隨著計算機網絡,智能家電,多通道用戶界面的飛速發展,人臉與語音相結合的人性化的交互方式,將成為未來人們使用計算機的主要趨勢。在基于網絡的人-人交互系統中,用戶的語音輸入可以直接在網絡上作為音頻流傳輸,在播放的一端進行音素切分,驅動人臉動畫。這樣做的優點是直接播放原始聲音,聲音失真小,缺點是傳輸的數據量大、需要占用較大的網絡帶寬,當虛擬環境中用戶數量較多時網絡和服務器可能不堪重負。另一種可行的方法是在發言的用戶一端將語音輸入切分為音素流,在播放的一端將音素流重新合成為語音,驅動人臉動畫。這樣做需要傳輸的數據量就小得多,網絡和服務器的負載都要小得多,缺點是用戶聽到的是合成語音。本文旨在說明如何利用SAPI5.0對輸入音頻進行音素切分。
2.SAPI5.0 及其語音識別(SR)簡介
微軟的 Speech SDK 5.0是微軟視窗環境的開發工具包。該開發工具包包括了先前的以"Whistler"和 "Whisper"命名的語音識別和語音合成引擎的最新版本。這個SDK中含有語音應用設計接口(SAPI)、微軟的連續語音識別引擎(MCSR)以及微軟的串聯語音合成(又稱語音到文本(TTS))引擎等等。SAPI中還包括對于低層控制和高度適應性的直接語音管理、訓練向導、事件、語法編譯、資源、語音識別(SR)管理以及TTS管理,其中應用程序接口(API)和設備驅動接口(DDI),結構如圖2所示。應用程序通過API層和SAPI(SpeechAPI)通信,語音引擎則通過DDI層和SAPI(SpeechAPI)進行交互。通過使用這些API,可以加快在語音識別或語音合成方面應用程序的開發。
SAPI5在語音識別方面提供的基本服務:
a)管理語音輸入,諸如從麥克風,文件等方式,并負責將語音轉化成引擎所能接受的特定格式。
b)加載文法并負責解析和編輯。
c)編譯用標準xml文件定義的文法,轉換定制文法等。
d)使多個應用共享一個識別引擎.
f)返回結果和必要的信息給應用程序。
g)保存輸入音頻和序列化結果以便分析。
h)進行適當的錯誤異常處理,增加應用程序的健壯性。
SR引擎提供的基本服務:
a)可使用SAPI的文法接口,加載所需文法。
b)進行語音識別
c)可調用SAPI來處理文法和識別狀態的改變。
d)產生識別結果并得到相應事件,以便給應用開發提供必要的信息。
3. 設計思想
由于SAPI5.0不提供直接的方法將中文語音輸入直接分解成相應的音素,故采用這種折衷的辦法來處理。
具體步驟:
a)初始化引擎并使其工作在連續語音識別方式下(Dictation Mode),即非特定詞匯的連續語音識別,同時建立一個從漢字到拼音的映射數據庫。然后進入消息循環處理階段,響應SPEI_SOUND_START消息,開始識別輸入語音,在得到SPEI_SOUND_END消息后,若在此聲音開關其間無任何識別結果,則認為是噪聲信號,不作任何處理。若期間得到SPEI_RECOGNITION消息,則在成功取得識別漢字后,執行b。
b)若處理完畢所有漢字,則輸出隊列中的全部元素,否則,對識別結果中的每一個漢字,重復執行c-e。
c)在識別的漢字中查詢相應的拼音。
d)按照一定的規則分解拼音為可視音素。
e)將該組可視音素入隊列。
用戶對麥克風連續講話,按上述思路,可完成其語音音素分解工作。其中涉及中文可視音素的劃分,在MPEG-4標準中,劃分14組可明顯區分的英文音素。我們根據漢語的發音特點,參照科大訊飛公司的標準及其其他相關文獻把漢語的可視音素劃分為15組。如下表所示:
可視音素標號 音素 可視音素標號 音素
1 A 9 O
2 P, b, m 10 R
3 D,t,n,l 11 U,v
4 E. 12 Z,c,s
5 F 13 Zh,ch,sh
6 G,k,h 14 N
7 I 15 Ng
8 J,q,x
每一組都代表一種可視音素的基本的口型,任何一個漢字拼音都可以分解為這些可視音素的組合。這樣,在輸出端就可使用音素流來驅動虛擬人臉了。
4. 具體實現
4.1)初始化COM
if (SUCCEEDED(::CoInitialize(NULL)))
{//進入主消息循環,直到收到退出消息為止
while(GetMessage(&msg,NULL,0,0)
{//消息處理代碼
......
}
::CoUninitialize();//退出時,釋放相關資源
}
4.2)初始化識別引擎
CComPtr<ISpRecoContext> cpRecoCtxt;
CComPtr<ISpRecoGrammar> cpDictationGrammar;
CComPtr<ISpRecognizer> cpRecoEngine;
CComPtr<ISpAudio> cpAudio;
hr = cpRecoEngine.CoCreateInstance(CLSID_SpInprocRecognizer);
//創建一個識別引擎對象,并使其工作在排他方式,只允許該應用訪問此識別引擎。
if( SUCCEEDED( hr ) )//
{
hr = cpRecoEngine->CreateRecoContext( &cpRecoCtxt );
//為該識別引擎實例創建一個識別上下文;
}
if (SUCCEEDED(hr))
{
hr = cpRecoCtxt->SetNotifyWindowMessage( hWnd, WM_USER_SR_MSG, 0, 0 );
//設定識別通知消息為WM_USER_SR_MSG(自定義消息),并由該消息所指定的函數處理;
}
if (SUCCEEDED(hr))
{//設定哪些引擎識別事件(消息)可觸發識別通知消息;
//在此,我們僅關心正確的識別消息(SPEI_RECOGNITION),而不關心假設識別和錯誤識別消息(即SPEI_HYPOTHESIS和SPEI_FALSE_RECOGNITION);
const ULONGLONG ullMyInterest = SPFEI(SPEI_RECOGNITION);
hr = m_cpRecoCtxt->SetInterest(ullMyInterest, ullMyInterest);
}
// 創建默認的音頻對象;
hr = SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN, &cpAudio);
// 設定引擎的輸入到cpAudio對象,以便處理SPEI_SOUND_START和SPEI_SOUND_END消息;
hr = cpRecoEngine->SetInput(cpAudio, TRUE);
hr = cpRecoEngine->SetRecoState( SPRST_ACTIVE );
if (SUCCEEDED(hr))
{
// 設定需要的文法并使其有效
hr = cpRecoCtxt->CreateGrammar( 0, &cpDictationGrammar );
}
if (SUCCEEDED(hr))
{
hr = cpDictationGrammar->LoadDictation(NULL, SPLO_STATIC);
}
if (SUCCEEDED(hr))
{
hr = m_cpDictationGrammar->SetDictationState( SPRS_ACTIVE );
}
4.3) 響應WM_USER_SR_MSG消息,并處理如下:
ProcessSapiMessage(......)
{
USES_CONVERSION;
CSpEvent event;
// 處理程序所關心的消息
while (event.GetFrom(cpRecoCtxt) == S_OK )
{
switch (event.eEventId)
{
case SPEI_SOUND_START:
bInputSound = TRUE;
break;
case SPEI_SOUND_END:
if (bInputSound)
{
bInputSound = FALSE;
if (!bGotReco)//是否識別到漢字?
{
// 一段語音輸入已完成,即檢測到了語音的開始和結束
// 但是識別引擎沒有成功識別任何東西,特殊處理
........
}
bGotReco = FALSE;
}
break;
case SPEI_RECOGNITION:
// 得到識別結果,可能是一個字,也可能是一個詞組,統一處理
{
bGotReco = TRUE;
CSpDynamicString dstrText;
if(SUCCEEDED(event.RecoResult()->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE, &dstrText, NULL)))
{
GetWordViseme(dstrText);//自定義函數,得到dstrText中漢字的可視音素并輸出。
}
break;
}
}//switch over
}//while loop over;
}
5. 結束語和進一步的工作
由于使用了連續的語音識別模式,就要求對講話者進行大量的語音訓練,否則識別效果堪憂,則相應的音素分解也就不言爾喻了。加之整個分解是建立在識別基礎上的,對機器的性能,速度要求也比較高。因此,我們擬采用更直接的方法,實際上,對音素表示而言,在人臉動畫應用方面,用它來合成語音是不太合適的。由于音素只是從聲學角度來區別發音高低,傳遞有用的語言成份,它忽略了發聲和臉形之間的聯系,臉形的幅度(大小)和發音能量之間的聯系,發音時和唇形的聯系等等。所以,我們希望能從音頻信號中直接產生唇形,以產生更加真實感的人臉動畫,這是下一步的工作。
|