JS30. Задание 23 Speech Synthesis
Демо: https://js3023.github.io/
Код: https://github.com/js3023/js3023.github.io
После задания на распознавания речи посмотрим как реализуется синтез речи в браузере. Синтез речи работает в большинстве современных браузеров.
Просто озвучить текст можно в три строки кода, об этом шла речь в предыдущей теме.
speechSynthesis.speak(
new SpeechSynthesisUtterance("Здесь текст")
);
Данное задание предлагает добавление дополнительных возможностей:
- выбора голоса;
- регулировки скорости и тембра голоса;
- окно для ввода текста;
- кнопки для запуска и остановки озвучивания текста.
Разметка:
<div class="voiceinator">
<h1>The Voiceinator 5000</h1>
<select name="voice" id="voices">
<option value="">Select A Voice</option>
</select>
<label for="rate">Rate:</label>
<input name="rate" type="range" min="0" max="3" value="1" step="0.1">
<label for="pitch">Pitch:</label>
<input name="pitch" type="range" min="0" max="2" step="0.1">
<textarea name="text">Hello! I love JavaScript 👍</textarea>
<button id="stop">Stop!</button>
<button id="speak">Speak</button>
</div>
Перечислю элементы разметки: обёртка "voiceinator", заголовок h1, тег select для выбора голоса, два инпута с типом type="range" для регулировки высоты и скорости голоса, тег textarea для окна для ввода текста, кстати, если потянуть за правый нижний угол - окно растягивается. Это свойство данного тега по умолчанию. И две кнопки: Stop! и Speak
Добавим инпутам с типом type="range" шкалу для изменения характеристик голоса:
<input name="rate" type="range" min="0" max="2" value="1" step="0.1">
<input name="pitch" type="range" min="0" max="2" value="1" step="0.1">
JS-код
1. Находим все переменные:
var msg = new SpeechSynthesisUtterance();
var voices = [];
var voicesDropdown = document.getElementById("voices");
var options = document.querySelectorAll("input, #text");
var speakButton = document.getElementById("speak");
var stopButton = document.getElementById("stop");
msg.text = document.getElementById("text").value;
Здесь:
msg - генератор речи;
voices - массив с голосами для озвучивания;
voicesDropdown - тег select для выбора голоса;
options - две шкалы для изменения характеристик голоса и окно для ввода текста;
speakButton, stopButton - кнопки для запуска и остановки озвучивания речи;
msg.text - текст в окне для ввода текста, который нужно озвучить
2. Функция populateVoices() находит голос для озвучивания из имеющихся в браузере, добавляет его в разметку
function populateVoices() {
voices = this.getVoices();
voicesDropdown.innerHTML = voices
.filter(voice => voice.lang.includes('ru'))
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
.join("");
}
Функция выбора голоса срабатывает только когда происходит событие "voiceschanged" у объекта speechSynthesis, так как раньше она недоступна
speechSynthesis.addEventListener("voiceschanged", populateVoices);
Выбор голоса зависит от языка, браузера и операционной системы. Для английского у меня Хром предлагает четыре варианта голоса, Опера - один. Для русского в Хроме один вариант озвучивания, в Опере ни одного. Firefox 51.0 озвучивать ни на английском ни на русском не умеет.
Ещё один момент. Если выставить язык озвучивания 'ru', то будет озвучиваться и русский и английский текст, но если выставлен язык 'en', русский текст не озвучивается.
3. Функция setVoice() определяет какой голос выбран и устанавливает его в качестве голоса для озвучивания. Эта функция производит поиск по массиву голосов и определяет в качестве голоса для озвучавания тот, который выбран в данный момент
function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
toggle();
}
Функция setVoice() запускается при выборе голоса в выпадающем списке
voicesDropdown.addEventListener("change", setVoice);
4. Нам нужно, чтобы при каждом изменении настроек голоса или при вводе в окно нового текста, функция озвучивания перезапускалась с новыми настройками
За это отвечает функция toggle
function toggle(startOver = true) {
speechSynthesis.cancel();
if (startOver) {
speechSynthesis.speak(msg);
}
}
5. Теперь, когда у нас есть синтез речи, работающий на базовом уровне, добавим возможность пользователям редактировать параметры (скорость, тембр и текст).
Все они выбраны и сохранены в options:
var options = document.querySelectorAll("input, #text");
Добавим прослушиватель событий к каждой из этих опций:
options.forEach (option => option.addEventListener ('change', setOption));
Функция setOption() обновляет speechSynthesis.speak(msg); с новыми параметрами:
function setOption() {
msg[this.name] = this.value;
toggle();
}
6. Последний пункт - добавить функционал кнопкам запуска и остановки озвучиваия
Автор делает это очень красиво и лаконично
speakButton.addEventListener("click", toggle);
stopButton.addEventListener("click", () => toggle(false));
Код полностью:
var msg = new SpeechSynthesisUtterance();
var voices = [];
var voicesDropdown = document.getElementById("voices");
var options = document.querySelectorAll("input, #text");
var speakButton = document.getElementById("speak");
var stopButton = document.getElementById("stop");
msg.text = document.getElementById("text").value;
function populateVoices() {
voices = this.getVoices();
voicesDropdown.innerHTML = voices
.filter(voice => voice.lang.includes("ru"))
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
.join("");
}
function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
toggle();
}
function toggle(startOver = true) {
speechSynthesis.cancel();
if (startOver) {
speechSynthesis.speak(msg);
}
}
function setOption() {
console.log(this.name, this.value);
msg[this.name] = this.value;
toggle();
}
speechSynthesis.addEventListener("voiceschanged", populateVoices);
voicesDropdown.addEventListener("change", setVoice);
options.forEach(option => option.addEventListener('change', setOption));
speakButton.addEventListener("click", toggle);
stopButton.addEventListener("click", () => toggle(false));