SAPI - 微软Speech API

微软自Windows7开始就内置了SAPI,通过C编程可以快速地实现多国语TTS功能。整理记录以备查阅。

SAPI - 微软Speech API

1 概要

本文整理及引用自《中文信息处理实验教程》(主审:朱巧明 主编:朱晓旭 苏州大学出版社)

微软自Windows7开始就内置了SAPI,通过C编程可以快速地实现多国语TTS功能。

Speech API通过Windows Speech SDK提供,包含几类接口:Voice Commands API, Voice Dictation API, Voice Text API, Voice Telephone API, Audio Object API。语音合成使用的是Voice Text API中的函数接口。


2 SAPI主要函数接口

2.1 SetRate

  • 设置朗读速度,取值-10~10

2.2 GetRate

  • 获取朗读速度

2.3 SetVoice

  • 设置使用的语音库

2.4 GetVoice

  • 获取使用的语音库

2.5 Pause

  • 暂停朗读

2.6 Resume

  • 恢复朗读

2.7 SetVolume

  • 设置音量,范围0~100

2.8 GetVolume

  • 获取音量

2.9 SetSyncSpeakTimeout

  • 设置同步朗读超时时间(毫秒)

2.10 GetSyncSpeakTimeout

  • 获取同步朗读超时时间(毫秒)

3 编程

3.1 Speak函数原型

1
2
3
4
5
HRESULT Speak(
LPCWSTR *pwcs,
DWORD dwFlags,
ULONG *pulStreamNumber
)

3.2 案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "sapi.h"
#include "sphelper.h"

#pragma comment(lib, "sapi.lib") // 引用lib库

void main()
{
ISpVoice *pSpVoice; // 定义TTS引擎接口指针
::CoInitialize(NULL); // COM初始化

CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void **)&pSpVoice); // 获取ISpVoice接口指针

printf("Speak\n");
pSpVoice->SetVolume(100); // 设置音量(0~100)
pSpVoice->Speak(TEXT(L"新垣结衣"), // L作为字符串前缀,告知编译器使用等宽两个字节的Unicode字符集
SPF_ASYNC, // SND_SYNC 同步播放,在播放完后Speak才返回;另:SND_ASYNC/SPF_ASYNC 异步播放,开始播放时Speak立即返回。
NULL);

printf("Speak return.\n");
getchar();
pSpVoice->Release();
::CoUninitialize();
}
  • TEXT(L"新垣结衣") 提供的是一个WCHAR字符串。Speak函数原型中,LPCWSTR是typedef const WCHAR *LPCWSTR的类型定义结果。实质是WCHAR宽字符const字符串的指针。而L作为字符串前缀,作用就是告知编译器,使用等宽两字节的Unicode字符编码而非默认的ANSI编码。
  • 如果采用异步播放,则Speak函数会立即返回,同时开始播放,因此需要在主函数结束前添置一个getchar()避免主函数过早return,导致进程在尚未完成播放的情况下提前结束。
    • SPF_ASYNC是enum枚举类型元素,可读值为1,表示异步;
    • SPF_DEFAULT是enum枚举类型元素,可读值为0,表示同步;
    • SND_ASYNC是宏定义#define SND_ASYNC 0X0001,表示异步;
    • SND_SYNC是宏定义#define SND_ASYNC 0X0000,表示同步;

4 XML定制化朗读

通过XML标签,实现对TTS发音的控制,如:强调重读、整数朗读和逐个数字字符朗读的区分 等个性化朗读定制。

1
2
3
pSpVoice->Speak(TEXT(L"110"),	// 作为110整数朗读
SPF_DEFAULT, // 默认同步播放
NULL);
  • 整数朗读
1
2
3
pSpVoice->Speak(TEXT(L"<spell>110</spell>"),	// 作为1 1 0数字字符逐个朗读
SPF_DEFAULT|SPF_IS_XML, // 默认同步播放,并置SPF_IS_XML位(该位值为8)
NULL);
  • 逐个数字字符朗读

5 错误解决

5.1 C4996 'GetVersionExA' 被声明为已否决

在较高版本的Visual Studio中会遇到此问题,且阻止编译进行。

解决方法是,取消项目的SDL检查。

Project Properties > Configuration Properties > C/C++ > General > SDL checks(将其关闭)

关闭后,此问题仅作为warning提示。

5.2 无法将const char* 转换为LPCWSTR

见本文对L字符串前缀的介绍。