【问题标题】:C# (C++) SAPI - TTS - how to get the speech timings for the text being readC# (C++) SAPI - TTS - 如何获取正在阅读的文本的语音时间
【发布时间】:2012-02-10 06:05:17
【问题描述】:

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

“这是一个文本”..

tts.Speak("This is a text"); // 这将“阅读”它..

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

例如:

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

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

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

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

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

【问题讨论】:

  • TTS 引擎不是这样工作的。语音单位是音素。您可以订阅Phoneme 事件,它会为您提供角色位置和持续时间。 msdn.microsoft.com/en-us/library/ms723588%28v=vs.85%29.aspx
  • 谢谢你们,我会查看链接并了解一些有关它的信息。。再问一个问题。如果我“声明”它,或者我什么时候用音素或单词来实现可以得到有关时间的信息?? (如果我理解得很好)..再次谢谢你..:) 编辑:对不起,我读错了:)..“它给了你角色位置和持续时间”它在我的提问中的答案:) 谢谢:)
  • 但是..有人问更多..我怎样才能“使用”SpVoice.phoneme()? :-/我正在尝试获取有关文本的一些信息..我总是得到错误 SpeechLib._ISpeechVoiceEvents_Event.Phoneme' 只能出现在 += 或 -=..:-/ 的左侧,并且一些示例不存在..

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


【解决方案1】:

我使用 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);
}

【讨论】:

  • 您好,请问您能否帮我解决这个问题。 stackoverflow.com/questions/17966387/…
  • 不幸的是,在这种情况下,回调函数是空的。我必须添加回调以使线程正常工作,但我的应用程序的回调实际上没有发生任何事情。我目前也无法在我正在使用的计算机上编译,但我想知道不同之处在于您是否需要 pVoice->WaitForNotifyEvent(INFINITE) 某处?这是我看到的你的代码和我的代码之间唯一的大区别。
  • 我只在我注释掉的部分代码中使用了 pVoice->WaitForNotifyEvent(INFINITE)。如果我也注释掉该行,则没有区别。无论如何,谢谢。
猜你喜欢
  • 2011-03-19
  • 1970-01-01
  • 2011-08-11
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 2012-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多