I am trying out a simple example with Speechsynthesis.
<script>
voices = window.speechSynthesis.getVoices()
var utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[4];
utterance.lang = voices[4].lang;
window.speechSynthesis.speak(utterance);
</script>
But this gives an error that voices is undefined. I found that getVoices() is loaded async. I saw this answer and updated my code as shown below to use callback.
<script>
window.speechSynthesis.onvoiceschanged = function() {
voices = window.speechSynthesis.getVoices()
var utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[4];
utterance.lang = voices[4].lang;
window.speechSynthesis.speak(utterance);
};
</script>
But due to some strange reason, the text is spoken three times instead of one. How can I fix this code?
I am trying out a simple example with Speechsynthesis.
<script>
voices = window.speechSynthesis.getVoices()
var utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[4];
utterance.lang = voices[4].lang;
window.speechSynthesis.speak(utterance);
</script>
But this gives an error that voices is undefined. I found that getVoices() is loaded async. I saw this answer and updated my code as shown below to use callback.
<script>
window.speechSynthesis.onvoiceschanged = function() {
voices = window.speechSynthesis.getVoices()
var utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[4];
utterance.lang = voices[4].lang;
window.speechSynthesis.speak(utterance);
};
</script>
But due to some strange reason, the text is spoken three times instead of one. How can I fix this code?
Share Improve this question edited May 23, 2017 at 11:47 CommunityBot 11 silver badge asked Mar 9, 2017 at 11:46 codingsplashcodingsplash 5,04512 gold badges54 silver badges92 bronze badges4 Answers
Reset to default 6I can't replicate your issue, but try adding an event listener so that your function runs after the voices are loaded.
let voices, utterance;
function speakVoice() {
voices = this.getVoices();
utterance = new SpeechSynthesisUtterance("Hello World");
utterance.voice = voices[1];
speechSynthesis.speak(utterance);
};
speechSynthesis.addEventListener('voiceschanged', speakVoice);
This can be seen on many JS Bin-type demos. For examples:
http://jsbin.com/sazuca/1/edit?html,css,js,output
https://codepen.io/matt-west/pen/wGzuJ
This behaviour is seen in Chrome, which uses the voiceschanged event, when a non-local voice is used. Another effect is that the list of voices is often triplicated.
The W3C specification says:
voiceschanged event
Fired when the contents of the SpeechSynthesisVoiceList, that the getVoices method will return, have changed. Examples include: server-side synthesis where the list is determined asynchronously, or when client-side voices are installed/uninstalled.
...so I presume that the event is fired once when Chrome gets the voices and then twice more when the first non-local voice is used.
Given that there doesn't seem to be a way to distinguish which change is triggering the event I have been using this ugly bit of code:
// Add voices to dropdown list
loadVoices();
// For browsers that use voiceschanged event
speechSynthesis.onvoiceschanged = function(e) {
// Load the voices into the dropdown
loadVoices();
// Don't add more options when voiceschanged again
speechSynthesis.onvoiceschanged = null;
}
Where loadVoices() is the function that adds the voices to a selection's options. It's not ideal, however it does work on all browsers (with speech synthesis) whether they use onvoiceschanged or not.
Faced the same problem just now & the solution is pretty easy. Just declare the voices globally not just inside the onclick function & do it two times
utterance.voice = window.speechSynthesis.getVoices()[Math.floor(Math.random()*6)]
setTimeout(() => {
utterance.voice = window.speechSynthesis.getVoices()[Math.floor(Math.random()*6)]
}, 1000)
The Utterance is variable containing speechSynthesisisUtterance()
The Brave browser only supports 6 types of voices as compared to 24 of chrome, that's why I choose any random voice b/w 1-6.
You can simply add this code and use SpeechSynthesis in your project, it works for me.
var su;
su = new SpeechSynthesisUtterance();
su.text = "Hello World";
speechSynthesis.speak(su);
speechSynthesis.cancel();