首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何更改声音的音频格式?

如何更改声音的音频格式?
EN

Stack Overflow用户
提问于 2014-04-09 21:13:57
回答 1查看 725关注 0票数 1

我在Windows上乱搞SAPI,我注意到声音的声音质量很低。通过比较简单测试程序的音频质量和eSpeak提供的各种质量,我得出的结论是,默认质量在16kHz 16 Bit Mono附近。

简易SAPI测试程序

代码语言:javascript
复制
#include <string>
#include <iostream>

#include <Windows.h>
#include <sapi.h>


#define _CHECK_HR(hr, debug_str)   \
    if(FAILED(hr)) {    \
        std::cout << debug_str << ": " << std::hex << "0x" << hr << std::dec << std::endl;   \
        goto check_failure;   \
    }

#define CHECK_HR(expr, debug_str)  \
    _CHECK_HR(expr, debug_str);

#define SAFE_RELEASE(obj)   \
    if(obj != NULL) {   \
        obj->Release(); \
        obj = NULL; \
    }


int main()
{
    ISpVoice* voice = NULL;

    CHECK_HR(CoInitialize(NULL), "CoInitialize");

    CHECK_HR(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (LPVOID*)&voice), "voice = CoCreateInstance");
    CHECK_HR(voice->Speak(TEXT("This is a simple test."), 0, NULL), "voice->Speak");

    std::cout << "No errors!" << std::endl;

check_failure:
    SAFE_RELEASE(voice);
    CoUninitialize();
}

当然,我已经尝试过咨询SAPI文档,但还没有找到如何更改格式。ISpVoice没有设置格式的方法,但它有一个SetOuput方法,它需要:

输出音频设备的流、音频设备或对象令牌。

我的下一步是创建一个IAudioClient,其格式由SpConvertStreamFormatEnum提供,并将其IAudioRenderClient设置为语音输出。由于无法初始化IAudioClient,尝试失败。

尝试将音频流设置为语音输出

代码语言:javascript
复制
#include <string>
#include <iostream>

#include <Windows.h>
#include <Mmdeviceapi.h>
#include <Audioclient.h>
#include <audiopolicy.h>
#include <sapi.h>
#include <sphelper.h>


#define _CHECK_HR(hr, debug_str)   \
    if(FAILED(hr)) {    \
        std::cout << debug_str << ": " << std::hex << "0x" << hr << std::dec << std::endl;   \
        goto check_failure;   \
    }

#define CHECK_HR(expr, debug_str)  \
    _CHECK_HR(expr, debug_str);

#define SAFE_RELEASE(obj)   \
    if(obj != NULL) {   \
        obj->Release(); \
        obj = NULL; \
    }

#define SAFE_FREE(obj)   \
    if(obj != NULL) {   \
        CoTaskMemFree(obj); \
        obj = NULL; \
    }


int main()
{
    ISpVoice* voice = NULL;
    IMMDeviceEnumerator* device_enumerator = NULL;
    IMMDevice* audio_device = NULL;
    WAVEFORMATEX *audio_format = NULL;
    GUID format_guid;
    IAudioClient* audio_client = NULL;
    IAudioRenderClient* audio_render_client = NULL;

    CHECK_HR(CoInitialize(NULL), "CoInitialize");

    CHECK_HR(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (LPVOID*)&voice), "CoCreateInstance");

    CHECK_HR(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), reinterpret_cast<void**>(&device_enumerator)), "CoCreateInstance");
    CHECK_HR(device_enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &audio_device), "device_enumerator->GetDefaultAudioEndpoint");

    CHECK_HR(audio_device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, reinterpret_cast<void**>(&audio_client)), "audio_device->Activate");
    CHECK_HR(SpConvertStreamFormatEnum(SPSF_48kHz16BitStereo, &format_guid, &audio_format), "SpConvertStreamFormatEnum");
    CHECK_HR(audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE, 0, 0, audio_format, NULL), "audio_client->Initialize");
    CHECK_HR(audio_client->Start(), "audio_client->Start");
    CHECK_HR(audio_client->GetService(__uuidof(IAudioRenderClient), reinterpret_cast<void**>(&audio_render_client)), "audio_client->GetService");

    CHECK_HR(voice->SetOutput(audio_render_client, FALSE), "voice->SetOutput");
    CHECK_HR(voice->Speak(TEXT("This is a test."), 0, NULL), "voice->Speak");

    std::cout << "No errors!" << std::endl;

check_failure:
    SAFE_RELEASE(device_enumerator);
    SAFE_RELEASE(audio_device);
    SAFE_FREE(audio_format);
    SAFE_RELEASE(audio_client);
    SAFE_RELEASE(audio_render_client);
    CoUninitialize();
}

除此之外,我还仔细研究了SAPI音频接口,找到了许多其他接口和实现,这些接口和实现似乎对这项任务没有什么特别的用处。我觉得我在这里绕圈跑。

问题:如何像eSpeak的TTSApp那样更改声音的音频格式?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-04-09 22:19:25

尝试:

代码语言:javascript
复制
ATL::CComPtr<ISpVoice> voice;
voice.CoCreateInstance(CLSID_SpVoice);

CSpStreamFormat format;
format.AssignFormat(SPSF_44kHz16BitMono);

ATL::CComPtr<ISpAudio> audio;
SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOOUT, &audio);
audio->SetFormat(format.FormatId(), format.WaveFormatExPtr());

voice->SetOutput(audio, FALSE);

注意:这不包括任何错误处理,所以您的代码需要检查HRESULT返回代码和对象/指针的有效性。

还请注意,eS匹克的本地输出格式是16位220‘s单频。

对于C版本,您需要自己处理COM对象的生存期,并查看CSpStreamFormatAssignFormatFormatIdWaveFormatExPtr方法中所做的事情。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22974076

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档