我刚刚下载了Visual Studio 2015(社区),以便可以使用Microsoft SAPI TTS开发应用程序。我安装了5.1 SDK,然后安装了5.4 SDK for Speech,并安装了SAPI运行时语言。
到目前为止,我可以通过使用我希望SAPI通过直接参数和阅读SSML .XML文件来使用的短语来设法使该应用程序正常工作。 SAPI和SSML的所有功能均可正常工作,但与更改语音令牌无关。 (例如,<voice xml:lang="pl-PL">
... <voice required="Gender:Female">
...等)
我阅读了一些有关如何设置语言/语音令牌的论坛,并且尝试了以下代码:
if(FAILED(::CoInitialized(NULL))
return false;
HRESULT hr = S_OK;
CComPtr<ISpVoice> cpVoice;
CComPtr<ISpObjectTokenCategory> cpObjectCat;
CComPtr<ISpObjectToken> cpObjectToken;
CComPtr<IEnumSpObjectTokens> cpEnum;
hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&cpVoice);
if(SUCCEEDED(hr))
{
hr = SpGetDefaultTokenFromCategoryId(SPCAT_VOICES, &cpObjectToken);
}
if(SUCCEEDED(hr))
{
hr = SpGetCategoryFromId(SPCAT_VOICES, &cpObjectCat);
}
if(SUCCEEDED(hr))
{
hr = cpObjectCat->EnumTokens(NULL, NULL, &cpEnum);
}
if(SUCCEEDED(hr))
{
hr = cpEnum->Next(1, &cpObjectToken, NULL);
//Currently only concerned with making 1 token assign without
//throwing exception
}
if(SUCCEEDED(hr))
{
hr = cpVoice->SetVoice(cpObjectToken);
}
if(SUCCEEDED(hr))
{
hr = cpVoice->Speak(L"Hello There!", NULL, NULL);
}
//... lots of commented-out code here ...
cpVoice.Release();
::CoUninitialize();
return true; // <-- Throws Exception Here
该程序的生成没有错误,但在最终的return语句中引发了错误0xC0000005(内存访问冲突)。
由于方法:: GetVersionExW()的弃用,我确实不得不修改头文件
<sphelper.h>
…我设法使用此链接中的方法使它起作用:http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe。奇迹般地(并且对系统源代码进行了一些微调,这可能是一个坏主意),它奏效了。我不知道为什么程序最终会抛出异常,因为问题一定出在程序访问注册表令牌上。我知道通常问题出在指针上,所以要完成这项工作我需要做什么?
请注意,我试图使
cpVoice
对象使用波兰语标记“ Paulina”。有没有办法以某种方式手动将注册表令牌值分配给对象? 最佳答案
这是您浏览每个已安装声音的方式。 pszCurTokenId将是您所获得的语音的描述。您可能将其打印到控制台等上,或者仅查看调试器中的值。
您不必编辑sphelper.h即可正确选择声音。有时SAPI可能需要几秒钟来更改声音,所以如果感觉像挂了一样,请耐心等待。我只是在Windows 7上运行了以下代码,并验证了它适用于该平台。
HRESULT hr = S_OK;
CComPtr<ISpObjectToken> cpVoiceToken;
CComPtr<ISpVoice> cpVoice;
::CoInitialize(NULL);
if(SUCCEEDED(hr))
hr = cpVoice.CoCreateInstance(CLSID_SpVoice);
ULONG ulCount = 0;
CComPtr<IEnumSpObjectTokens> cpEnum;
if(SUCCEEDED(hr))
hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);
//Get the number of voices
if(SUCCEEDED(hr))
hr = cpEnum->GetCount(&ulCount);
for(ULONG i = 0; i < ulCount; ++i) {
CSpDynamicString* szDescription;
CComPtr<ISpObjectToken> cpTempVoiceToken;
cpEnum->Item(i, &cpTempVoiceToken);
WCHAR* pszCurTokenId = NULL;
SpGetDescription(cpTempVoiceToken, &pszCurTokenId);
cpVoice->SetVoice(cpTempVoiceToken);
cpVoice->Speak(L"This is a test phrase.", SPF_DEFAULT, NULL);
cpTempVoiceToken.Release();
}
cpVoice.Release();
cpEnum.Release();
::CoUninitialize();
关于c++ - 枚举 token 时,基于SAPI的应用程序抛出内存访问冲突,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35925377/