本文最后更新于2021年2月20日,已超过 1 年没更新!内容可能已失效,请自行测试,失效请评论区反馈,谢谢啦~

前言

这是一个实验API,下面是来自MDN的兼容性表格,请注意,语音识别和语音合成兼容性不同,请注意区分.

MDN

语音合成

我们也看到了,语音合成浏览器支持的多一些,所以我们先学习语音合成.在我的随机抽号中,也使用了此API,具体效果如下(使用edge88):

我们首先要了解一个window.speechSynthesis,它是一个只读对象,返回一个SpeechSynthesis对象,该对象是使用Web Speech API语音合成功能的入口点.它有3个只读属性:

SpeechSynthesis.paused 只读
SpeechSynthesis 处于暂停状态时, Boolean 值返回 true
SpeechSynthesis.pending 只读
当语音播放队列到目前为止保持没有说完的语音时, Boolean 值返回 true
SpeechSynthesis.speaking 只读
当语音谈话正在进行的时候,即使SpeechSynthesis处于暂停状态, Boolean 返回 true

然后我们需要新建一个SpeechSynthesisUtterance对象:

tts = new SpeechSynthesisUtterance(str);

str是要转换的文本,最后,直接speak就是一个初级的tts了:

var say = window.speechSynthesis; 
var tts = new SpeechSynthesisUtterance(str);
say.speak(tts);

接下来,就是优化加功能了.

首先,刚才三个SpeechSynthesis的只读属性可以做判断,比如不允许播放之类(return),然后,还有下面可以设置:

  • volume – 声音的音量,区间范围是01,默认是1
  • rate – 语速,数值,默认值是1,范围是0.110,表示语速的倍数,例如2表示正常语速的两倍。
  • pitch – 表示说话的音高,数值,范围从0(最小)到2(最大)。默认值为1

都是在SpeechSynthesisUtterance操作的.最后,就是声音了.

首先,window.speechSynthesis.getVoices()是获取浏览器支持的语音列表,如在edge中,有以下内容:

所以,我们可以先新建一个<select>,然后设置idTTSlist,随后,var TTSlist = document.getElementById('TTSlist')方便使用.目前代码为:

<html>
<body>
<select id="TTSlist"></select>
<script>
var TTSlist = document.getElementById('TTSlist')
var say = window.speechSynthesis; 
function ttsReady(){
	voices = say.getVoices();
	
}
ttsReady();
if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = ttsReady;
}

var tts = new SpeechSynthesisUtterance('hello javascript');
say.speak(tts);
</script>
</body>
</html>

因为后面可能还会执行这个函数,所以我们还需要TTSlist.innerHTML = '';,接下来就是将刚刚获取到的列表输出即可

for(i = 0; i < voices.length ; i++) {
    var option = document.createElement('option');
    option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
    option.setAttribute('data-lang', voices[i].lang);
    option.setAttribute('data-name', voices[i].name);
    TTSlist.appendChild(option);
	}

封装进函数ttsReady,然后调用一次.但是不知道为什么会在edge上出错,所以还需一个保险:

if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = ttsReady;
}

因为有一些浏览器不支持speechSynthesis.onvoiceschanged,所以我们需要判断一次.他现在应该是这样的:

我们不难发现,有两个onlinezh-CN跑到了最后,所以我们需要提前.找到刚才的voices = say.getVoices(),改成:

voices = say.getVoices().sort(function (a, b) {
      const aname = a.lang.toUpperCase(), bname = b.lang.toUpperCase();
	  if(aname == 'ZH-CN' && bname != 'ZH-CN') return -1;
	  else if(aname != 'ZH-CN' && bname == 'ZH-CN') return 1;
	  else if(aname == 'ZH-CN' && bname == 'ZH-CN') return 0;
      else if ( aname < bname ) return -1;
      else if ( aname == bname ) return 0;
      else return +1;
  });

这下就可以了,接下来,就是把选择的语音应用.核心代码如下:

voice = TTSlist.selectedOptions[0].getAttribute('data-name');
for(i = 0; i < voices.length ; i++) {
      if(voices[i].name === voice) {
        tts.voice = voices[i];
	console.log(voices[i])
        break;
      }
    }

最后为了方便大家,我把整个代码贴在这里(请不要什么都不看直接无脑抄,有问题随时反馈,音高等自己设置):

<html>
<body>
<select id="TTSlist"></select>
<script>
var TTSlist = document.getElementById('TTSlist')
var say = window.speechSynthesis; 
function ttsReady(){
	voices = say.getVoices().sort(function (a, b) {
      const aname = a.lang.toUpperCase(), bname = b.lang.toUpperCase();
	  if(aname == 'ZH-CN' && bname != 'ZH-CN') return -1;
	  else if(aname != 'ZH-CN' && bname == 'ZH-CN') return 1;
	  else if(aname == 'ZH-CN' && bname == 'ZH-CN') return 0;
      else if ( aname < bname ) return -1;
      else if ( aname == bname ) return 0;
      else return +1;
  });
	for(i = 0; i < voices.length ; i++) {
    var option = document.createElement('option');
    option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
    option.setAttribute('data-lang', voices[i].lang);
    option.setAttribute('data-name', voices[i].name);
    TTSlist.appendChild(option);
	}
}
ttsReady();
if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = ttsReady;
}

function testTTS(str) {
	voice = TTSlist.selectedOptions[0].getAttribute('data-name');
	if(str == '')	{console.log('string is empty!');return;}
	if(say.speaking) {
		console.error('voice is speaking!');
		return;
	}
	tts = new SpeechSynthesisUtterance(str);
	for(i = 0; i < voices.length ; i++) {
      if(voices[i].name === voice) {
        tts.voice = voices[i];
		console.log(voices[i])
        break;
      }
    }
	say.speak(tts);
	
}
</script>
</body>
</html>

语音识别下次写吧.