如何获得Microsoft TTS演讲的经过的时间

How to get the elapsed time of Microsoft TTS speech?

本文关键字:经过 时间 何获得 Microsoft TTS      更新时间:2023-10-16

我现在使用以下函数实现TTS服务。

int tts(LPCWSTR text){
    ::CoInitialize(NULL);         
    CLSID CLSID_SpVoice;
    CLSIDFromProgID(_T("SAPI.SpVoice"), &CLSID_SpVoice);
    ISpVoice *pSpVoice = NULL;
    IEnumSpObjectTokens *pSpEnumTokens = NULL;
    if (FAILED(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void**)&pSpVoice))){
        return -1;
    }
    if (SUCCEEDED(SpEnumTokens(SPCAT_VOICES, NULL, NULL, &pSpEnumTokens))){
        ISpObjectToken *pSpToken = NULL;
        SpFindBestToken(SPCAT_VOICES, L"Gender=Male", L"Name=Microsoft Simplified Chinese", &pSpToken);
        pSpVoice->SetVoice(pSpToken);
        pSpVoice->Speak(text, SPF_DEFAULT, NULL);
        pSpEnumTokens->Release();        
    }
    pSpVoice->Release();
    ::CoUninitialize();
    return 0;
}

我有可能让每个角色所经过的时间流逝吗?还是恒定(如果设定了语音率)?目的是我想展示一些面部动画以匹配演讲...

您不一定需要经过的时间;您可以使用视觉事件触发动画。

由于您使用的是C ,请使用ISPVOICE :: SETInterest描述所需的事件集,以及ISPnotifYsource方法之一(取决于您的外部代码所做的)来获取事件。

Microsoft有一个详细的工作,以防此草图没有帮助。

请注意,Visemes的精确 set (以及哪些Visemes映射到哪些值)是依赖语言的。对于我们英语,在这里定义了观众。对于中文,从音素到Viseme的映射尚未公开定义。

另一方面,您可以使用触发器的Vibeme事件,并且并不真正在乎实际的Viseme values

假设您在应用程序中的某个地方有消息循环,则您的代码看起来像:

CLSID CLSID_SpVoice;
CLSIDFromProgID(_T("SAPI.SpVoice"), &CLSID_SpVoice);
ISpVoice *pSpVoice = NULL;
IEnumSpObjectTokens *pSpEnumTokens = NULL;
ULONGLONG  ullMyEvents = SPFEI(SPEI_VISEME);
if (FAILED(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void**)&pSpVoice))){
    return -1;
}
if (SUCCEEDED(SpEnumTokens(SPCAT_VOICES, NULL, NULL, &pSpEnumTokens))){
    ISpObjectToken *pSpToken = NULL;
    SpFindBestToken(SPCAT_VOICES, L"Gender=Male", L"Name=Microsoft Simplified Chinese", &pSpToken);
    pSpVoice->SetVoice(pSpToken);
    // Set type of events the client is interested in.
    pSpVoice->SetInterest(ullMyEvents, ullMyEvents);
    // deliver a WM_APP message when a SAPI event arrives.   
    // Use a different message ID for real code.
    pSpVoice->SetNotifyWindowMessage(hWnd, WM_APP, 0, 0);
    pSpVoice->Speak(text, SPF_DEFAULT, NULL);
    pSpEnumTokens->Release();        
}
pSpVoice->Release();

以后,在您的消息循环中,您需要处理SAPI消息:

  case WM_APP:
     SPEVENT eventItem;
     memset( &eventItem;, 0,sizeof(SPEVENT));
     while( pVoice->GetEvents(1, &eventItem;, NULL ) == S_OK )
     {
       switch(eventItem.eEventId )
       {
          case SPEI_VISEME:
             .
             .
             .
             break;
          default:
             break;
       }
     SpClearEvent( eventItem );