我使用 C++ 和 SAPI 5.1 来合成语音并让虚拟角色相应地移动它的嘴唇。这是一些适用于语音视位的代码。根据http://msdn.microsoft.com/en-us/library/ms720164(v=vs.85).aspx上的文档,音素的工作方式相同,除了替换SPEI_VISEME
为SPEI_PHONEME
.
DWORD WINAPI Character::sayMessage(LPVOID lpParam){
HRESULT hres;
try{
::CoInitialize(NULL);
ThreadParam * param = (ThreadParam *)lpParam;
wstring s = param->message;
//first check the string for null
if (s == L"") return false;
//http://msdn.microsoft.com/en-us/library/ms720163(VS.85,classic).asp is my source for this
//set up text to speech
//get the voice associated with the character
ISpVoice * pVoice;
pVoice = param->sceneObject->characterVoice;
if (pVoice != NULL){
pVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0 );
SPEVENT event;
ULONG ul;
pVoice->SetInterest(SPFEI(SPEI_VISEME)|SPFEI(SPEI_END_INPUT_STREAM),SPFEI(SPEI_VISEME)|SPFEI(SPEI_END_INPUT_STREAM));
pVoice->SetNotifyCallbackFunction(&eventFunction,0,0);
pVoice->WaitForNotifyEvent(INFINITE);
if (param->sceneObject->age == CHILD){
s = L"<pitch middle=\"+10\">" + s + L"</pitch>";
}
hres = pVoice->Speak(s.c_str(),SPF_ASYNC,NULL);
bool isDone = false;
while(!isDone && pVoice != NULL && !FAILED(hres)){
if(pVoice->GetEvents(1,&event, &ul) == S_OK){
if(event.eEventId==SPEI_VISEME){
//get the viseme
int vis = LOWORD(event.lParam); //handle it however you'd like after this
}
else if(event.eEventId== SPEI_END_INPUT_STREAM){
isDone = true;
s = L"";
return true;
}
}
}
}
}
catch(...){
return false;
}
return !FAILED(hres);
}