从文本到声音:解锁语音合成 API 的无限可能

432 阅读6分钟

语音合成技术:代码深度解析与 API 调用神奇之旅

在数字世界的广袤宇宙中,语音合成技术如同一位能说会道的向导,引领我们跨越人机交互的新纪元。今天,让我们穿梭于代码的丛林,探索语音合成(Speech Synthesis)的秘密,从基本概念到 API 的应用,逐一揭开这项迷人技术的面纱。

引言:语音的力量

在页面功能实现过程中,我们经常会遇到需要文字转语音的情况,这时候,我们可以考虑查询一下相关的官方文档,今天我们介绍一下 Web Speech API ,让大家了解了解基础的文字转语音方法。

深入API的世界:Web Speech API

为了让你更好地理解和实现语音合成,我们首先需要熟悉 Web Speech API,特别是其 SpeechSynthesis 接口。这一接口为开发者提供了强大的工具,可以让网页应用具备读出文本的能力。

基础代码示例

让我们从一个简单的示例开始,看看如何使用这个 API 来合成语音:

HTML 样式

下面提供了一个简单的 HTML 。其中,<select> 元素初始是空的,之后会通过 JavaScript 使用 <option> 填充。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width" />
    <title>Speech synthesiser</title>
    <link rel="stylesheet" href="style1.css" />
  </head>
  <body>
    <h1>Speech synthesiser</h1>
    <p>
      在下面的输入中输入一些文字,然后按回车或“播放”按钮要听,请使用下拉菜单更改声音。
    </p>
    <form>
      <label for="txt">Enter text</label>
      <input id="txt" type="text" class="txt" />
      <div>
        <label for="rate">Rate</label
        ><input type="range" min="0.5" max="2" value="1" step="0.1" id="rate" />
        <div class="rate-value">1</div>
        <div class="clearfix"></div>
      </div>
      <select></select>
      <div class="controls">
        <button id="play" type="submit">Play</button>
      </div>
    </form>
    <script src="script1.js"></script>
  </body>
</html>

效果图如下:主要内容包括一个输入框(可以自行输入要转换为语音的内容),一个语速控制滑动按钮(可以通过拖动按钮,控制语音的语速),一个语言选择器(可以根据自己输入的内容切换选择不同的语种),和一个播放按钮(摁下按钮语音即可输出)。

image.png

JS 构造

首先,我们需要获得 Window.speechSynthesis 的引用。这是 API 的入口点 —— 它返回了 SpeechSynthesis 的一个实例,这是 web 语音合成的控制接口。

const synth = window.speechSynthesis;

const inputForm = document.querySelector("form");
const inputTxt = document.querySelector(".txt");
const voiceSelect = document.querySelector("select");

const rate = document.querySelector("#rate");
const rateValue = document.querySelector(".rate-value");

let voices = [];
function populateVoiceList() {
  voices = synth.getVoices().sort(function (a, b) {
    const aname = a.name.toUpperCase();
    const bname = b.name.toUpperCase();

    if (aname < bname) {
      return -1;
    } else if (aname == bname) {
      return 0;
    } else {
      return +1;
    }
  });
  const selectedIndex =
    voiceSelect.selectedIndex < 0 ? 0 : voiceSelect.selectedIndex;
  voiceSelect.innerHTML = "";

  for (let i = 0; i < voices.length; i++) {
    const option = document.createElement("option");
    option.textContent = `${voices[i].name} (${voices[i].lang})`;

    if (voices[i].default) {
      option.textContent += " -- DEFAULT";
    }

    option.setAttribute("data-lang", voices[i].lang);
    option.setAttribute("data-name", voices[i].name);
    voiceSelect.appendChild(option);
  }
  voiceSelect.selectedIndex = selectedIndex;
}

populateVoiceList();

if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = populateVoiceList;
}
function speak() {
  if (synth.speaking) {
    console.error("speechSynthesis.speaking");
    return;
  }

  if (inputTxt.value !== "") {
    const utterThis = new SpeechSynthesisUtterance(inputTxt.value);

    utterThis.onend = function (event) {
      console.log("SpeechSynthesisUtterance.onend");
    };

    utterThis.onerror = function (event) {
      console.error("SpeechSynthesisUtterance.onerror");
    };

    const selectedOption = voiceSelect.selectedOptions[0].getAttribute("data-name");

    for (let i = 0; i < voices.length; i++) {
      if (voices[i].name === selectedOption) {
        utterThis.voice = voices[i];
        break;
      }
    }
    utterThis.rate = rate.value;
    synth.speak(utterThis);
  }
}

inputForm.onsubmit = function (event) {
  event.preventDefault();

  speak();
  inputTxt.blur();
};

rate.onchange = function () {
  rateValue.textContent = rate.value;
};

voiceSelect.onchange = function () {
  speak();
};

Web Speech API

SpeechSynthesis 接口

