通过 ISpTTSEngine 与 ISpVoice 通话

问题描述 投票:0回答:2

我正在为 Microsoft Speech API (SAPI) 实现 ISpTTSEngine。我想要 这个声音就像典型的 TTS 声音一样进行报读。而不是写我的 自己的语音合成器,我想委托给内置的 ISpVoice。

我已经编写了足够的代码来听到文本发声,但它有一个重大缺陷 我无法解释:演讲直到我发言之后才开始

ISpTTSEngine:Speak
的实施已返回。在此期间 声音输出,我的
ISpTTSEngine:Speak
实现没有被调用,甚至 当使用 TTS 语音的软件发送请求时。

(上下文:我这个项目的目标是以编程方式观察其他片段的语音数据 的软件正在尝试发声。该部分似乎正在工作 有意。)

完整源码可用 在这里。 我会尝试 用最相关的部分进行总结。

我的

ISpTTSEngine
实现有一个名为
m_cpVoice

class ATL_NO_VTABLE CTTSEngObj :
    public CComObjectRootEx<CComMultiThreadModel>,
    public CComCoClass<CTTSEngObj, &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::wstring& text = textFrag->pTextStart; hr = m_cpVoice->Speak(text.substr(0, textFrag->ulTextLen).c_str(), dwSpeakFlags | SPF_ASYNC | SPF_PURGEBEFORESPEAK, 0);
如上所述,直到

ISpTTSEngine:Speak

之后才发出音频
返回。任意的 sleep 语句最清楚地证明了这一点。轮询
ISpVoice 的 
SpeakCompleteEvent
 句柄不可避免地会超时。删除
调用 
SPF_ASYNC
 时的 
ISpVoice::Speak
 标志会导致调用者
崩溃。

任何人都可以解释这种行为吗?或者提出一个改变,让我能够 观察后续的语音请求?

visual-c++ com text-to-speech sapi
2个回答
1
投票
SAPI 不希望以递归方式输入。考虑使用不同的 TTS 引擎(例如,WinRT

System.Media.SpeechSynthesis API)来进行实际合成。文本片段不会有任何嵌入的标记,所以这不是什么大问题。


0
投票
根据文档

https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee431810(v=vs.85)

如果您想异步发言,请将发言标志更改为 SPF_ASYNC,并在 ISpVoice::Speak() 等待发言过程完成后调用 ISpVoice::WaitUntilDone()。

© www.soinside.com 2019 - 2024. All rights reserved.