Я только недавно загрузил Visual Studio 2015 (сообщество), чтобы разрабатывать приложения с использованием Microsoft SAPI TTS. Я установил 5.1 SDK, а затем 5.4 SDK для речи и установил языки времени выполнения для 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
Программа компилируется без ошибок, но выдает ошибку 0xC0000005 (нарушение доступа к памяти) в последнем операторе возврата.
Я должен был изменить заголовочный файл <sphelper.h>
из-за устаревшего метода :: GetVersionExW () … мне удалось заставить его работать, используя методы из этой ссылки: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe . Чудом (и с небольшим изменением исходного кода системы, вероятно, плохой идеей), это сработало.
Я не знаю, почему программа выдает в самом конце, так как проблема должна быть в программе, обращающейся к токенам реестра. Я знаю, что обычно проблема заключается в указателях, так что мне нужно сделать, чтобы эта работа работала?
Обратите внимание, что я пытаюсь сделать cpVoice
Объект использовать польский токен, «Паулина». Есть ли способ как-нибудь вручную присвоить объекту значение токена реестра?
Вот как вы проходите через каждый из ваших установленных голосов. 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();
Других решений пока нет …