Спасибо контент-провайдерам:Jinniu District Wu Di Студия разработки программного обеспечения
предисловие
Сегодня мы собираемся сделать кое-что интересное, преобразование голоса ИИ! Когда мы столкнулись с необходимостью преобразования голоса, мы почувствовали, вау, это так сложно, как же это разработать. На самом деле это очень просто.Сегодня автор покажет вам как мы используем js для реализации функции преобразования голоса!
Во-первых, давайте сделаем две кнопки, кнопку запуска и кнопку, чтобы закончить и начать преобразование речи:
Глава 1: Распознавание речи
1. Начните писать код
писать html и простой css
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {margin: 0;padding: 0;}
body {
display: flex;
justify-content: space-around;
align-items: center;
}
.startBtn, .endBtn {
display: block;
width: 150px;
height: 120px;
border: 2px solid;
margin: 10px;
}
</style>
</head>
<body>
<button onclick="start()" class="startBtn">开始说话</button>
<br />
<button onclick="end()" class="endBtn">结束并转换普通话</button>
</body>
</html>
Затем мы делаем некоторую отладочную информацию в консоли и сообщаем окончательный результат преобразования!
js-код
<script>
var recognition = new webkitSpeechRecognition() || new SpeechRecognition();
recognition.lang = 'cmn-Hans-CN'; //定义普通话 (中国大陆)
function start() {
console.log('start')
// 开启
recognition.start();
}
function end() {
console.log('end')
// 停止
recognition.stop();
}
// 当调用recognition的stop的时候会触发此对象的onresult事件,然后我们在这里获取我们的转换结果。
recognition.onresult = function(event) {
alert(event.results[0][0].transcript);
}
</script>
2. Объяснение очков знаний
мы можем поставить этоSpeechRecognitionВылезает встроенная консоль объекта, чтобы посмотреть, какие свойства и методы у него есть
Введение атрибута:
Атрибуты | эффект | параметр |
---|---|---|
grammars | В этом свойстве хранится коллекция объектов SpeechGrammar, представляющих грамматики, допустимые для данного распознавания. | Справочный адрес |
lang | Это свойство задает язык, распознаваемый запросом, с допустимым языковым тегом BCP 47. Если он не установлен, он по-прежнему не установлен для получения сценария, но по умолчанию используется корневой элемент HTML-документа и связанные иерархии для этого языка. Это значение по умолчанию рассчитывается и используется, когда входящий запрос открывает соединение со службой распознавания. | Подобно атрибуту lang в html, это перечисление. |
continuous | Когда для этого свойства установлено значение false, пользовательский агент ДОЛЖЕН вернуть не более одного окончательного результата в ответ на распознавание инициации (например, однооборотный шаблон взаимодействия). Если установлено значение true, пользовательский агент ДОЛЖЕН возвращать ноль или более окончательных результатов, представляющих несколько последовательных распознаваний в ответ на начальное распознавание (например, диктовку). Значение по умолчанию должно быть ложным. Установка этого свойства не влияет на промежуточные результаты. | boolean |
interimResults | Определяет, возвращать ли промежуточные результаты. Если установлено значение true, промежуточные результаты должны быть возвращены. Если установлено значение false, промежуточные результаты не должны возвращаться. Значение по умолчанию должно быть ложным. Это свойство не влияет на конечный результат. | boolean |
maxAlternatives | Это свойство задает максимальное количество каждого результата SpeechRecognitionAlternative. Значение по умолчанию 1. | Его значение находится в диапазоне [0, 18446744073709551615]. |
Введение метода:
метод | вводить |
---|---|
start() | Когда вызывается метод запуска, он указывает время, в которое веб-приложение хочет начать распознавание. Когда голосовой ввод передается в режиме реального времени через входной медиапоток, этот начальный вызов представляет, когда служба должна начать прослушивание и попытаться сопоставить грамматику, связанную с этим запросом. После того, как система успешно прослушала распознавание, пользовательский агент ДОЛЖЕН инициировать событие запуска. Если метод запуска вызывается для уже запущенного объекта (то есть метод start был вызван ранее, и для этого объекта не возникло ни ошибки, ни события завершения), пользовательский агент ДОЛЖЕН сгенерировать исключение DOMException "InvalidStateError" и проигнорировать вызов. |
stop() | Метод остановки представляет собой инструкцию для службы распознавания, которая прекращает прослушивание большего количества аудио и пытается вернуть результат, используя только аудио, полученное для этого распознавания. Типичное использование метода остановки может быть для веб-приложения, где конечный пользователь указывает на конечную точку, подобно рации. Конечный пользователь может удерживать клавишу пробела, чтобы поговорить с системой, и вызов запуска происходит при нажатии клавиши пробела, а метод остановки вызывается при отпускании клавиши пробела, чтобы гарантировать, что система больше не слушает Пользователь. После вызова метода остановки речевой сервис не должен собирать дополнительный звук или продолжать слушать пользователя. Речевая служба должна попытаться вернуть результат распознавания (или несоответствие) на основе аудио, которое было собрано для этого распознавания. Если метод остановки вызывается для объекта, который был остановлен или останавливается (т. е. для него никогда не вызывался метод start), произошло событие конца или ошибки, или ранее был вызван метод остановки), пользовательский агент ДОЛЖЕН игнорировать вызов. |
abort() | Метод прерывания представляет собой запрос на немедленное прекращение прослушивания и прекращения распознавания и не возвращает никакой информации, но система готова. Речевая служба должна перестать распознавать вызов метода прерывания. Как только голосовая служба больше не подключена, пользовательский агент ДОЛЖЕН вызвать событие завершения. Если метод abort вызывается для объекта, который был остановлен или прерывается (то есть для него никогда не вызывался start, для него возникало событие end или error, или для него ранее вызывался abort), пользователь Агент должен игнорировать вызов. |
Введение события
событие | вводить |
---|---|
audiostart | Запускается, когда пользовательский агент начинает захват звука |
soundstart | Срабатывает при обнаружении какого-либо звука (вероятно, речи). Это должно запускаться с малой задержкой, например, с помощью детектора энергии на стороне клиента. Событие audiostart должно быть сгенерировано до события soundstart. |
speechstart | Запускается, когда начинается речь, которая будет использоваться для распознавания речи. Событие audiostart должно быть запущено до события speechstart. |
speechend | Запускается, когда заканчивается речь, которая будет использоваться для распознавания речи. Событие speechstart всегда должно запускаться перед началом речи. |
soundend | Запускается, когда определенные звуки больше не обнаруживаются. Это должно запускаться с малой задержкой, например, с помощью детектора энергии на стороне клиента. Событие soundstart всегда должно запускаться до soundend. |
audioend | Запускается после того, как пользовательский агент закончил захват звука. Событие audiostart всегда должно запускаться до события audioend. |
result | Запускается, когда распознаватель речи возвращает результат. Событие должно использовать интерфейс SpeechRecognitionEvent. Событие audiostart должно быть сгенерировано до события результата. |
nomatch | Запускается, когда распознаватель речи возвращает окончательный результат, при котором ни одна гипотеза распознавания не соответствует порогу достоверности или не превышает его. Событие должно использовать интерфейс SpeechRecognitionEvent. Атрибуты в событии результатов могут содержать результаты распознавания речи, которые ниже доверительного порога или пусты. Событие audiostart должно быть запущено до события NOMATCH. |
error | Запускается при возникновении ошибки распознавания речи. Событие должно использовать интерфейс SpeechRecognitionErrorEvent. |
start | Запускается, когда служба распознавания начинает прослушивать аудио для распознавания |
end | Запускается, когда служба отключена. Событие всегда должно генерироваться при завершении сеанса, независимо от причины окончания сеанса. |
3. Введение в совместимость
С сожалением должен сказать вам, что совместимость этого API не очень хорошая. Обычно я использую его только на хроме. Если это не хром-браузер, то я буду вызывать внутренний интерфейс. Например, он реализован на таких языках, как java или python.
Многие друзья очень странные, зачем его использовать, так как совместимость плохая, потому что вызов внутреннего интерфейса неизбежно вызовет некоторую нагрузку на сервер, и это во многом связано со скоростью сети и так далее. Если мы можем реализовать это сами на внешнем интерфейсе, мы должны отдать приоритет нашей собственной реализации.
Совместимое написание
<script>
function start() {
voiceConversion('start')
}
function end() {
voiceConversion('end')
}
function voiceConversion(type) {
console.log(type);
try {
let recognition = new webkitSpeechRecognition() || new SpeechRecognition();
console.log(recognition)
recognition.lang = 'cmn-Hans-CN'; //普通话 (中国大陆)
if (type === 'start') {
// 开启
recognition.start();
} else {
// 停止
recognition.stop();
}
recognition.onresult = function(event) {
alert(event.results[0][0].transcript);
}
} catch (e) {
console.log('调用后端接口');
}
}
</script>
4. Фактические боевые учения
Далее мы покажем вам, как распознавать и отображать то, что сказал пользователь, в режиме реального времени, когда пользователь нажимает на запись:
Полный код:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {margin: 0;padding: 0;}
.wrapBox {
display: flex;
justify-content: space-around;
align-items: center;
}
.startBtn, .endBtn {
display: block;
width: 150px;
height: 120px;
border: 2px solid;
margin: 10px;
}
</style>
</head>
<body>
<div class="wrapBox">
<button onclick="start()" class="startBtn">开始说话</button>
<br />
<button onclick="end()" class="endBtn">结束并转换普通话</button>
</div>
<div id="resultText"></div>
<script>
const resultTextDiv = document.querySelector('#resultText');
function start() {
voiceConversion('start')
}
function end() {
voiceConversion('end')
}
function voiceConversion(type) {
console.log(type);
try {
let recognition = new webkitSpeechRecognition() || new SpeechRecognition();
recognition.lang = 'cmn-Hans-CN'; //普通话 (中国大陆)
recognition.interimResults = true;
if (type === 'start') {
// 开启
recognition.start();
} else {
// 停止
recognition.stop();
}
recognition.onresult = function(event) {
const text = event.results[0][0].transcript;
resultTextDiv.innerHTML = text;
}
} catch (e) {
console.log('调用后端接口');
}
}
</script>
</body>
</html>
конец:
Это просто основное требование для нас, чтобы начать, нам также нужно добавить требование для получения громкости голоса и функции повторения
Глава 2: Создайте небольшой стиль для оценки громкости голоса
Один: расширение в соответствии с первым кодом требования
Нам нужно добавить к нему тег html, чтобы показать размер нашего голоса:
<span id="volumeBox"></span>
Затем определите функцию, которая определяет громкость звука:
// 获取我们的音量盒子元素
const mystatus = document.getElementById('volumeBox');
let mediaStreamSource = null,
scriptProcessor = null;
// 开始检测音量大小的函数
function beginDetect() {
let audioContext = new (window.AudioContext || window.webkitAudioContext)();
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// 获取用户的 media 信息
navigator.mediaDevices.getUserMedia({audio: true}).then((stream) => {
// 将麦克风的声音输入这个对象
mediaStreamSource = audioContext.createMediaStreamSource(stream);
// 创建一个音频分析对象,采样的缓冲区大小为4096,输入和输出都是单声道
scriptProcessor = audioContext.createScriptProcessor(4096,1,1);
// 将该分析对象与麦克风音频进行连接
mediaStreamSource.connect(scriptProcessor);
// 解决 Chrome 自身的 bug
scriptProcessor.connect(audioContext.destination);
// 开始处理音频
scriptProcessor.onaudioprocess = (e) => {
// 获得缓冲区的输入音频,转换为包含了PCM通道数据的32位浮点数组
const buffer = e.inputBuffer.getChannelData(0);
// 获取缓冲区中最大的音量值
const maxVal = Math.max.apply(Math, buffer);
// 显示音量值
mystatus.innerHTML = `您的音量值:${ Math.round(maxVal * 100)}`;
};
}).catch((error) => {
mystatus.innerHTML = `获取音频时好像出了点问题。${error}`;
})
} else {
mystatus.innerHTML = '您的浏览器不支持识别声音大小';
}
};
// 关闭检测音量大小
function stopDetect() {
scriptProcessor.disconnect
? scriptProcessor.disconnect()
: console.log('无需关闭任何');
}
Затем мы вызываем эти две функции, когда начинаем говорить и когда заканчиваем:
// 在voiceConversion函数里进行局部追加代码
if (type === 'start') {
// 开启
beginDetect();
recognition.start();
} else {
// 停止
stopDetect();
recognition.stop();
}
Мы можем разработать некоторые другие стили на основе maxValue. Вместо того, чтобы просто показывать шрифты, как автор разместил здесь. Например [похоже на это]:
Любой, кто хочет подобный стиль, может пообщаться с автором в частном порядке. Поскольку в этом сообщении блога слишком много контента, код не будет выпущен ~.
Во-вторых, очки знаний
mediaDevices
метод | вводить |
---|---|
MediaDevices.enumerateDevices() | Получите ряд информации о медиа-входах и выходах, доступных в системе. |
getSupportedConstraints() | Возвращает объект, который соответствует информации MediaTrackSupportedConstraints, указывающей, какие ограничиваемые свойства поддерживаются в интерфейсе MediaStreamTrack. |
getDisplayMedia() | Предлагает пользователю выбрать дисплей или часть дисплея (например, окно) для захвата MediaStream для совместного использования или записи. Возвращает Promise MediaStream, который разрешается в. |
MediaDevices.getUserMedia() | Включите камеру или общий доступ к экрану и/или микрофон в системе с разрешения пользователя через приглашение и предоставьте вход MediaStream, содержащий видеодорожку и/или звуковую дорожку. |
AudioContext
Интерфейс AudioContext представляет граф обработки звука, построенный из связанных аудиомодулей, каждый из которых представлен AudioNode. Аудиоконтекст управляет как созданием содержащихся в нем узлов, так и выполнением обработки или декодирования звука. Вам нужно создать AudioContext, прежде чем делать что-либо еще, потому что все происходит в контексте.
метод | вводить |
---|---|
AudioContext.close() | Закрывает аудиоконтекст, освобождая все используемые системные аудиоресурсы. |
AudioContext.createMediaElementSource() | Создает HTMLMediaElement, связанный с MediaElementAudioSourceNode. Это можно использовать для воспроизведения и управления звуком из или элементов. |
AudioContext.createMediaStreamSource() | Создает MediaStreamAudioSourceNode, связанный с представлением MediaStream аудиопотока, который может исходить от микрофона локального компьютера или другого источника. |
AudioContext.createMediaStreamDestination() | Создайте связь MediaStreamAudioDestinationNode с MediaStream для представления аудиопотока, который можно сохранить в локальном файле или отправить на другой компьютер. |
AudioContext.createMediaStreamTrackSource() | Создает связь MediaStreamTrackAudioSourceNode с MediaStream, представляющим дорожку медиапотока. |
AudioContext.getOutputTimestamp() | Возвращает новый объект AudioTimestamp, содержащий два значения метки времени аудио относительно текущего контекста аудио. |
AudioContext.resume() | Возобновление хода времени в ранее приостановленном/приостановленном звуковом контексте. |
AudioContext.suspend() | Приостановите время в звуковой среде, временно остановите доступ к звуковому оборудованию и уменьшите использование ЦП/батареи в процессе. |
AudioContext.createScriptProcessor() | Метод createScriptProcessor() интерфейса AudioContext создает ScriptProcessorNode для обработки аудио непосредственно через JavaScript. |
createScriptProcessor() принимает три параметра: ==размер буфера==
Размер буфера в выборочных кадрах. В частности, размер буфера должен быть одним из следующих значений: 256, 512, 1024, 2048, 4096, 8192, 16384. Если параметр не передан или равен 0, берется наиболее подходящий размер буфера для текущей среды, a константа, значение которой является степенью числа 2, постоянной на протяжении всего времени существования узла. Это значение определяет, как часто отправляются события аудиопроцесса и сколько выборочных кадров обрабатывается за вызов. Чем ниже значение bufferSzie, тем больше задержка. Более высокий размер буфера должен позаботиться о том, чтобы избежать сбоев и сбоев звука. Автору рекомендуется не указывать конкретный размер буфера и позволить системе выбрать хорошее значение, чтобы сбалансировать задержку и качество звука. == количество входных каналов == Значение представляет собой целое число, которое используется для указания количества каналов входного узла.Значение по умолчанию равно 2, а максимальное значение может быть 32. ==numberOfOutputChannels== Значение представляет собой целое число, которое используется для указания количества каналов выходного узла.Значение по умолчанию равно 2, максимальное значение может быть 32.
грамматика: var audioCtx = новый AudioContext();
myScriptProcessor = audioCtx.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels);
3. Введение в совместимость
MediaDevices хорошо поддерживается другими браузерами, кроме IE. Аудиоконтекст тот же.
Глава 3: Реализация функции повтора браузера
1. Отображение кода
<!--追加一个选择语言的select标签-->
<div>选择语言:<select name="" id=""></select></div>
Сначала получите язык, поддерживаемый браузером, затем добавьте тег option к тегу select, чтобы мы могли выбрать Примечание: Распознавание лучше всего убрать.interimResults=true;, иначе взаимодействие будет очень недружественным.
// 首先获取浏览器支持的语言
const synth = window.speechSynthesis;
let voices = synth.getVoices();
const voiceSelect = document.querySelector('select');
function populateVoiceList() {
voices = synth.getVoices();
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);
}
}
populateVoiceList();
if (synth.onvoiceschanged !== undefined) {
synth.onvoiceschanged = populateVoiceList;
}
Прочитайте полученный текст в нашем распознавании. по результату
const utterThis = new window.SpeechSynthesisUtterance(text);
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];
}
}
synth.speak(utterThis);
Во-вторых, очки знаний
Первый — это объект SpeechSynthesisUtterance, который в основном используется для создания экземпляров синтеза речи, таких как объект экземпляра utterThis в приведенном выше коде. Мы можем напрямую написать текстовое содержимое для чтения во время построения. Вы также можете установить его текстовое свойство позже.
Атрибуты | вводить |
---|---|
text | Это свойство указывает текст, который следует синтезировать и произнести для этой речи. Это может быть обычный текст или правильно сформированный полный документ SSML. [SSML] Для механизмов синтеза речи, которые не поддерживают SSML или поддерживают только определенные теги, пользовательский агент или механизм обработки речи ДОЛЖНЫ удалять неподдерживаемые теги и произносить текст. Максимальная длина текста может быть ограничена 32 767 символами. |
lang | Этот атрибут указывает язык синтеза речи для речи с использованием действительного языкового тега BCP 47. [BCP47] Если он не установлен, он по-прежнему не установлен для получения сценария, но по умолчанию используется корневой элемент HTML-документа и связанные иерархии для этого языка. Это значение по умолчанию рассчитывается и используется, когда входящий запрос открывает соединение со службой распознавания. |
voice | Тип — SpeechSynthesisVoice, который может иметь значение null.Это свойство указывает голос синтеза речи, который хочет использовать веб-приложение. Это свойство должно быть инициализировано значением null при создании объекта SpeechSynthesisUtterance. Если для этого свойства задан один из объектов SpeechSynthesisVoice, возвращаемых функцией getVoices() при вызове метода speak(), пользовательский агент ДОЛЖЕН использовать этот голос. Если это свойство не установлено или имеет значение null при вызове метода speak(), пользовательский агент ДОЛЖЕН использовать речь пользовательского агента по умолчанию. Голос агента пользователя по умолчанию должен поддерживать текущий язык (см. язык), может быть локальной или удаленной голосовой службой и может включать выбор конечного пользователя через интерфейсы, предоставляемые агентом пользователя (например, параметры конфигурации браузера). |
volume | Это свойство определяет громкость речи. Его диапазон составляет от 0 до 1 включительно, где 0 — самая низкая громкость, 1 — самая высокая громкость, а значение по умолчанию — 1. При использовании SSML это значение будет переопределено просодическим тегом в теге. |
rate | Это свойство определяет скорость произнесения речи. Это скорость по умолчанию для этого голоса. 1 — это скорость по умолчанию, поддерживаемая механизмом синтеза речи или конкретной речью (должна соответствовать нормальной скорости речи). 2 — это удвоенная скорость, а 0,5 — половина скорости. Значения меньше 0,1 или больше 10 строго запрещены, но минимальная и максимальная скорости могут быть дополнительно ограничены механизмом синтеза речи или конкретным голосом, например, конкретный голос не может быть в 3 раза быстрее, чем обычная речь, даже если вы укажете значение больше 3. При использовании SSML это значение будет переопределено тегом просодии в разметке. |
pitch | Это свойство определяет высоту голоса вокализации. Диапазон значений составляет от 0 до 2 включительно, где 0 — самый низкий тон, а 2 — самый высокий. 1 соответствует механизму синтеза речи или основному тону для конкретной речи. Минимальная и максимальная скорости могут быть дополнительно ограничены механизмом синтеза речи или речью. При использовании SSML это значение будет переопределено тегом просодии в разметке. |
Тогда есть объект SpeechSynthesis. Это скриптовый веб-API для управления преобразованием текста в речь.
Атрибуты | вводить |
---|---|
pending | Это свойство имеет значение true, если очередь глобального экземпляра SpeechSynthesis содержит все высказывания, которые еще не начали произноситься. |
speaking | Это свойство истинно, если произносится речь. В частности, если высказывание было начато, но не закончено. Это никак не связано с тем, находится ли глобальный экземпляр SpeechSynthesis в состоянии паузы. |
paused | Это свойство имеет значение true, если глобальный экземпляр SpeechSynthesis приостановлен. Это состояние не зависит от того, есть ли что-нибудь в очереди. Состоянием по умолчанию глобального экземпляра SpeechSynthesis нового окна является состояние без приостановки. |
метод | вводить |
---|---|
speak(utterance) | Для глобальных экземпляров SpeechSynthesis этот метод добавляет речь объекта SpeechSynthesisUtterance в конец очереди. Это не изменяет состояние паузы экземпляра SpeechSynthesis. Если экземпляр SpeechSynthesis приостановлен, он останется приостановленным. Если не приостановлено и в очереди нет других голосов, голос произносится немедленно, в противном случае голос ставится в очередь, чтобы начать говорить после того, как все остальные голоса в очереди будут произнесены. Если в объект SpeechSynthesisUtterance после вызова этого метода и до соответствующего завершения или ошибки внесено событие изменения, неизвестно, повлияют ли эти изменения на то, что вы сказали, и эти изменения могут привести к возврату ошибки. Объект SpeechSynthesis становится исключительным владельцем объекта SpeechSynthesisUtterance. Передача его в качестве параметра speak() другому объекту SpeechSynthesis должна вызвать исключение. (Например, два кадра могут иметь одно и то же происхождение, и каждый кадр будет содержать объект SpeechSynthesis.) |
cancel() | Этот метод удаляет все выступления из очереди. Если произносится высказывание, речь немедленно прекращается. Этот метод не изменяет состояние паузы глобального экземпляра SpeechSynthesis. |
pause() | Этот метод переводит глобальный экземпляр SpeechSynthesis в состояние ожидания. Если высказывание произносится, оно приостанавливает среднее высказывание. (При вызове, когда экземпляр SpeechSynthesis уже приостановлен, он ничего не сделает.) |
resume() | Этот метод переводит глобальный экземпляр SpeechSynthesis в состояние без приостановки. Если произносится высказывание, оно будет продолжать произнесение высказывания, пока оно приостановлено, в противном случае оно начнет произносить следующее высказывание в очереди (если есть). (При вызове, когда экземпляр SpeechSynthesis уже находится в неподвешенном состоянии, он ничего не сделает.) |
getVoices() | Этот метод возвращает доступные звуки. Речь пользователя зависит от того, какие звуки доступны. Если голоса недоступны или список доступных голосов неизвестен (например, синтез на стороне сервера, где список определяется асинхронно), этот метод должен возвращать SpeechSynthesisVoiceList нулевой длины. |
voiceschanged | Запускается, когда содержимое SpeechSynthesisVoiceList, возвращаемое методом getVoices, изменилось. Примеры включают: синтез на стороне сервера, где список определяется асинхронно, или установка/удаление речи на стороне клиента. |
3. Введение в совместимость