I try to realize a small web page with a javascript, that allows to playback a spechsynthesis part from text in between two mp3.
As for whatever reason the onend statement of the spoken part does not work, I wanted to create a recursive function, that helps me. For that, I use the "speaking" methode of the SpeechSynthesis. But for whatever reason, speaking is never true.
I debugged and also tried several statements (see code), but it never ever turns out to be true. Is there something with the code? Otherwise, how to report a bug of this library?
function doSpeech() {
var synth = window.speechSynthesis;
var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say.');
var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side.');
synth.speak(utterance1);
if(synth.speaking){
doNothing();
}else{
playEnd();
}
playEnd() just plays an mp3 if synth is speaking.
Please note, when I put playEnd() in the if statement, it won't play. I can put whatever code in there, it is never reached, as synth.speaking will never be true. This example is close to the example of Mozilla foundations documentation on this (https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/speaking). I wanted to test it, as the recursion never worked.
EDIT: Recursion still won't do it in my specific coding. Am I missing something here?
function doSpeech() {
var synth = window.speechSynthesis;
var speech = new SpeechSynthesisUtterance();
speech.text = getText();
speech.lang = "en-US";
speech.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == 'Google UK English Male'; })[0];
speech.addEventListener('start', function(){
speechEndLoop(synth);
});
synth.speak(speech);
}
function speechEndLoop(x) {
if (x.speaking) {
speechEndLoop(x);
} else {
playEnd();
}
}
It works perfectly, the problem is that according to your code you are verifying immediately for the status. This may be a problem because it depends on how the API is converting the text to audio (using the local text to speech of the operative system or using the google servers):
function doSpeech() {
var synth = window.speechSynthesis;
var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say. Make it longer !');
var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side. even longer !');
synth.speak(utterance1);
// If you check immediately (js code executed in less than ms) the
// status won't be true
if (synth.speaking) {
console.log("This is usually printed, if the utterance uses the default voice of the browser (native)");
}
// Wait 500ms to check for the status of the utterance
setTimeout(function(){
if (synth.speaking) {
console.log("This will be printed if starts after 500ms :)");
}
}, 500);
}
doSpeech();
In my case, both of the console.log statements are being printed. But if in your case it isn't being printed, execute your code only after the start event of the utterance:
function doSpeech() {
var synth = window.speechSynthesis;
var msg = new SpeechSynthesisUtterance();
msg.text = "We should say another sentence too, just to be on the safe side. even longer !";
msg.addEventListener('start', function () {
if(synth.speaking){
console.log("This will be printed !");
}
});
synth.speak(msg);
}
doSpeech();
Is pretty nice to work with the plain API by yourself, but if you want something more robust to solve the text to speech problem, i recommend you to use the JS Library Artyom.js, it offers a pretty nice wrapper for the Speech Synthesis API. Even with this library you will see the same behaviour:
function doSpeech() {
let assistant = new Artyom();
assistant.say('How about we say this now? This is quite a long sentence to say. Make it longer !', {
onStart: function() {
if(assistant.isSpeaking()){
console.log("This will be shown");
}
}
});
if(assistant.isSpeaking()){
console.log("This won't appear !");
}
}
doSpeech();
Related
this is my first post.
greetings to readers.
So Im fairly new to coding, and ive got this code implemented onto my frontend, a succesful scan sends a GET request to my python API to fetch data from database.. but this script scans qr code few times a second (not only that but it submits it too).
So my question is how could I slow it down a bit, lets say a timeout for 2 seconds after a succesful scan?
function onScanSuccess(decodedText, decodedResult) {
// Handle on success condition with the decoded text or result.
console.log(`Scan result: ${decodedText}`, decodedResult);
$('#search').val(decodedText);
$('#frm').submit();
}
var html5QrcodeScanner = new Html5QrcodeScanner(
"reader", { fps: 10, qrbox: 250 });
html5QrcodeScanner.render(onScanSuccess);
});
edit: I havent said I didnt write this and I have no idea how to do timeouts in Typescript or Javascript and not even where.
Im thanking you for your time :)
This is taken directly from the html5QrcodeScanner example. On success, it will update the result, and if there's no new result scanned, it wont update the result
var resultContainer = document.getElementById('qr-reader-results');
var lastResult, countResults = 0;
function onScanSuccess(decodedText, decodedResult) {
if (decodedText !== lastResult) {
++countResults;
lastResult = decodedText;
// Handle on success condition with the decoded message.
console.log(`Scan result ${decodedText}`, decodedResult);
}
}
var html5QrcodeScanner = new Html5QrcodeScanner(
"qr-reader", { fps: 10, qrbox: 250 });
html5QrcodeScanner.render(onScanSuccess);
but this wont stop your device from scanning, it just won't update the result as from my understanding of your question that would be sufficient, but if you want to stop the camera/ scanning process altogether after successful scan, you can go into a lil bit advanced part of the library
import {Html5Qrcode} from "html5-qrcode"
const html5QrCode = new Html5Qrcode("reader");
html5QrCode.stop().then((ignore) => {
// QR Code scanning is stopped.
}).catch((err) => {
// Stop failed, handle it.
});
by doing this also means that you need to implement the whole process from Pro Mode, you can refer here for pro mode
I'm a little lost as to how to make the app wait until the client has network connectivity. The consumers of the app are not expected to start the app manually (they will not be very computer literate) and the app will start up automatically on a user login to the Windows/Linux/Mac machine. In such a case, how do I ensure that during the user's session on the computer, the app starts as soon as internet connectivity is available. One option I am using is the node-main parameter provided to run a script before launch. My code for the script is :-
isOnline = require('is-online');
online = false;
window.console.log("Hello");
var a = function () {
while(online == false) {
isOnline(function(err,_online) {
online = _online;
});
}
};
a();
Hello gets logged but then my app starts loading and fails as expected due to the lack of internet connectivity. Any other ideas to implement this ?
My previous answer wouldn't work. Here's one that should, it checks for Internet connectivity every 5 seconds and only exits when there's a connection.
var isOnline = require('is-online');
process.stdout.write("Hello\n");
var check = function() {
process.stdout.write("Checking...\n");
isOnline(function(err, _online) {
if (_online) {
// If you want to invoke a script directly, do so here.
// If you want to script to exit when there's a connection,
// just don't do anything here.
process.stdout.write("Online\n");
} else {
process.stdout.write("Offline\n");
setTimeout(check, 5000);
}
})
}
check();
You can use the navigator object to check the online status:
alert(navigator.onLine);
It returns a boolean so you can easily use logic like this...
if(navigator.onLine){Proceed();} else {Whatever();}
For a quick test, if you pull out your CAT5 cable from your computer you should get a false.
You might also wanna use an async-await syntax with IIFE here:
;(async function onlineCheck() {
if(await isOnline())
run() // I enclosed all my code into a function named run.
else {
console.error("Retrying... Connection attempt falied at " + (new Date()).toString());
await onlineCheck();
}
})();
I'm playing arround with the HTML5 voice recognition.
Currently I have a function like this:
doSomething() {
listen("name");
console.log("done");
}
The "listen" Function works currently like this:
recognition = new webkitSpeechRecognition();
recognition.lang = "de-DE";
recognition.continuous = false;
//recognition.interimResults = true;
recognition.onresult = function(event) {
result = event.results[event.resultIndex];
confidence = result[0].confidence;
result = result[0].transcript.trim();
};
//TODO: remove old results, work with results
recognition.start();
What is happening is that Chrome asks for the microphone access and directly does the console.log.
What I want is for the console.log to wait until the speech recognition is done. Like this:
Chrome asks for mic access
User says something
Something is done with what the user said
the console.log and everything that follows will be executed.
How can I do that?
Thank you!
Javascript programming is event-driven. The code is not a sequence of statements to execute, but just a description of events to handle and reactions on them.
If you want to perform some action on speech recognized, you need to put it into even handler, in your case:
recognition.onresult = function(event) {
result = event.results[event.resultIndex];
confidence = result[0].confidence;
result = result[0].transcript.trim();
console.log("done")
};
You can access variables inside handler function and do more complex things.
There are many explanations of event-driven programming on the web, but the most complete one is Chapter 17 Handling Events of JavaScript: The Definitive Guide, 6th Edition
var callback = function(result){
//alert(result);
var json = eval('('+result+')');
if(json.criticalerror==true) dialogCriticalError(json.errormessage);
else{
if(json.error==true) dialogError(json.errormessage);
else{
// Do something else
}
}
};
When this callback-function is executed the "Do something else" part is called without problems. But in the case the json.error is true the dialogError-function is not executed. I've checked the transmitted JSON in Firebug. Everything is ok. The result is a JSON string as it should be.
The interesting thing is, that it actually is executed if i call the JSON-response with an alert() function at the beginning of the callback function. I'm new to JavaScript and probably missing something obvious but i just can't figure it out. Where's the bug?
EDIT:
It seems the problem is the time. If i put a 100ms delay between the JSON-result and the actual callback, everything works perfectly. But this can't be right... I'm kind of clueless.
(Oh and by the way: the communication is done by JBoss Seam Remoting)
The whole function looks like that:
function nextNode() {
var callback = function(result){
var json = JSON.parse(result);
if (json.criticalerror==true) {
dialogCriticalError(json.errormessage);
}else if (json.error==true) {
dialogError(json.errormessage);
}else {
document.getElementById('currentTree').innerHTML = json.state;
document.getElementById('countTrees').innerHTML = json.amountSteps;
document.getElementById('iframe').contentWindow.importGraph(json.tree);
document.getElementById('relevantnode').innerHTML = json.node;
createNodeBar(json);
}
};
manager.nextNode(callback);
}
The manager object is provided by the Seam Framework through the following function:
var manager = Seam.Component.getInstance("solverTreeStructure");
LAST EDIT:
Okay now i got the definite source of the problem. Its not not the Seam Remoting but the dialogError() function and the library it uses to display the dialog.
The dialogError() function looks like that:
function dialogError(error){
TINY.box.show({html:error,width:250,height:100,close:true,mask:true,opacity:20,topsplit:3})
}
It uses a small dialog library called TINYBOX. Now this library offers a variety of parameters to configure the dialog boxes. The 'mask' parameter caused all the trouble. It is resposible for darkening the background of the dialog box. If its turned on, TINYBOX needs a start-delay in order to work with the callback function. (i have NO idea why)
But for those who like riddles:
Thats the library. Its very small and clear. Unfortunately my JavaScript skills are not yet sophisticated enough to understand it.
http://www.scriptiny.com/2011/03/javascript-modal-windows/
Thats the answer. Have a nice day folks! ;)
Just a general advice: do not mix blocks with and without {}. The following form is much more readable and you can pinpoint your problem quicker.
console.log(json);
if (json.criticalerror == true) {
console.log("criticalerror");
dialogCriticalError(json.errormessage);
} else if (json.error == true) {
console.log("error");
dialogError(json.errormessage);
} else {
console.log("something else");
// Do something else
}
It seems the problem is the time. If i
put a 100ms delay between the
JSON-result and the actual callback,
everything works perfectly. But this
can't be right... I'm kind of
clueless.
Sounds like your doing asynchronous (ajax) communication. WHere is the rest of your code that asks the server for some data. Your handling the result before the server gives it to you. This explains the delay.
My coworker wrote a quick mvc chat application so we can chat about work stuff without leaving our desks.
What are some ways to indicate to each other a new message has been posted? My first thought was make the browser title bar flash. Anyone know how?
It is not possible to make the browser blink in javascript.
A possibility is to set the document title to empty an then write it again with through a period of time with setTimeout()
You could play a tone or other audio clip when a new message displays.
The nice thing about an audible cue is that you are able to keep your eyes on your work until you come to a natural break point to answer the message. Visual cues, in my opinion, are more likely to interrupt your work flow.
Obviously you can make the audible cue as pleasant and non-intrusive as your imagination allows.
This nifty function i got reserved should be handy:
It changes the title of the page to alert the user, and returns the function that will stop the interval(i.e. on a window.onmousemove listener).
function Alert(msg [, ti]) {
// msg = the message, ti= time interval between title changes(default is 1.5s)
var intervalId, oldTitle = document.title;
intervalId = setInterval(function(){
document.title = document.title == msg ? oldTitle : msg;
}, ti ? ti : 1500);
return function() {
if(oldTitle) {
clearInterval(intervalId);
document.title = oldTitle;
oldTitle = intervalId = null;
}
};
}
I've written a jQuery plugin for this purpose. See my answer to this question.