Search code examples
javascripttext-to-speechspeech-synthesis

how to fix Speech Synthesis Utterance in javascript


When ever i run this code i get a female response and then the second time i get a male voice and if i try to run it again it fails to respond.

here is the code/

var aiload = document.getElementById('ai').innerHTML
var msg = new SpeechSynthesisUtterance(aiload);
var voices = window.speechSynthesis.getVoices();

voices.forEach(function (voice, i) {
    var voiceName = 'Google UK English Female';
    var selected = '';

    if(voiceName == 'native') {
        selected = 'selected';
    }
    var option = "<option value='" + voiceName + "' " + selected + " >" + voiceName + "</option>";
    voiceSelect.append(option);
    console.log(voiceName);
});

msg.volume = 1; // 0 to 1
msg.rate = 1; // 0.1 to 10
msg.pitch = 0; //0 to 2
msg.text = aiload;
msg.lang = 'en-US';

msg.onend = function(e) {
    console.log('Finished in ' + event.elapsedTime + ' seconds.');
};


speechSynthesis.speak(msg);

Solution

  • Your problem seems to be not treating the Web Speech API asynchronously.

    The following snippet is not needed for now, but I want to point out that it looks like you never change the voiceName variable anywhere so the if statement looks unnecessary:

    voices.forEach(function (voice, i) {
        var voiceName = 'Google UK English Female';
        var selected = '';
    
        if(voiceName == 'native') {
            selected = 'selected';
        }
        var option = "<option value='" + voiceName + "' " + selected + " >" + voiceName + "</option>";
        voiceSelect.append(option);
        console.log(voiceName);
    });
    

    Here's one way you'll get the voice you want every time (notice my changes with comments):

    var aiload = document.getElementById('ai').innerHTML;
    
    // Use setInterval to keep checking if the voices array has been filled prior to creating the speech utterance
    var voiceGetter = setInterval(function() {
      var voices = window.speechSynthesis.getVoices();
      if (voices.length !== 0) {
        var msg = new SpeechSynthesisUtterance(aiload);
        // Pick any voice from within the array; you can console.log(voices) to see options
        msg.voice = voices[5];
        msg.volume = 1;
        msg.rate = 1;
        msg.pitch = 0;
        // msg.text = aiload; <== This is redundant because of how msg is defined
        msg.lang = 'en-US';
        msg.onend = function(e) {
            console.log('Finished in ' + event.elapsedTime + ' seconds.');
        };
        speechSynthesis.speak(msg);
        clearInterval(voiceGetter);
      }
    }, 200)