Reputation: 63
Good day.
I'm having trouble with inconsistencies of my speech synthesis speaking long texts.
I'm trying to make text-to-speech in English and Mandarin. When I specify utterance.lang = 'en-US'; I found out that my article in English is read out until finished. However, when I'm using utterance.lang = 'zh-CN'; my text in English and Mandarin can only read out until 30 words only. I don't know if there's a problem with coding or anything.
The article:
E. Cyclocarpum
Enterolobium cyclocarpum, commonly known as guanacaste, caro caro, or elephant-ear tree, is a species of flowering tree in the pea family. Fabaceae, that is native to tropical regions of the Americas, from the central Mexico south to northern Brazil (Roraima) and Venezuela. It is known for its large proportions, its expansive, often spherical crown, and its curiously shaped seedpods. The abundance of this tree, especially in Guanacaste Province, Costa Rica, where it is prized for the shady relief it provides from the intense sun, coupled with its immensity, have made it a widely recognized species. It is the national tree of Costa Rica.
onload = function() {
if ('speechSynthesis' in window) with(speechSynthesis) {
var playEle = document.querySelector('#play');
var pauseEle = document.querySelector('#pause');
var stopEle = document.querySelector('#stop');
var flag = false;
playEle.addEventListener('click', onClickPlay);
pauseEle.addEventListener('click', onClickPause);
stopEle.addEventListener('click', onClickStop);
function onClickPlay() {
if(!flag){
flag = true;
utterance = new SpeechSynthesisUtterance(document.querySelector('article').textContent);
utterance.lang = 'zh-CN';
utterance.onend = function(){
flag = false; playEle.className = pauseEle.className = ''; stopEle.className = 'stopped';
};
playEle.className = 'played';
stopEle.className = '';
speak(utterance);
}
if (paused) { /* unpause/resume narration */
playEle.className = 'played';
pauseEle.className = '';
resume();
}
}
function onClickPause() {
if(speaking && !paused){ /* pause narration */
pauseEle.className = 'paused';
playEle.className = '';
pause();
}
}
function onClickStop() {
if(speaking){ /* stop narration */
/* for safari */
stopEle.className = 'stopped';
playEle.className = pauseEle.className = '';
flag = false;
cancel();
}
}
}
else { /* speech synthesis not supported */
msg = document.createElement('h5');
msg.textContent = "Detected no support for Speech Synthesis";
msg.style.textAlign = 'center';
msg.style.backgroundColor = 'red';
msg.style.color = 'white';
msg.style.marginTop = msg.style.marginBottom = 0;
document.body.insertBefore(msg, document.querySelector('div'));
}
}
Upvotes: 5
Views: 2672
Reputation: 131
I've recently stumbled upon the issue where speech is cut off after a duration of 14(?) seconds as well. This causes for the synthesis to get stuck in 'speaking' mode, never marking it as done and thus never actually being able to check when it finishes talking. This also makes for all speech-synth options to be blocked until you restart your browser.
This bug only seems to happen when you use the promise options to fetch the voices and languages. If you don't need to option to select and just pre-set them, it seems to be working as should (at least for me).
The solution of Frazer didn't work for me until I also added a pause right before the resume to make it stop for a very short moment and then continue. This cancels the "max 14-second" bug.
With this small tweak added, the code from Frazer would look like:
let r = setInterval(() => {
console.log(speechSynthesis.speaking);
if (!speechSynthesis.speaking) {
clearInterval(r);
} else {
speechSynthesis.pause();
speechSynthesis.resume();
}
}, 14000);
Upvotes: 13
Reputation: 1089
It's a known bug. The workaround is to issue a resume every 14 seconds.
For your code this means to add the following after 'speak(utterance)':
let r = setInterval(() => {
console.log(speechSynthesis.speaking);
if (!speechSynthesis.speaking) {
clearInterval(r);
} else {
speechSynthesis.resume();
}
}, 14000);
Upvotes: 12