C++ Microsoft SAPI:如何将 Windows 文本转语音输出设置到内存缓冲区?

发布于 2024-08-31 10:57:08 字数 360 浏览 7 评论 0原文

我一直试图弄清楚如何使用 Windows SAPI 5.1 将文本“讲”到内存缓冲区中,但到目前为止没有成功,尽管看起来应该非常简单。

将合成语音流式传输到 .wav 文件的示例,但没有如何将其流式传输到内存缓冲区的示例。

最后,我需要以 16 kHz 16 位小端 PCM 格式将合成语音存储在 char* 数组中。目前,我创建一个临时 .wav 文件,将语音输出重定向到那里,然后读取它,但这似乎是一个相当愚蠢的解决方案。

有人知道该怎么做吗?

谢谢!

I have been trying to figure out how to "speak" a text into a memory buffer using Windows SAPI 5.1 but so far no success, even though it seems it should be quite simple.

There is an example of streaming the synthesized speech into a .wav file, but no examples of how to stream it to a memory buffer.

In the end I need to have the synthesized speech in a char* array in 16 kHz 16-bit little-endian PCM format. Currently I create a temp .wav file, redirect speech output there, then read it, but it seems to be a rather stupid solution.

Anyone knows how to do that?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

彩扇题诗 2024-09-07 10:57:10

查看 ISpStream::SetBaseStream。这里有一个小帮手:

inline HRESULT SPCreateStreamOnHGlobal(
                    HGLOBAL hGlobal,            //Memory handle for the stream object
                    BOOL fDeleteOnRelease,      //Whether to free memory when the object is released
                    const WAVEFORMATEX * pwfex, //WaveFormatEx for stream
                    ISpStream ** ppStream)      //Address of variable to receive ISpStream pointer
{
    HRESULT hr;
    IStream * pMemStream;
    *ppStream = NULL;
    hr = ::CreateStreamOnHGlobal(hGlobal, fDeleteOnRelease, &pMemStream);
    if (SUCCEEDED(hr))
    {
        hr = ::CoCreateInstance(CLSID_SpStream, NULL, CLSCTX_ALL, __uuidof(*ppStream), (void **)ppStream);
        if (SUCCEEDED(hr))
        {
            hr = (*ppStream)->SetBaseStream(pMemStream, SPDFID_WaveFormatEx, pwfex);
            if (FAILED(hr))
            {
                (*ppStream)->Release();
                *ppStream = NULL;
            }
        }
        pMemStream->Release();
    }
    return hr;
}

Look at ISpStream::SetBaseStream. Here's a little helper:

inline HRESULT SPCreateStreamOnHGlobal(
                    HGLOBAL hGlobal,            //Memory handle for the stream object
                    BOOL fDeleteOnRelease,      //Whether to free memory when the object is released
                    const WAVEFORMATEX * pwfex, //WaveFormatEx for stream
                    ISpStream ** ppStream)      //Address of variable to receive ISpStream pointer
{
    HRESULT hr;
    IStream * pMemStream;
    *ppStream = NULL;
    hr = ::CreateStreamOnHGlobal(hGlobal, fDeleteOnRelease, &pMemStream);
    if (SUCCEEDED(hr))
    {
        hr = ::CoCreateInstance(CLSID_SpStream, NULL, CLSCTX_ALL, __uuidof(*ppStream), (void **)ppStream);
        if (SUCCEEDED(hr))
        {
            hr = (*ppStream)->SetBaseStream(pMemStream, SPDFID_WaveFormatEx, pwfex);
            if (FAILED(hr))
            {
                (*ppStream)->Release();
                *ppStream = NULL;
            }
        }
        pMemStream->Release();
    }
    return hr;
}
暮光沉寂 2024-09-07 10:57:10

我使用 ISpStream 完成了它。使用 ispstream 的 Setbasestream 函数将其绑定到 istream,然后将 ispvoice 的输出设置到该 ispstream。

如果有人需要,这是我的工作解决方案:

https://github.com/itsyash/MS-SAPI -演示

I accomplished it using the ISpStream. Use Setbasestream function of the ispstream to bind it to an istream and then set the output of ispvoice to that ispstream.

Here is my working solution if anybody wants it :

https://github.com/itsyash/MS-SAPI-demo

请止步禁区 2024-09-07 10:57:10

您知道如何创建内存映射文件吗?您可以查看 ISpStream 是否会绑定到它。

Do you know how to create a memory-mapped file? You could see if the ISpStream will bind to it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文