其中 SpeechSynthesis 接口是语音服务的控制接口;它可以用于获取设备上关于可用的合成声音的信息,开始、暂停语音,或除此之外的其他命令。

属性
  • paused : 当 SpeechSynthesis 处于暂停状态时,Boolean 值返回 true

  • pending : 当语音播放队列到目前为止保持没有说完的语音时,Boolean 值返回 true

  • speaking : 当语音谈话正在进行的时候,即使SpeechSynthesis处于暂停状态,Boolean返回 true

事件操作
  • onvoiceschanged : 当由SpeechSynthesis.getVoices()方法返回的 SpeechSynthesisVoice列表改变时触发。
方法
  • cancel() : 移除所有语音谈话队列中的谈话。

  • getVoices() : 返回当前设备所有可用声音的 SpeechSynthesisVoice 列表。

  • pause() : 把 SpeechSynthesis 对象置为暂停状态。

  • resume() : 把 SpeechSynthesis 对象置为一个非暂停状态:如果已经暂停了则继续。

  • speak() : 添加一个 utterance 到语音谈话队列;它将会在其他语音谈话播放完之后播放。

以上属性和方法,均可根据自己的需求添加到代码中调试运行,在这段代码中,我们创建了一个 SpeechSynthesisUtterance 对象,并设置了其属性和事件处理函数,然后通过 speechSynthesis.speak() 方法让浏览器朗读指定的文字。

SpeechSynthesisVoice 接口

SpeechSynthesisVoice 接口表示系统支持的语音。每个 SpeechSynthesisVoice 都有自己的相对语音服务,包括语言、名称和 URI 信息。

实例属性
  • default : 布尔值,指示该语音是否为当前应用程序语言(true)的默认语音(false)。

  • lang : 返回 BCP 47 语言标签,指示语音的语言。

  • localService : 指示声音是由本地语音合成服务(true)还是由远程语音合成服务提供(false)。

  • name : 返回一个代表语音的可读名称。

  • voiceURI : 返回此语音的URI类型和语音合成服务的位置。

代码分析

这段代码实现了一个基本的文本转语音(TTS)功能,允许用户从一个输入框中输入文本,选择不同的语音和速率,然后播放所选文本的语音合成。以下是代码的核心要点和功能分析:

初始化和获取语音列表

  1. window.speechSynthesis:

    • window.speechSynthesis 是 Web Speech API 的一部分,提供了语音合成功能。
  2. populateVoiceList 函数:

    • 用于获取并填充语音选择下拉菜单。

    • 使用 synth.getVoices() 获取当前可用的所有语音。

    • 将语音按照名称排序,并创建相应的 option 元素添加到下拉菜单中。

    • 为每个 option 设置了 data-lang 和 data-name 属性,用于存储语音的语言和名称。

  3. 事件监听器:

    • 如果浏览器支持 speechSynthesis.onvoiceschanged 事件,代码将注册 populateVoiceList 函数为事件处理器,确保语音列表发生变化时能够更新下拉菜单。

文本转语音功能

  1. speak 函数:

    • 检查 speechSynthesis 是否正在说话,如果是,则不执行新的语音合成请求。

    • 创建一个新的 SpeechSynthesisUtterance 对象,用于封装待合成的文本。

    • 为 SpeechSynthesisUtterance 对象注册 onend 和 onerror 事件处理器,以便在语音合成结束或出现错误时执行相应动作。

    • 根据用户在下拉菜单中的选择,设置 SpeechSynthesisUtterance 对象的 voice 属性。

    • 设置语音合成的速率,这将影响语音的快慢。

    • 使用 synth.speak() 方法开始语音合成。

用户交互

  1. 表单提交事件:

    • 监听表单的 submit 事件,阻止默认的表单提交行为,调用 speak 函数,并使输入框失去焦点。
  2. 速率变化事件:

    • 监听速率输入框的 change 事件,更新显示速率值的元素内容。
  3. 语音选择变化事件:

    • 监听语音选择下拉菜单的 change 事件,调用 speak 函数,使用户在选择不同语音时立即听到语音合成。

总结

这段代码通过合理地利用 Web Speech API 的功能,代码实现了与用户交互的文本转语音功能,同时处理了事件监听、语音列表更新和语音合成控制。

结语:技术与未来的对话

通过今天的探索,我们不仅了解了如何使用 Web Speech API 实现基本的语音合成,还学习了如何根据用户的选择动态生成语音。语音合成技术的进步,正推动着人机交互方式的革命,使得我们的数字生活更加多彩。

但使用 Web Speech API 完成文字转语音的功能实现,也有明显的缺点,比如这使用该方法时,无法根据上下文内容正确地识别字段中的多音字。为解决这个问题,我们还可以调用相关的 AI 模型,就可以更加智能地完成文字转语音的功能,具体实现方法本人还在学习中,成功实现后会更新文章。