#visual-c #com #text-to-speech #sapi
Вопрос:
Я внедряю ISpTTSEngine для Microsoft Speech API (SAPI). Я бы хотел, чтобы этот голос объявлял так же, как обычный голос TTS. Вместо того, чтобы писать свой собственный синтезатор речи, я хотел бы делегировать его встроенному ISpVoice.
Я написал достаточно кода, чтобы слышать озвученный текст, но у него есть серьезный недостаток, который я не смог объяснить: речь не начинается до тех пор, пока моя реализация ISpTTSEngine:Speak
не вернется. В течение всего времени звукового вывода моя реализация ISpTTSEngine:Speak
не вызывается, даже когда программное обеспечение, использующее голос TTS, отправляет запросы.
(Для контекста: моя цель в этом проекте-программно наблюдать за речевыми данными, которые другие части программного обеспечения пытаются озвучить. Эта часть, похоже, работает так, как задумывалось.)
Полный источник доступен здесь. Я постараюсь подвести итог с наиболее релевантными частями.
В моей реализации ISpTTSEngine
есть частный участник с именем m_cpVoice
:
class ATL_NO_VTABLE CTTSEngObj :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CTTSEngObj, amp;CLSID_SampleTTSEngine>,
public ISpTTSEngine,
public ISpObjectWithToken
{
// ...
private:
CComPtr<ISpVoice> m_cpVoice;
И он инициализируется в FinalConstruct
методе:
HRESULT CTTSEngObj::FinalConstruct()
{
HRESULT hr = S_OK;
// ...
hr = m_cpVoice.CoCreateInstance(CLSID_SpVoice);
Моя реализация ISpTTSEngine:Speak
перебирает текстовые фрагменты, которые она получает
, и передает текстовые данные ISpVoice::Speak
методу:
STDMETHODIMP CTTSEngObj::Speak(DWORD dwSpeakFlags,
REFGUID rguidFormatId,
const WAVEFORMATEX* pWaveFormatEx,
const SPVTEXTFRAG* pTextFragList,
ISpTTSEngineSite* pOutputSite)
{
// ...
for (const SPVTEXTFRAG* textFrag = pTextFragList; textFrag != NULL; textFrag = textFrag->pNext)
{
// ...
const std::wstringamp; text = textFrag->pTextStart;
hr = m_cpVoice->Speak(text.substr(0, textFrag->ulTextLen).c_str(), dwSpeakFlags | SPF_ASYNC | SPF_PURGEBEFORESPEAK, 0);
Как упоминалось выше, звук не будет издаваться до тех пор, пока ISpTTSEngine:Speak
ВОЗВРАТ. Произвольное утверждение сна демонстрирует это наиболее ясно. Опрос
SpeakCompleteEvent
дескриптора ISpVoice неизбежно заканчивается. Удаление
SPF_ASYNC
флага из вызова ISpVoice::Speak
вызывает сбой вызывающего абонента.
Кто-нибудь может объяснить такое поведение? Или предложите изменение, которое позволило бы мне наблюдать за последующими речевыми запросами?
Ответ №1:
SAPI не ожидает, что его будут вводить рекурсивно. Рассмотрите возможность использования другого движка TTS (например, системы WinRT.Медиафайлы.API-интерфейсы SpeechSynthesis) для выполнения фактического синтеза. Текстовые фрагменты не будут иметь встроенной разметки, так что это не будет иметь большого значения.
Комментарии:
1. Я пытаюсь лучше понять платформу, чтобы самостоятельно распознавать подобные ограничения. Не могли бы вы порекомендовать более внимательно ознакомиться с » Руководством по переносу поставщика движка TTS от Microsoft»? Есть ли какая-нибудь другая документация, которая могла бы помочь?