通过浏览器的语音合成音频并播放

一、关于SpeechSynthesis

1、SpeechSynthesis简介

SpeechSynthesis是HTML5的一个新特性,基于SpeechSynthesis可以实现在客户浏览器端进行动态文本的语音合成播放。在HTML5中和Web Speech相关的API实际上有两类,一类是“语音识别(Speech Recognition)”,另外一个就是“语音合成(Speech Synthesis)”,这两个名词听上去很高大上,实际上指的分别是“语音转文字”,和“文字变语音”。而本文要介绍的就是这里的“语音合成-文字变语音”。为什么称为“合成”呢?比方说你Siri发音“你好,世界!” 实际上是把“你”、“好”、“世”、“界”这4个字的读音给合并在一起,因此,称为“语音合成”。

2、SpeechSynthesis的核心类

2023032710520331.jpg

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 onstart 语音合成开始时候的回调。
2 onpause 语音合成暂停时候的回调
3 onresume 语音合成重新开始时候的回调
4 onend 语音合成结束时候的回调
5 onmark Fired when the spoken utterance reaches a named SSML "mark" tag.

speechSynthesis是实际调用SpeechSynthesisUtterance对象进行合成播报的。他的属性和方法如下两个表格描述。

序号 名称 描述
1 paused 当SpeechSynthesis 处于暂停状态时, Boolean (en-US) 值返回 true
2 pending 当语音播放队列到目前为止保持没有说完的语音时, Boolean (en-US) 值返回 true 。
3 speaking 当语音谈话正在进行的时候,即使SpeechSynthesis处于暂停状态, Boolean (en-US) 返回 true 。二、SpeechSynthesi文本实例合成

二、SpeechSynthesi文本实例合成

QQ截图20240120135229.jpg

1、完整示例代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>SpeechSynthesisUtterance</title>
</head>
<body>
	<div style="text-align: center;margin-top:50px">
		<textarea style="height: 100px; width:300px;" id="text">这段文字将通过浏览器的语音合成API来播放</textarea>
		<br/>
		<select name="voice" id="voices">
		   <option value="">选择语音</option>
		</select>

		<label>速度:</label>
		<input name="rate" type="range" min="0" max="3" value="1" step="0.1">
		<label>音高:</label>
		<input name="pitch" type="range" min="0" max="2" value="1" step="0.1">

		<div style="margin-top:30px">
			<button id="playBtn">播放</button>
			<button id="pauseBtn">暂停</button>
			<button id="resumeBtn">继续</button>
			<button id="cancelBtn">取消</button>
			<button id="statusBtn">获取状态</button>
		</div>
	</div>

</body>
<script>
	const speech = window.speechSynthesis
	const text = document.getElementById("text");
	const playBtn = document.getElementById("playBtn");
	const pauseBtn = document.getElementById("pauseBtn");
	const resumeBtn = document.getElementById("resumeBtn");
	const cancelBtn = document.getElementById("cancelBtn");
	const statusBtn = document.getElementById("statusBtn");

	const voicesDropdown = document.querySelector('[name="voice"]')
	const rate = document.querySelector('[name="rate"]')
	const pitch = document.querySelector('[name="pitch"]')

	let ssu = null;
	playBtn.addEventListener("click", () => {
		const { pending, speaking, paused } = speech
		if (pending) { // 判断当前播放状态
			console.log(`当前播放列表${pending ? "有" : "没有"}未播完的语音`);
			return false;
		}
		// 创建语音
		if (!ssu) {
			ssu = new SpeechSynthesisUtterance();
			ssu.text = text.value;
			ssu.lang = voicesDropdown.selectedOptions[0].value // 设置播放语言(默认zh-CN)
			ssu.pitch = pitch.value // 获取并设置话语的音调(0-2 默认1,值越大越尖锐,越低越低沉)
			ssu.rate = rate.value // 获取并设置说话的速度(0.1-10 默认1,值越大语速越快,越小语速越慢)
			ssu.volume = 100 // 获取并设置说话的音量
			let count = 0
			console.log(ssu);
			speech.speak(ssu);

			ssu.addEventListener("start", () => {
				console.log("开始播放语音");
			});
			ssu.addEventListener("end", () => {
				console.log("播放语音结束");
				count ++
				setTimeout(function() { // 增加控制播放次数
				    count < 3 && speech.speak(ssu);
			    },  1000);
			});
			ssu.addEventListener("boundary", (e) => {
				// console.log("当前遇到单词或句子", e.name);
			});
			ssu.addEventListener("pause", () => {
				console.log("暂停播放语音");
			});
			ssu.addEventListener("resume", () => {
				console.log("继续播放语音");
			});
			ssu.addEventListener("error", (e) => {
				console.log("发生错误", e.error);
			});
		}
	});
	pauseBtn.addEventListener("click", () => {
		speech.pause();
	});
	resumeBtn.addEventListener("click", () => {
		speech.resume();
	});
	cancelBtn.addEventListener("click", () => {
		speech.cancel();
	});
	statusBtn.addEventListener("click", () => {
		const { pending, speaking, paused } = speech
		console.log(pending, speaking, paused);
		console.log(`当前播放列表${pending ? "有" : "没有"}未播完的语音`);
		console.log(`当前播放列表${speaking ? "存在" : "不存在"}语音`);
		console.log(`当前${paused ? "是" : "不是"}暂停播放状态`);
	});

	let voices = []
	speech.addEventListener('voiceschanged',getSupportVoices)

	function getSupportVoices() {
		voices = speech.getVoices()
		voices.forEach(e => {
			const option = document.createElement('option')
			option.value = e.lang
			option.text = e.name
			if (e.lang == 'zh-CN') {
				option.selected = true;
			}
			voicesDropdown.appendChild(option)
		})
	}

</script>
</html>

冯奎博客
请先登录后发表评论
  • latest comments
  • 总共0条评论