Monday, 11 November 2019

SpeechSynthesisUtterance script with play, pause, stop buttons and selection of language and voice

I would like to read the text of my pages with SpeechSynthesisUtterance.

I found this script: https://www.hongkiat.com/blog/text-to-speech/

Almost perfect, but the pause button doesn't seem to do much, and I wish I had the ability to set a language and maybe choose a voice.

I found the reference here: https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance, but I'm not very knowledgeable in javascript and I need help.

For language, as far as I understand, should be used the lang parameter set in the html tag.

For the voice I have absolutely no idea of how to implement it in the code.

It would be important because I have texts in English, Spanish, French and Italian, and the result without voice and language settings sometimes sounds really weird...


Update

These days I fiddled a little, I managed (more or less) to combine two different scripts/examples.

This: https://www.hongkiat.com/blog/text-to-speech/

and this: https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis#Examples

The code that came out is this:

HTML

<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="text-to-speech.js"></script>
</head>
<body>
<div class=buttons>
    <button id=play></button> &nbsp;
    <button id=pause></button> &nbsp;
    <button id=stop></button>
</div>
    <select id="voices">

    </select>
<div id="description">
The SpeechSynthesis interface of the Web Speech API is the controller interface for the speech service; this can be used to retrieve information about the synthesis voices available on the device, start and pause speech, and other commands besides. 
Questo รจ in italiano come viene?
</div>

</body>
</html>

CSS

@import url('https://fonts.googleapis.com/css?family=Crimson+Text');

.buttons {
    margin-top: 25px;
}

button {
    background: none;
    border: none;
    cursor: pointer;
    height: 48px;
    outline: none;
    padding: 0;
    width: 48px;
}

#play {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/play.svg);
}

#play.played {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/play1.svg);
}

#pause {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/pause.svg);
}

#pause.paused {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/pause1.svg);
}

#stop {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/stop.svg);
}

#stop.stopped {
    background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/stop1.svg);
}

JAVASCRIPT

onload = function() {
    if ('speechSynthesis' in window) with(speechSynthesis) {

// select voices////
var synth = window.speechSynthesis;

var voiceSelect = document.querySelector('#voices');

var voices = [];

function populateVoiceList() {
  voices = synth.getVoices().sort(function (a, b) {
      const aname = a.name.toUpperCase(), bname = b.name.toUpperCase();
      if ( aname < bname ) return -1;
      else if ( aname == bname ) return 0;
      else return +1;
  });
  var selectedIndex = voiceSelect.selectedIndex < 0 ? 0 : voiceSelect.selectedIndex;
  voiceSelect.innerHTML = '';
  for(i = 0; i < voices.length ; i++) {
    var option = document.createElement('option');
    option.textContent = voices[i].name + ' (' + voices[i].lang + ')';

    if(voices[i].default) {
      option.textContent += ' -- DEFAULT';
    }

    option.setAttribute('data-lang', voices[i].lang);
    option.setAttribute('data-name', voices[i].name);
    voiceSelect.appendChild(option);
  }
  voiceSelect.selectedIndex = selectedIndex;
}

populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = populateVoiceList;
}
//end select voices

        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('#description').textContent);
                //utterance.voice = getVoices()[0];

                //add voice//
                var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
                    for(i = 0; i < voices.length ; i++) {
                      //if(voices[i].name === 'Google UK English Female') {
                      if(voices[i].name === selectedOption) {
                        utterance.voice = voices[i];
                        break;
                      }
                    }


                voiceSelect.onchange = function(){
                    onClickStop();
                    stopEle.className = '';
                    onClickPlay();
                    playEle.className = 'played';
                }
                //and add voice

                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'));
    }

}

Now I have the play, stop and pause buttons (pauses still does not work) and I can select one of the voices from those available in the device.

Seems to work fine with chrome, maybe a little less with firefox, (but I'm using Linux LMDE, maybe it's my fault). And after a while on chrome stops talking ... I don't know why, but it seems to me that I've seen someone maybe understand why in some of the thousands of web pages I've opened these days, I'll have to reopen them all...

It would be nice if the selected voice was saved in a cookie, so if I open another page the script starts with the last voice I selected (I have no idea how to do it in javascript)

Javascript is not my world and I really need someone's help to combine these things correctly.



from SpeechSynthesisUtterance script with play, pause, stop buttons and selection of language and voice

No comments:

Post a Comment