DKL9 GitList
Repositories
DKL9 home
site_root
Code
Commits
Branches
Tags
Search
Tree:
993e20c
Branches
Tags
master
site_root
tools
text_to_speech.html
Initial commit: track much site content
dkl9
commited
993e20c
at 2025-352 15:27:28
text_to_speech.html
Blame
History
Raw
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Document-to-speech</title> <link rel="stylesheet" href="/style.css"> <link rel="icon" type="image/png" href="/favicon.png"> <style> textarea { width: 100%; height: 50%; } #prs { width: 50vw; } </style> </head> <body> <noscript>Enable JavaScript, or use a different browser</noscript> <p>Put text in the box and click the play button to have it read aloud by your browser's built-in TTS.</p> <p><label>Progress: <span id="pri">0</span>% <input id="prs" type="range" min="0" /></label></p> <p>Enter text below | <label>Speed: <span id="psi">1</span>x <input id="pss" type="range" min="0.5" max="5" step="0.1" /></label> | <button id="ppt">▶</button> | <label>Language: <input id="lsf" /></label> | <button id="nwc">Not working?</button></p> <textarea id="tts">hello world</textarea> <p>Originally developed in 2021. Comments and questions are welcome. Email them to <a href="mailto:contact@dkl9.net">contact@dkl9.net</a>. <span style="display: none;">And not <a href="mailto:sucrose@dkl9.net">sucrose@dkl9.net</a>, unless you are a spambot.</span></p> <p><a href="/">dkl9 home</a></p> <script> const PLAY_SYM = "▶"; const PAUSE_SYM = "❙❙"; const PHRASE_BOUNDARY = /([\.\;\:\!\?\(\)]|\s)*[\.\;\!\?]([\.\;\:\!\?\(\)]|\s)*/; const sourceText = document.getElementById("tts"); const progressSlider = document.getElementById("prs"); const progressIndicator = document.getElementById("pri"); const speedSlider = document.getElementById("pss"); const speedIndicator = document.getElementById("psi"); const playButton = document.getElementById("ppt"); const langSelect = document.getElementById("lsf"); const notWorkingButton = document.getElementById("nwc"); const utterance = new SpeechSynthesisUtterance(); let phraseList = ["hello", "world"]; let phraseInd = 0; let playing = false; function updateSpeed(newSpeed) { utterance.rate = parseFloat(newSpeed); speedSlider.value = newSpeed; speedIndicator.innerText = newSpeed.toString(); } function updateProgress(newInd) { phraseInd = newInd; progressSlider.value = phraseInd; progressIndicator.innerText = Math.round(100 * phraseInd / phraseList.length).toString(); } function nextWord() { if (!playing) { utterance.onend = null; return; } if (phraseInd < phraseList.length) { utterance.text = phraseList[phraseInd] || ""; window.speechSynthesis.speak(utterance); updateProgress(phraseInd + 1); } else { playing = false; phraseInd = 0; } } function updateText(text) { const oldPos = phraseInd / phraseList.length; phraseList = text.split(PHRASE_BOUNDARY).filter(x => x); progressSlider.max = phraseList.length - 1; updateProgress(Math.round(oldPos * phraseList.length)); } function selectLanguage(lang) { utterance.lang = lang; } function stopPlaying(force) { if (playing || force) { playing = false; playButton.innerText = PLAY_SYM; if (window.speechSynthesis.speaking) { window.speechSynthesis.cancel(); } } } function startPlaying(force) { if (!playing || force) { playing = true; playButton.innerText = PAUSE_SYM; if (phraseInd > 0) { updateProgress(phraseInd - 1); } utterance.onend = nextWord; nextWord(); } } function togglePlaying() { if (playing) { stopPlaying(); } else { startPlaying(); } } updateText(sourceText.value); utterance.onend = nextWord; sourceText.onchange = function(ev) { stopPlaying(); updateText(ev.target.value); }; playButton.onclick = togglePlaying; langSelect.onchange = function(ev) { selectLanguage(ev.target.value); }; progressSlider.onchange = function(ev) { const oldState = playing; stopPlaying(); updateProgress(ev.target.value); if (oldState) { startPlaying(); } }; speedSlider.onchange = function(ev) { stopPlaying(); updateSpeed(ev.target.value); startPlaying(); } notWorkingButton.onchange = function(ev) { stopPlaying(true); }; </script> </body> </html>