SpeechSynthesis demo

HTML

<h1>SpeechSynthesis demonstration</h1>
<form id="voiceForm">
  <p>
    Text to speech: <input id="inputTxt" type="text">
  </p>
  <p>
    Voice: <select id="voiceSelect"></select>
  </p>
  <p>
    Pitch: <input id="pitch" type="number" min="0" max="2" step="any" value="1"> (default 1)
  </p>
  <p>
    Speed (rate): <input id="rate" type="number" min="0.1" max="10" step="any" value="1"> (default 1)
  </p>
  <p>
    Volume: <input id="volume" type="number" min="0" max="1" step="any" value="1"> (default 1)
  </p>
  <button type="submit">
    Play
  </button>
  <button id="pauseBtn" type="button">
    Pause
  </button>
  <button id="resumeBtn" type="button">
    Resume
  </button>
  <button id="cancelBtn" type="button">
    Cancel
  </button>
</form>

<hr>
<h3>Debug</h3>
<div id="synth-events">
  <h4>Synth events:</h4>
</div>
<div id="utterance-events">
  <h4>Utterance events:</h4>
</div>

JavaScript

const synth = window.speechSynthesis;
let voices;


const voiceSelect = document.getElementById('voiceSelect');
function loadVoices() {
	voices = synth.getVoices();
  for (let i = 0; i < voices.length; i++) {
    const option = document.createElement("option");
    option.textContent = `${voices[i].name} (${voices[i].lang})`;
    option.value = i;
    voiceSelect.appendChild(option);
  }// endfor;
}// loadVoices


// listen form submit. ====================
const voiceForm = document.getElementById('voiceForm');
const inputTxt = document.getElementById('inputTxt');
const utteranceEventsPh = document.getElementById('utterance-events');
voiceForm?.addEventListener('submit', (event) => {
	event.preventDefault();
  const utterance = new SpeechSynthesisUtterance(inputTxt?.value);
  utterance.voice = voices[voiceSelect.value];
  utterance.lang = voices[voiceSelect.value].lang;
  utterance.pitch = document.getElementById('pitch')?.value;
  utterance.rate = document.getElementById('rate')?.value;
  utterance.volume = document.getElementById('volume')?.value;
  synth.speak(utterance);
  inputTxt?.blur();

  // utterance events. ----------------
  utterance.addEventListener("boundary", (event) => {
    console.log(
      `${event.name} (${utterance.text[event.charIndex]}) boundary reached after ${event.elapsedTime} seconds.`,
    );
    utteranceEventsPh.insertAdjacentHTML('beforeend', `${event.name} (${utterance.text[event.charIndex]}) boundary reached after ${event.elapsedTime} seconds.<br>`);
  });
  utterance.addEventListener("end", (event) => {
    console.log(
      `Utterance has finished being spoken after ${event.elapsedTime} seconds.`,
    );
    utteranceEventsPh.insertAdjacentHTML('beforeend', `Utterance has finished being spoken after ${event.elapsedTime} seconds.<br><br>`);
  });
  utterance.addEventListener("error", (event) => {
    console.log(
      `An error has occurred with the speech synthesis: ${event.error}`,
    );
   ...