• 0
Votes
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /var/www/html/cnasolution/site/application/views/question.php
Line: 191
Function: _error_handler

File: /var/www/html/cnasolution/site/application/controllers/Questions.php
Line: 419
Function: view

File: /var/www/html/cnasolution/site/index.php
Line: 315
Function: require_once

Related to this text to speech question, I have the following code:

First of all, I am not sure if this is the best way to write the code, because it is initializing, and then setting a listener to "call itself". (seems a little bit hacky).

Second, although the listeners got "notified", the voices.length is still 0. Nothing really happens with an array of voices. I had to uncomment this line:

// voices = synth.getVoices();   // this line should not be needed 

so that it can come back with an array of voices, but even so, the first word was not pronounced. Why does synth.getVoices() need to be called twice, and why did the first word not get pronounced? It would appear you only have to call synth.getVoices() once.

Note that if you try it as a snippet, no voice will be given out (due to iframe or security reasons? To hear something, the code needs to run in developer's console).

(one note when I was debugging: if all the voices were obtained, and the last 3 lines were run again, the second and third line became the same. It looks like some kind of "speech end" event needs to be listened to, to serialize them one by one -- maybe using a promise or async function. But then further debugging showed that it seemed a new instance of SpeechSynthesisUtterance is needed each time, so I moved the let msg = new SpeechSynthesisUtterance(); to inside of the last else { } and running those 3 lines have no problem).

So let me hide the original snippet:

let msg, synth, voices;    function foo(phrase) {    if (!voices) {      msg = new SpeechSynthesisUtterance();      synth = window.speechSynthesis;      voices = synth.getVoices();        console.log("Waiting 01", voices);      synth.addEventListener('voiceschanged', function() {        foo(phrase);      });    } else if (voices.length === 0) {      // this section is needed if foo() is called twice or multiple times in a row initially        console.log("Waiting 02", voices);        // voices = synth.getVoices();   // this line should not be needed      synth.addEventListener('voiceschanged', function() {        foo(phrase);      });    } else {      console.log("How many voices", voices.length);        // the voices are ready and could be changed here,      // but since each system is different, so it won't be      // changed here:      // msg.voice = voices[0];      msg.text = phrase;      synth.speak(msg);    }  }    foo("Hello");  foo("World");  foo("a third line");

and show the improved version (which still has the same problem):

let msg, synth, voices;    function foo(phrase) {    if (!voices) {      synth = window.speechSynthesis;      voices = synth.getVoices();        console.log("Waiting 01", voices);      synth.addEventListener('voiceschanged', function() {        foo(phrase);      });    } else if (voices.length === 0) {      // this section is needed if foo() is called twice or multiple times in a row initially.      // synth.getVoices() has been called and we shouldn't need to call it again.      // but if voices.length is still 0 we just again listen on the voiceschanged event and when ready, call foo(phrase)        console.log("Waiting 02", voices);        // voices = synth.getVoices();   // this line should not be needed      synth.addEventListener('voiceschanged', function() {        foo(phrase);      });    } else {      let msg = new SpeechSynthesisUtterance();        console.log("How many voices", voices.length);        // the voices are ready and could be changed here,      // but since each system is different, so it won't be      // changed here:      // msg.voice = voices[0];      msg.text = phrase;      synth.speak(msg);    }  }    foo("Hello");  foo("World");  foo("a third line");

Download script demo [LINK] [Origin]
Download script demo [LINK 2] [Onedrive] Download script demo [LINK 2] [Google drive]

OK, I think I found the issue.

The issue is with voices = synth.getVoices();

That's the recommended way to get the voices in the sample code, but note that in similar situation for event driven or "future value" or promise programming, the value is not there. It is in the future, possibly in the event object, or provided to the callback (provided to the handler or the "listener" or "observer"). (Or we might think, voices is an array. Can't it just get populated? The answer seems like a "no" in this case.)

In this case, the event doesn't seem to have it. So we need to call voices = synth.getVoices(); again when the handler gets called, so the code becomes:

let msg, synth, voices;    function foo(phrase) {    if (!voices) {      synth = window.speechSynthesis;      synth.getVoices();      voices = synth.getVoices();        console.log("Waiting 01", voices);      synth.addEventListener('voiceschanged', function(ev) {        console.log("Done Waiting 01", voices, ev);        voices = synth.getVoices();        // <---------- this is important        foo(phrase);      });    } else if (voices.length === 0) {      // this section is needed if foo() is called twice or multiple times in a row initially        console.log("Waiting 02", voices);        synth.addEventListener('voiceschanged', function() {        foo(phrase);      });    } else {      let msg = new SpeechSynthesisUtterance();         console.log("How many voices", voices.length);        // the voices are ready and could be changed here,      // but since each system is different, so it won't be      // changed here:      // msg.voice = voices[0];      msg.text = phrase;      synth.speak(msg);    }  }    foo("Hello");  foo("World");  foo("a third line");

We might even not use voices = synth.getVoices(); the very first time, and just use voices = []; synth.getVoices(); because if we set it to synth.getVoices(), other coders reading the code might have some expectation that it will get populated.

see demo
  • 0
Reply Report

This is really interesting indeed. Seems that the first condition is the reason why the first line doesn't played. Still reading the docs and play with the code, so i don't quite know why this works, but maybe this will help:

 
demo
  • 0
Reply Report