23 - Speech Synthesis 俗話說的好,一天一蘋果,醫生遠離我
一天一 JS,What the f*ck JavaScript?
small steps every day - 記錄著新手村日記
完成目標 語音輸出(speech synthesis)
功能
切換不同的聲音(語系)
調整說話速度(聲調改變)
調整咬字速度
要能輸入要唸的內容
可以觸發開始講、暫停
切換聲音時,會先暫停再開始講
index_START.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Speech Synthesis</title > <link href ='https://fonts.googleapis.com/css?family=Pacifico' rel ='stylesheet' type ='text/css' > <link rel ="stylesheet" href ="style.css" > </head > <body > <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 > <script > </script > </body > </html >
JS - step by step 首先,我們先將變數中的 msg 設定 text 值,也就是聲音要講的文字內容,在抓到值之前我們可以先看一下 SpeechSynthesisUtterance
裡面存放著什麼
透過 querySelector
抓取文字方塊內的 value
,並存進到上方的 text 之中
1 msg.text = document .querySelector('[name="text"]' ).value;
這時候就可以看到原本的 SpeechSynthesisUtterance
中的 text
值已經被更新了!
1 2 3 4 5 6 7 8 9 10 11 <script> const msg = new SpeechSynthesisUtterance(); let voices = []; const voicesDropdown = document .querySelector('[name="voice"]' ); const options = document .querySelectorAll('[type="range"], [name="text"]' ); const speakButton = document .querySelector('#speak' ); const stopButton = document .querySelector('#stop' ); msg.text = document .querySelector('[name="text"]' ).value; </script>
再來我們來將 speechSynthesis
加上監聽事件 onvoiceschanged
並觸發populateVoices
方法,透過 SpeechSynthesis.getVoices()
取得包含所有物件的陣列,並將資料加入下拉式選單 Dropdown
SpeechSynthesis: voiceschanged event:https://tinyurl.com/y24evh2v
SpeechSynthesis.getVoices():https://tinyurl.com/ybxxro7q
1 2 3 4 5 6 7 8 9 10 11 <script> speechSynthesis.addEventListener('voiceschanged' , populateVoices); function populateVoices ( ) { voices = this .getVoices(); voicesDropdown.innerHTML = voices .filter(voice => voice.lang.includes('en' )) .map(voice => `<option value="${voice.name} ">${voice.name} (${voice.lang} )</option>` ) .join('' ); } </script>
接下來來將剛剛加入的下拉式選單與聲音連動起來吧!透過陣列尋找如果現在我們選擇的聲音資料與API那端的相符,就會以那個聲音觸發 toggle
方法
1 2 3 4 5 6 7 8 <script> voicesDropdown.addEventListener('change' , setVoice); function setVoice ( ) { msg.voice = voices.find(voice => voice.name === this .value); toggle(); } </script>
toogle
方法就單純許多,只是控制先執行取消發生、再執行說話
SpeechSynthesis.cancel():https://tinyurl.com/yysl5zxs
SpeechSynthesis.speak():https://tinyurl.com/yykz4obn
1 2 3 4 5 6 7 8 9 <script> function toggle (startOver = true ) { speechSynthesis.cancel(); if (startOver) { speechSynthesis.speak(msg); } } </script>
再來調整發音速度與音調的部分
1 2 3 4 5 6 7 8 9 <script> options.forEach(option => option.addEventListener('change' , setOption)); function setOption ( ) { msg[this .name] = this .value; toggle(); } </script>
最後就將按鈕觸發 click
來播放、停止說話,來控制 toggle
就可以控制說話惹w
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <script> const msg = new SpeechSynthesisUtterance(); let voices = []; const voicesDropdown = document .querySelector('[name="voice"]' ); const options = document .querySelectorAll('[type="range"], [name="text"]' ); const speakButton = document .querySelector('#speak' ); const stopButton = document .querySelector('#stop' ); msg.text = document .querySelector('[name="text"]' ).value; speechSynthesis.addEventListener('voiceschanged' , populateVoices); function populateVoices ( ) { voices = this .getVoices(); voicesDropdown.innerHTML = voices .filter(voice => voice.lang.includes('en' )) .map(voice => `<option value="${voice.name} ">${voice.name} (${voice.lang} )</option>` ) .join('' ); } voicesDropdown.addEventListener('change' , setVoice); function setVoice ( ) { msg.voice = voices.find(voice => voice.name === this .value); toggle(); } function toggle (startOver = true ) { speechSynthesis.cancel(); if (startOver) { speechSynthesis.speak(msg); } } options.forEach(option => option.addEventListener('change' , setOption)); function setOption ( ) { console .log(this .name, this .value); msg[this .name] = this .value; toggle(); } speakButton.addEventListener('click' , toggle); stopButton.addEventListener('click' , () => toggle(false )); </script>
就大功告成啦!
JS - final 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <script> const msg = new SpeechSynthesisUtterance(); let voices = []; const voicesDropdown = document .querySelector('[name="voice"]' ); const options = document .querySelectorAll('[type="range"], [name="text"]' ); const speakButton = document .querySelector('#speak' ); const stopButton = document .querySelector('#stop' ); msg.text = document .querySelector('[name="text"]' ).value; speechSynthesis.addEventListener('voiceschanged' , populateVoices); function populateVoices ( ) { voices = this .getVoices(); voicesDropdown.innerHTML = voices .filter(voice => voice.lang.includes('en' )) .map(voice => `<option value="${voice.name} ">${voice.name} (${voice.lang} )</option>` ) .join('' ); } voicesDropdown.addEventListener('change' , setVoice); function setVoice ( ) { msg.voice = voices.find(voice => voice.name === this .value); toggle(); } function toggle (startOver = true ) { speechSynthesis.cancel(); if (startOver) { speechSynthesis.speak(msg); } } options.forEach(option => option.addEventListener('change' , setOption)); function setOption ( ) { console .log(this .name, this .value); msg[this .name] = this .value; toggle(); } speakButton.addEventListener('click' , toggle); stopButton.addEventListener('click' , () => toggle(false )); </script>
本刊同步於個人網站:http://chestertang.site/
本次範例程式碼原作者來源:https://tinyurl.com/yavm5f5n