2

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

“这是一个文本” ..

tts.Speak("这是一段文字"); // 这将“读取”它..

好的,很好......但我也需要获取有关“时间”的信息..

例如:

“Th”(“This”的第一个声音(音素))在 0.01 毫秒内被“读取”。

“i”(“is”的第一个声音)在 0.5 毫秒内被“读取”..

“e”(“文本”的第二个声音)在 1.02 毫秒内被“读取”。

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

对不起我的英语,对不起我对我的问题的糟糕描述,但问题是我认为很简单,所有人都会理解。如果不是,我将尝试再次描述问题:) ^^..

4

1 回答 1

4

我使用 C++ 和 SAPI 5.1 来合成语音并让虚拟角色相应地移动它的嘴唇。这是一些适用于语音视位的代码。根据http://msdn.microsoft.com/en-us/library/ms720164(v=vs.85).aspx上的文档,音素的工作方式相同,除了替换SPEI_VISEMESPEI_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);
}
于 2012-05-08T17:50:59.870 回答