Last active
January 14, 2024 08:13
-
-
Save prof3ssorSt3v3/1c275f7e1d534945aefba5104077bce0 to your computer and use it in GitHub Desktop.
Code from video on Intro to Web Text to Speech
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let VOICE = null; | |
let synth = window.speechSynthesis; | |
let voices = synth.getVoices(); | |
(function addListeners() { | |
document.getElementById('voiceSelect').addEventListener('change', changeVoice); | |
document.getElementById('btnRead').addEventListener('click', readParas); | |
document.getElementById('btnPause').addEventListener('click', () => { | |
synth.pause(); | |
}); | |
document.getElementById('btnResume').addEventListener('click', () => { | |
synth.resume(); | |
}); | |
document.getElementById('rate').addEventListener('input', (ev) => { | |
document.getElementById('rate-value').textContent = ev.target.value; | |
}); | |
document.getElementById('pitch').addEventListener('input', (ev) => { | |
document.getElementById('pitch-value').textContent = ev.target.value; | |
}); | |
document.getElementById('volume').addEventListener('input', (ev) => { | |
document.getElementById('volume-value').textContent = ev.target.value; | |
}); | |
//build the select list | |
setTimeout(() => { | |
if (voices.length === 0) { | |
voices = synth.getVoices(); | |
} | |
loadVoices(); | |
}, 100); | |
})(); | |
function loadVoices() { | |
//build the select list | |
// voice .lang 'en-CA', name: 'Karen', default: true|false | |
for (let i = 0; i < voices.length; i++) { | |
if (!voices[i].lang.startsWith('en-')) continue; | |
const option = document.createElement('option'); | |
option.textContent = voices[i].name + ' (' + voices[i].lang + ')'; | |
if (voices[i].default) { | |
option.className = 'picked'; | |
VOICE = voices[i]; | |
} | |
option.setAttribute('data-lang', voices[i].lang); | |
option.setAttribute('data-name', voices[i].name); | |
document.getElementById('voiceSelect').appendChild(option); | |
} | |
} | |
function readParas(ev) { | |
//read the text from the inputs and speak it | |
const inputs = document.querySelectorAll('.sentences input'); | |
inputs.forEach((input, idx) => { | |
const txt = input.value; | |
const utter = new SpeechSynthesisUtterance(txt); | |
utter.voice = VOICE; | |
//change the rate, pitch and volume | |
utter.rate = document.getElementById('rate').value; | |
utter.pitch = document.getElementById('pitch').value; | |
utter.volume = document.getElementById('volume').value; | |
synth.speak(utter); | |
}); | |
} | |
function changeVoice(ev) { | |
//pick a voice from the list | |
const select = ev.target; | |
const index = select.selectedIndex; | |
const name = select.options[index].getAttribute('data-name'); | |
select.querySelector('.picked').removeAttribute('class'); | |
for (let i = 0; i < voices.length; i++) { | |
if (voices[i].name === name) { | |
VOICE = voices[i]; | |
select.options[index].className = 'picked'; | |
} | |
} | |
console.log(VOICE); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html { | |
color-scheme: dark light; | |
font-size: 20px; | |
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | |
} | |
.sentences { | |
display: flex; | |
flex-direction: column; | |
} | |
input[type='text'] { | |
font-size: 1.2rem; | |
padding: 0.2rem 1rem; | |
margin: 1rem; | |
width: 50ch; | |
} | |
.buttons { | |
display: flex; | |
flex-direction: row; | |
} | |
button { | |
background-color: steelblue; | |
color: white; | |
font-size: 1.2rem; | |
padding: 0.2rem 2rem; | |
margin-inline: 2rem; | |
border: none; | |
cursor: pointer; | |
} | |
.controls { | |
display: flex; | |
flex-direction: row; | |
gap: 2rem; | |
} | |
.controls p { | |
display: flex; | |
flex-direction: column; | |
} | |
.controls p * { | |
font-size: 1.2rem; | |
} | |
option.picked { | |
text-align: right; | |
font-weight: bold; | |
} | |
/* deprecated in most places from CSS 2.1 | |
@media aural { | |
body { | |
voice-family: Karen, female; | |
pause-before: 100ms; | |
cue-after: url('./effect.mp3'); | |
stress: 20; | |
richness: 90; | |
speech-rate: medium; | |
azimuth: 0deg; | |
elevation: 30deg; | |
volume: 100; | |
} | |
} | |
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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, initial-scale=1.0" /> | |
<title>SpeechSynthesis - Text 2 Speech</title> | |
<link href="./main.css" rel="stylesheet" /> | |
<script src="./app.js" type="module"></script> | |
</head> | |
<body> | |
<header> | |
<h1>SpeechSynthesis & SpeechSynthesisUtterance</h1> | |
</header> | |
<div class="sentences"> | |
<input type="text" value="So, I asked my girlfriend Matilda if she wanted to waltz." /> | |
<input type="text" value="Pineapple Apple Pen." /> | |
</div> | |
<div class="buttons"> | |
<button id="btnRead">READ</button> | |
<button id="btnPause">PAUSE playback</button> | |
<button id="btnResume">RESUME playback</button> | |
</div> | |
<div class="controls"> | |
<p> | |
<label for="voiceSelect">Voice List</label> | |
<select id="voiceSelect" name="voiceSelect"></select> | |
</p> | |
<p> | |
<label for="pitch">Pitch (0 - 2)</label> | |
<input type="range" id="pitch" min="0" max="2" value="1" step="0.1" /> | |
<span id="pitch-value">1</span> | |
</p> | |
<p> | |
<label for="rate">Rate (1 - 10)</label> | |
<input type="range" id="rate" min="1" max="10" value="1" step="1" /> | |
<span id="rate-value">1</span> | |
</p> | |
<p> | |
<label for="volume">Volume (0 - 1)</label> | |
<input type="range" id="volume" min="0" max="1" value="0.5" step="0.1" /> | |
<span id="volume-value">0.5</span> | |
</p> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment