如何获取Microsoft TTS语音的经过时间?
How to get the elapsed time of Microsoft TTS speech?
我现在用下面的函数来实现一个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;
}
我可以得到每个字被说出的经过时间吗?或者它是恒定的(如果设置了语速)?目的是想展示一些面部动画来配合演讲...
您不一定需要经过的时间;你可以使用 Viseme 事件来触发你的动画。
由于您使用的是 C++,因此请使用 ISpVoice::SetInterest to describe the set of events that you want, and one of the ISpNotifySource 方法(取决于您的外部代码在做什么)来获取传递给您的事件。
Microsoft 提供了详细的 workthrough 以防此草图没有帮助。
请注意,具体的 组 视位(以及视位映射到哪些值)取决于语言。对于美国英语,视位定义为 here。对于中文,从音位到语音位的映射没有公开定义。
另一方面,您可以使用发音事件作为触发器,而不必真正关心实际的发音值。
假设您的应用中某处有一个消息循环,您的代码将如下所示:
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 );
我现在用下面的函数来实现一个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;
}
我可以得到每个字被说出的经过时间吗?或者它是恒定的(如果设置了语速)?目的是想展示一些面部动画来配合演讲...
您不一定需要经过的时间;你可以使用 Viseme 事件来触发你的动画。
由于您使用的是 C++,因此请使用 ISpVoice::SetInterest to describe the set of events that you want, and one of the ISpNotifySource 方法(取决于您的外部代码在做什么)来获取传递给您的事件。
Microsoft 提供了详细的 workthrough 以防此草图没有帮助。
请注意,具体的 组 视位(以及视位映射到哪些值)取决于语言。对于美国英语,视位定义为 here。对于中文,从音位到语音位的映射没有公开定义。
另一方面,您可以使用发音事件作为触发器,而不必真正关心实际的发音值。
假设您的应用中某处有一个消息循环,您的代码将如下所示:
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 );