C#(C ++)SAPI - TTS - 如何获取正在读取的文本的语音时序

时间:2012-01-14 06:53:12

标签: c# speech-recognition text-to-speech sapi speech-synthesis

请有人帮帮我吗?我搜索一些例子如何通过SAPI获取有关在TTS中编写文本的信息(我在C#编写我的应用程序,但不需要它,SAPI在C ++中是相同的,等等) 我需要的信息是例如: 用户将在文本框中写入:

  

“这是一个文字” ..

     

tts.Speak(“这是一个文本”); //这将“读取”它..

好的,很好......但我也需要获得关于“计时”的信息..

例如:

  

“Th”(“This”的第一个声音(音素))在0.01ms内被“读取”..

     

“i”(“是”的第一个声音)在0.5ms内被“读取”..

     

“e”(“文字”的第二个声音)在1.02ms内被“读”..

当我保存SAPI生成的.wav文件时,我需要获取有关.wav中时间的信息,以便随后“处理”wav文件。

对不起我的英语,对不起我对我的问题的不良描述,但问题是我觉得非常简单,所有人都会理解。如果没有,我会再次尝试描述问题:) ^^ ..

1 个答案:

答案 0 :(得分:4)

我已经使用C ++和SAPI 5.1来合成语音,并让虚拟角色相应地移动它的嘴唇。这是一些适用于视位的代码。根据{{​​3}}上的文档,除了将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);
}