微软的提供的SAPI工具包,用于语音技术开发,提供包括语音识别和语音合成两方面的内容。我们可以通过其中Voice Text API完成从文字到语音的转换。
SAPI需要用到COM框架,在程序开始和结束的地方需要分别初始化和释放COM框架
TextSpeaker::TextSpeaker() {
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
......
}
TextSpeaker::~TextSpeaker() {
CoUninitialize();
}
可以通过SpEnumTokens接口,枚举指定的对象资源。能够查询出当前支持的人声以及可以输出的设备。
#include
#include
#pragma warning(push)
#pragma warning(disable : 4996)
#include
#pragma warning(pop)
static std::vector>> GetTokens(
const wchar_t* registryKey) {
std::vector>> ret;
CComPtr cpEnum;
if (!SUCCEEDED(SpEnumTokens(registryKey, nullptr, nullptr, &cpEnum))) {
return ret;
}
unsigned long count = 0;
if (!SUCCEEDED(cpEnum->GetCount(&count))) {
return ret;
}
for (size_t i = 0; i < count; ++i) {
CComPtr token;
if (!SUCCEEDED(cpEnum->Next(1, &token, nullptr))) {
return ret;
}
LPWSTR str = nullptr;
token->GetStringValue(nullptr, &str);
ret.push_back({ std::wstring{ str }, std::move(token) });
}
return ret;
}
// WIN10后新的资源注册表地址
static std::wstring NEW_WIN10_REG_KEY
= L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech_OneCore\\Voices";
// 获取系统语音资源
mVoices = GetTokens(SPCAT_VOICES);
{
// 合并WIN10后新的资源
std::vector>>
extraVoices = GetTokens(NEW_WIN10_REG_KEY.c_str());
mVoices.insert(mVoices.end(), extraVoices.begin(), extraVoices.end());
}
通过获取的语音资源,可以查看系统支持的语音资源。打印出来后结果如下:
for (const std::pair>& v : mVoices) {
wprintf(L"%zu : %s\n", i + 1, v.first.c_str());
}
1 : Microsoft Huihui Desktop - Chinese (Simplified)
2 : Microsoft Zira Desktop - English (United States)
3 : Microsoft Huihui - Chinese (Simplified, PRC)
4 : Microsoft Kangkang - Chinese (Simplified, PRC)
5 : Microsoft Yaoyao - Chinese (Simplified, PRC)
改变注册表位置,可以获取能够输出的音频设备
mDevices = GetTokens(SPCAT_AUDIOOUT);
for (const std::pair>& v : mDevices) {
wprintf(L"%zu : %s\n", i + 1, v.first.c_str());
}
1 : 扬声器 (Jabra EVOLVE 30 II)
2 : LEN P24i-10 (英特尔(R) 显示器音频)
3 : 扬声器 (Realtek(R) Audio)
通过ISpVoice接口可以设置和播放语音。
CComPtr voicePtr;
voicePtr.CoCreateInstance(CLSID_SpVoice);
// 设置音量,支持范围0~100
voicePtr->SetVolume(vol);
// 设置人声速度,支持-10~10
voicePtr->SetRate(speed);
// 设置播放的人声,可以使用GetTokens中获取的人声资源ISpObjectToken
// 如果不设置,则合成操作使用默认语音,在HKEY_CURRENT_USER\Software\Microsoft\Speech Server\v11.0\Voices\DefaultTokenId指定
voicePtr->SetVoice(selectedVoice);
// 设置播放的设备,可以使用GetTokens中获取的设备资源ISpObjectToken
// 如果不设置,则使用默认设备播放
voicePtr->SetOutput(device, TRUE);
完成ISpVoice的设置后,就可以开始播放文字
// 设置为异步播放,避免使用时阻塞
mDefaultSpeaker->Speak(sentence.c_str(), SPF_DEFAULT | SPF_ASYNC, nullptr);
// 停止播放,SPF_PURGEBEFORESPEAK可以舍弃队列中剩余要合成的数据
mDefaultSpeaker->Speak(L"", SPF_DEFAULT | SPF_PURGEBEFORESPEAK | SPF_ASYNC, nullptr);