Разговор с помощью голоса ISP от isptsengine

#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»? Есть ли какая-нибудь другая документация, которая могла бы помочь?