<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 id="playBtn" 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>
button {
border: 1px solid #bbb;
border-radius: 5px;
padding: 8px 6px;
}
input, select {
border: 1px solid #bbb;
border-radius: 5px;
padding: 4px 3px;
}
#playBtn {
background-color: blue;
border: 1px solid blue;
color: #fff;
}
#synth-events,
#utterance-events {
border: 1px dashed #ccc;
padding: 5px;
margin: 0 0 10px 0;
}
#synth-events h4,
#utterance-events h4 {
margin: 0 0 10px 0;
}
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}`,
);
utteranceEventsPh.insertAdjacentHTML('beforeend', `<span style="color: red;">An error has occurred with the speech synthesis: ${event.error}</span><br><br>`);
});
utterance.addEventListener("mark", (event) => {
console.log(`A mark was reached: ${event.name}`);
utteranceEventsPh.insertAdjacentHTML('beforeend', `A mark was reached: ${event.name}<br>`);
});
utterance.addEventListener("pause", (event) => {
console.log(`Speech paused after ${event.elapsedTime} seconds.`);
utteranceEventsPh.insertAdjacentHTML('beforeend', `Speech paused after ${event.elapsedTime} seconds.<br>`);
});
utterance.addEventListener("resume", (event) => {
console.log(`Speech resumed after ${event.elapsedTime} seconds.`);
utteranceEventsPh.insertAdjacentHTML('beforeend', `Speech resumed after ${event.elapsedTime} seconds.<br>`);
});
utterance.addEventListener("start", (event) => {
console.log(`We have started uttering this speech: ${event.utterance.text}`);
utteranceEventsPh.insertAdjacentHTML('beforeend', `We have started uttering this speech: ${event.utterance.text}<br>`);
});
// end utterance events. ------------
});
// end listen form submit. ================
// control buttons. ======================
const pauseBtn = document.getElementById('pauseBtn');
if (pauseBtn) {
pauseBtn.addEventListener('click', (event) => {
event.preventDefault();
synth.pause();
});
}
const resumeBtn = document.getElementById('resumeBtn');
if (resumeBtn) {
resumeBtn.addEventListener('click', (event) => {
event.preventDefault();
synth.resume();
});
}
const cancelBtn = document.getElementById('cancelBtn');
if (cancelBtn) {
cancelBtn.addEventListener('click', (event) => {
event.preventDefault();
synth.cancel();
});
}
// end control buttons. ==============
// synth event(s). ===================
synth.addEventListener('voiceschanged', (event) => {
console.log('synth voice changed.');
const synthEventsPh = document.getElementById('synth-events');
synthEventsPh.insertAdjacentHTML('beforeend', '<p>voices changed.</p>');
});
// end synth event(s). ===============
loadVoices();
if (
typeof speechSynthesis !== "undefined" &&
speechSynthesis.onvoiceschanged !== undefined
) {
speechSynthesis.onvoiceschanged = loadVoices;
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.