前言
语音合成(Text To Speech,TTS)可以实现网页文章的阅读。通过它,我们可以不需要看文字,就可以听新闻、听小说。
目前国内的主流的语音合成解决方案无非是以下几种:
- 科大讯飞
- 云服务(阿里云、腾讯云……)
- 百度api
上述的方案,音质不错,语音包选择多。但是都有一定的免费配额或者语言的限制(如科大讯飞的试用语音包),没有完全免费的方案。
开源免费的方案的效果比较差,而且需要利用自己的服务器资源,需要考虑额外的成本。
那有没有什么免费可以使用的方案呢?还是有的!
这里就要搬出来 Web API 里面的 SpeechSynthesis。这个接口是浏览器原生支持的语音合成。
基本上现在主流的现代浏览器都支持这个接口。具体的浏览器支持情况可以查阅上面链接里的文档。
1、SpeechSynthesis技术简介
SpeechSynthesis是HTML5的一个新特性,基于SpeechSynthesis可以实现在客户浏览器端进行动态文本的语音合成播放。
在HTML5中和Web Speech相关的API实际上有两类,一类是“语音识别(Speech Recognition)”,另外一个就是“语音合成(Speech Synthesis)”,实际上指的分别是“语音转文字”,和“文字变语音”。
文章介绍的就是“语音合成-文字变语音”。为什么称为“合成”呢?比方说你Siri发音“你好,世界!” 实际上是把“你”、“好”、“世”、“界”这4个字的读音给合并在一起,因此,称为“语音合成”。
技术参考api-MDN
mdn英文文档:MDN Web Docs
mdn中文文档:Web 开发者指南 | MDN
1.1 SpeechSynthesis 的技术类方法
1.2 SpeechSyntehesisUtteranc属性
这个类主要用于控制合成声音的属性配置,比如主要内容,语音模板,语速等等,通过这个核心类控制。它的属性信息如下:
序号 | 参数 | 解释 |
1 | text | 要合成的文字内容,字符串 |
2 | lang | 使用的语言,字符串, 例如:"zh-cn" |
3 | voiceURI | 指定希望使用的声音和服务,字符串。 |
4 | volume | 声音的音量,区间范围是0到1,默认是1 |
5 | rate | 语速,数值,默认值是1,范围是0.1到10,表示语速的倍数,例如2表示正常语速的两倍。 |
6 | pitch | 表示说话的音高,数值,范围从0(最小)到2(最大)。默认值为1 |
1.3 SpeechSyntehesisUtteranc核心方法
如下表所示:
序号 | 方法名 | 说明 |
1 | onstart | 语音合成开始时候的回调。 |
2 | onpause | 语音合成暂停时候的回调 |
3 | onresume | 语音合成重新开始时候的回调 |
4 | onend | 语音合成结束时候的回调 |
5 | onmark | Fired when the spoken utterance reaches a named SSML "mark" tag. |
1.4 speechSynthesis对象
是实际调用SpeechSynthesisUtterance对象进行合成播报的。
他的属性和方法如下两个表格描述。
序号 | 名称 | 描述 |
1 | paused | 当SpeechSynthesis 处于暂停状态时, Boolean (en-US) 值返回 true |
2 | pending | 当语音播放队列到目前为止保持没有说完的语音时, Boolean (en-US) 值返回 true 。 |
3 | speaking | 当语音谈话正在进行的时候,即使SpeechSynthesis处于暂停状态, Boolean (en-US) 返回 true 。 |
1.5 语音包
简单来说,SpeechSynthesis 的语音包来自两大地方——操作系统自带和浏览器自带。
所以我们才发现 window.speechSynthesis.getVoices() 拿到的语音包存在一部分是 Apple 提供的,一部分是 Google 提供的。
对于语音包的一些技术解释,具体的文档可以查看 MDN。
以 macOS 下的 Google Chrome 为例,
通过 window.speechSynthesis.getVoices() 可以获取全部语音包,下面是一部分的输出:
[{
"voiceURI": "Ting-Ting",
"name": "Ting-Ting",
"lang": "zh-CN",
"localService": true,
"default": true
}, {
"voiceURI": "Google 普通话(中国大陆)",
"name": "Google 普通话(中国大陆)",
"lang": "zh-CN",
"localService": false,
"default": false
}]
上述数组是 SpeechSynthesisVoice 的实例数组,SpeechSynthesisVoice 的参数如下:
voiceURI:语音合成服务的URL
name:语音包名称
lang:语言(符合BCP 47规范)
localService:是本地语言包(离线)还是远程语言包(网络)
default:是否为默认的语音包
通过观察,可以发现
Google Chrome 在 macOS 下可以使用的语音包有macOS 自带的本地语音包和谷歌提供的在线语音包。
如苹果的「Ting-Ting」和谷歌的「Google 普通话(中国大陆)」。
在构建 SpeechSynthesisUtterance 的时候,传入支持的语音包的 lang 和 voice (对应 SpeechSynthesisVoice 的 name)就可以选择语音包了。
通过这个接口,我们可以给使用 Google Chrome 的浏览器用户提供来自谷歌的语音合成功能。
探索 SpeechSynthesis 的原理下面,
我们通过 Chromium 的源代码探索 Google Chrome 的 SpeechSynthesis 是怎么实现的。
Chromium 里面的 SpeechSynthesis 类都是在 speech 模块 中实现的。
其中,该模块包含 语音识别(speechRecognizer)和 语音合成 (SpeechSynthesis)两大功能的实现。
看语音合成的头文件就大概知道有哪些功能:
speech_synthesis_impl.h: SpeechSynthesis 实现的后端,分派任务给 TTS Conreoller
tts_controller_impl.h: 语音合成的控制器,集成了获取语音包、设置引擎、播放、暂停等功能
tts_platform_impl.h: 管理平台相关的语音包,具体的实现在
语音包怎么来的?
我们可以先看 tts_controller_impl 里面的 GetVoices 实现:
void TtsControllerImpl::GetVoices
(BrowserContext* browser_context,std::vector<VoiceData>* out_voices) {
TtsPlatform* tts_platform = GetTtsPlatform(); // 获取操作系统相关的 TTS
if (tts_platform) { // 当前平台存在 TTS
// Ensure we have all built-in voices loaded. This is a no-op if already
// loaded.
tts_platform->LoadBuiltInTtsEngine(browser_context); // 加载本地的 TTS
if (tts_platform->PlatformImplAvailable())
tts_platform->GetVoices(out_voices);
}
if (browser_context) {
TtsControllerDelegate* delegate = GetTtsControllerDelegate();
if (delegate && delegate->GetTtsEngineDelegate()) // 浏览器自带的 TTS
delegate->GetTtsEngineDelegate()->GetVoices(browser_context, out_voices);
}
}
简单来说,SpeechSynthesis 的语音包来自两大地方——操作系统自带和浏览器自带。所以我们才发现 window.speechSynthesis.getVoices() 拿到的语音包存在一部分是 Apple 提供的,一部分是 Google 提供的。
这个技术是最常用在谷歌浏览器,H5的语音合成:Speech Synthesis ,基本上兼容大部分的主流浏览器,但是完全不兼容IE,需要设置IE需要写一些兼容的语句。Microsoft Edge浏览器的支持较好,支持的语言包比较丰富。
2、项目界面截图
3、封装class类方法(实例化调用)
// 语音播报的函数
export default class SpeakVoice {
constructor(vm, config) {
let that = this
that._vm = vm
that.config = {
text: '春江潮水连海平,海上明月共潮生。滟滟随波千万里,何处春江无月明!',
volume: 1, // 声音音量:1,范围从0到1
rate: 1, // 设置语速:1,范围从0到100
labelData:{
name:''
},
...config
}
that.synth = window.speechSynthesis // 启用文本
that.instance = new SpeechSynthesisUtterance()
that.instance.lang = "zh-CN"; // 使用的语言:中文
that.status = '初始化'
that.isload = false;
that.initVoice();
}
// 初始化
initVoice(){
let that = this
if(that.isload){
return false
}else{
that.isload = true
that.instance.text = that.config.text; // 文字内容: 测试内容
that.instance.volume = that.config.volume;
that.instance.rate = that.config.rate;
that.instance.onstart = e => {
that.status = '开始播放'
}
that.instance.onend = e => {
that.status = '结束播放'
}
that.instance.onpause = e => {
this.status = "暂停播放"
}
}
/*let speech = that.getSpeechVoices();
speech.then((voices) => {
voices = voices.filter(item => (item.lang.indexOf('zh-') > -1 && item.localService));
if (voices.length === 0) {
console.error('没有可用的中文语音!'); //中文包可以调试多种语言包切换
}else {
//实例化播报内容
that.instance.lang = "zh-CN"; // 使用的语言:中文
that.instance.text = '测试内容'; // 文字内容: 测试内容
that.instance.volume = 1
that.instance.rate = 1
that.instance.voice = voices[0]
that.synth.speak(that.instance); // 播放
}
});*/
}
// 语音开始
handleSpeak() {
this.synth.speak(this.instance); // 播放
}
// 语音队列重播
handleReply() {
this.handleCancel();
this.handleSpeak()
}
// 语音队列删除 , 删除队列中所有的语音.如果正在播放,则直接停止
handleCancel() {
this.synth.cancel(this.instance);
}
// 语音暂停, 暂停语音该次语音播放
handleStop() {
this.synth.pause(this.instance);
}
// 恢复暂停的语音
handleResume(){
this.synth.resume(this.instance) //恢复暂停的语音
}
//获取语言包数据, 这个接口需要一点时间,改成异步的
getSpeechVoices() {
let that = this
return new Promise(function (resolve, reject) {
let id;
id = setInterval(() => {
if (that.synth.getVoices().length !== 0) {
resolve(that.synth.getVoices());
clearInterval(id);
}
}, 10);
}
)
}
destory () {
this.handleCancel()
}
}
4、实例化父组件
<i title="播放" class="el-icon-microphone" @click="actMicroFun"></i>
import SpeakVoice from './speak-voice.js'
actMicroFun () {
let speakVoice = new SpeakVoice();
speakVoice.handleReply();
}
5、关于语音api解析
属性设置
SpeechSynthesisUtterance.lang 获取并设置话语的语言
SpeechSynthesisUtterance.pitch 获取并设置话语的音调(值越大越尖锐,越低越低沉)
SpeechSynthesisUtterance.rate 获取并设置说话的速度(值越大语速越快,越小语速越慢)
SpeechSynthesisUtterance.text 获取并设置说话时的文本
SpeechSynthesisUtterance.voice 获取并设置说话的声音
SpeechSynthesisUtterance.volume 获取并设置说话的音量
函数设置
speechSynthesis.speak() 将对应的实例添加到语音队列中
speechSynthesis.cancel() 删除队列中所有的语音.如果正在播放,则直接停止
speechSynthesis.pause() 暂停语音
speechSynthesis.resume() 恢复暂停的语音
speechSynthesis.getVoices() 获取支持的语言数组.