Play sound ONLY ONCE - javascript

I'm making a small asteroid avoiding game and when my lives are over I'm executing the following code:
gameover.play();
while gameover is defined like so:
var gameover = new Audio('gameover.wav');
When I execute the code, it loops the sound and I want to play it just once, how would I do that? Thanks.

I believe setting the loop property to false will accomplish your goal.
var birdSound = new Audio('http://www.noiseaddicts.com/samples_1w72b820/4929.mp3');
birdSound.loop = false;
birdSound.play();
var birdSound = new Audio('http://www.noiseaddicts.com/samples_1w72b820/4929.mp3');
birdSound.loop = false;
birdSound.play();
var statusElem = document.getElementById('status');
var startTime = Date.now();
updateStatus();
function updateStatus(){
if (birdSound.ended){
statusElem.innerText = 'Stopped';
} else {
statusElem.innerText = 'Playing (' + ( ( Date.now() - startTime ) / 1000 ) + ')';
window.setTimeout(updateStatus, 50);
}
}
Audio Status: <span id="status">Playing</span>
Tested in:
Chrome 44.0.2403.155 (64-bit)
Firefox 40.0.2
Safari 8.0.6
Vivaldi 1.0.94.2 (for giggles)

Related

Start running SpeechSynthesis API on my Android and Safari devices

I'm trying to make a web app with the SpeechSynthesis API to run my program after one click on start button and then start listening to the user on my Android and iOS devices. The user could speak anything to run the program. After that, I can play my audio files every three seconds. Below is my code so far. Is my logic wrong? I can't start my program after the click and hear any sound.
Another question is this SpeechSynthesis API could support Android and iOS devices, but when I saw some event such as 'soundstart event', it doesn't support Safari Mobile. What are their relationships? I got really confused. And the SpeechRecognition API only supports for Chrome browser but don't I need to user some event like soundstart?
Thank you for help in advance. I really appreciate it.
<p id="msg" align="center"></p>
<script>
var utterance = new SpeechSynthesisUtterance("Hello");
//window.speechSynthesis.speak(utterance);
var supportMsg = document.getElementById('msg');
if ('speechSynthesis' in window)
{
supportMsg.innerHTML = 'Your browser <strong>supports</strong> speech synthesis.';
console.log("Hi");
utterance.onstart = function(event)
{
console.log('Hhhh')
};
var playList = ["1_hello", "2_how_old", "3_what_did_you_make"];
var dir = "sound/";
var extention = ".wav";
audio.src = dir + playList[audioIndex] + extention;
audio.load();
var audioIndex = 0;
setTimeout(function(){audio.play();}, 1000);
window.speechSynthesis.speak(utterance);
}
else
{
supportMsg.innerHTML = 'Sorry your browser <strong>does not support</strong> speech synthesis.<br>Try this in Chrome Canary.';
}
//window.speechSynthesis(utterance);
</script>
<div class="container">
<button id="runProgram" onclick='utterance.onstart();'
class="runProgram-button">Start</button>
</div>
Does this work for you?
function playAudio() {
var msg = new SpeechSynthesisUtterance('Help me with this code please?');
msg.pitch = 0;
msg.rate = .6;
window.speechSynthesis.speak(msg);
var msg = new SpeechSynthesisUtterance();
var voices = window.speechSynthesis.getVoices();
msg.voice = voices[10]; // Note: some voices don't support altering params
msg.voiceURI = 'native';
msg.volume = 1; // 0 to 1
msg.rate = 1.2; // 0.1 to 10
msg.pitch = 2; //0 to 2
msg.text = 'Sure. This code plays "Hello World" for you';
msg.lang = 'en-US';
msg.onend = function(e) {
var msg1 = new SpeechSynthesisUtterance('Now code plays audios for you');
msg1.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == 'Whisper'; })[0];
msg1.pitch = 2; //0 to 2
msg1.rate= 1.2; //0 to 2
// start your audio loop.
speechSynthesis.speak(msg1);
console.log('Finished in ' + e.elapsedTime + ' seconds.');
};
speechSynthesis.speak(msg);
}
<div class="container">
<button id="runProgram" onclick='playAudio();' class="runProgram-button">Start</button>
</div>

Download speed using php [duplicate]

How can I create a JavaScript page that will detect the user’s internet speed and show it on the page? Something like “your internet speed is ??/?? Kb/s”.
It's possible to some extent but won't be really accurate, the idea is load image with a known file size then in its onload event measure how much time passed until that event was triggered, and divide this time in the image file size.
Example can be found here: Calculate speed using javascript
Test case applying the fix suggested there:
//JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
var imageAddr = "http://www.kenrockwell.com/contax/images/g2/examples/31120037-5mb.jpg";
var downloadSize = 4995374; //bytes
function ShowProgressMessage(msg) {
if (console) {
if (typeof msg == "string") {
console.log(msg);
} else {
for (var i = 0; i < msg.length; i++) {
console.log(msg[i]);
}
}
}
var oProgress = document.getElementById("progress");
if (oProgress) {
var actualHTML = (typeof msg == "string") ? msg : msg.join("<br />");
oProgress.innerHTML = actualHTML;
}
}
function InitiateSpeedDetection() {
ShowProgressMessage("Loading the image, please wait...");
window.setTimeout(MeasureConnectionSpeed, 1);
};
if (window.addEventListener) {
window.addEventListener('load', InitiateSpeedDetection, false);
} else if (window.attachEvent) {
window.attachEvent('onload', InitiateSpeedDetection);
}
function MeasureConnectionSpeed() {
var startTime, endTime;
var download = new Image();
download.onload = function () {
endTime = (new Date()).getTime();
showResults();
}
download.onerror = function (err, msg) {
ShowProgressMessage("Invalid image, or error downloading");
}
startTime = (new Date()).getTime();
var cacheBuster = "?nnn=" + startTime;
download.src = imageAddr + cacheBuster;
function showResults() {
var duration = (endTime - startTime) / 1000;
var bitsLoaded = downloadSize * 8;
var speedBps = (bitsLoaded / duration).toFixed(2);
var speedKbps = (speedBps / 1024).toFixed(2);
var speedMbps = (speedKbps / 1024).toFixed(2);
ShowProgressMessage([
"Your connection speed is:",
speedBps + " bps",
speedKbps + " kbps",
speedMbps + " Mbps"
]);
}
}
<h1 id="progress">JavaScript is turned off, or your browser is realllllly slow</h1>
Quick comparison with "real" speed test service showed small difference of 0.12 Mbps when using big picture.
To ensure the integrity of the test, you can run the code with Chrome dev tool throttling enabled and then see if the result matches the limitation. (credit goes to user284130 :))
Important things to keep in mind:
The image being used should be properly optimized and compressed. If it isn't, then default compression on connections by the web server might show speed bigger than it actually is. Another option is using uncompressible file format, e.g. jpg. (thanks Rauli Rajande for pointing this out and Fluxine for reminding me)
The cache buster mechanism described above might not work with some CDN servers, which can be configured to ignore query string parameters, hence better setting cache control headers on the image itself. (thanks orcaman for pointing this out))
The bigger the image size is, the better. Larger image will make the test more accurate, 5 mb is decent, but if you can use even a bigger one it would be better.
Well, this is 2017 so you now have Network Information API (albeit with a limited support across browsers as of now) to get some sort of estimate downlink speed information:
navigator.connection.downlink
This is effective bandwidth estimate in Mbits per sec. The browser makes this estimate from recently observed application layer throughput across recently active connections. Needless to say, the biggest advantage of this approach is that you need not download any content just for bandwidth/ speed calculation.
You can look at this and a couple of other related attributes here
Due to it's limited support and different implementations across browsers (as of Nov 2017), would strongly recommend read this in detail
I needed a quick way to determine if the user connection speed was fast enough to enable/disable some features in a site I’m working on, I made this little script that averages the time it takes to download a single (small) image a number of times, it's working pretty accurately in my tests, being able to clearly distinguish between 3G or Wi-Fi for example, maybe someone can make a more elegant version or even a jQuery plugin.
var arrTimes = [];
var i = 0; // start
var timesToTest = 5;
var tThreshold = 150; //ms
var testImage = "http://www.google.com/images/phd/px.gif"; // small image in your server
var dummyImage = new Image();
var isConnectedFast = false;
testLatency(function(avg){
isConnectedFast = (avg <= tThreshold);
/** output */
document.body.appendChild(
document.createTextNode("Time: " + (avg.toFixed(2)) + "ms - isConnectedFast? " + isConnectedFast)
);
});
/** test and average time took to download image from server, called recursively timesToTest times */
function testLatency(cb) {
var tStart = new Date().getTime();
if (i<timesToTest-1) {
dummyImage.src = testImage + '?t=' + tStart;
dummyImage.onload = function() {
var tEnd = new Date().getTime();
var tTimeTook = tEnd-tStart;
arrTimes[i] = tTimeTook;
testLatency(cb);
i++;
};
} else {
/** calculate average of array items then callback */
var sum = arrTimes.reduce(function(a, b) { return a + b; });
var avg = sum / arrTimes.length;
cb(avg);
}
}
As I outline in this other answer here on StackOverflow, you can do this by timing the download of files of various sizes (start small, ramp up if the connection seems to allow it), ensuring through cache headers and such that the file is really being read from the remote server and not being retrieved from cache. This doesn't necessarily require that you have a server of your own (the files could be coming from S3 or similar), but you will need somewhere to get the files from in order to test connection speed.
That said, point-in-time bandwidth tests are notoriously unreliable, being as they are impacted by other items being downloaded in other windows, the speed of your server, links en route, etc., etc. But you can get a rough idea using this sort of technique.
Even though this is old and answered, i´d like to share the solution i made out of it 2020 base on Shadow Wizard Says No More War´s solution
I just merged it into an object that comes with the flexibility to run at anytime and run a callbacks if the specified mbps is higher or lower the measurement result.
you can start the test anywhere after you included the testConnectionSpeed Object by running the
/**
* #param float mbps - Specify a limit of mbps.
* #param function more(float result) - Called if more mbps than specified limit.
* #param function less(float result) - Called if less mbps than specified limit.
*/
testConnectionSpeed.run(mbps, more, less)
for example:
var testConnectionSpeed = {
imageAddr : "https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg", // this is just an example, you rather want an image hosted on your server
downloadSize : 2707459, // Must match the file above (from your server ideally)
run:function(mbps_max,cb_gt,cb_lt){
testConnectionSpeed.mbps_max = parseFloat(mbps_max) ? parseFloat(mbps_max) : 0;
testConnectionSpeed.cb_gt = cb_gt;
testConnectionSpeed.cb_lt = cb_lt;
testConnectionSpeed.InitiateSpeedDetection();
},
InitiateSpeedDetection: function() {
window.setTimeout(testConnectionSpeed.MeasureConnectionSpeed, 1);
},
result:function(){
var duration = (endTime - startTime) / 1000;
var bitsLoaded = testConnectionSpeed.downloadSize * 8;
var speedBps = (bitsLoaded / duration).toFixed(2);
var speedKbps = (speedBps / 1024).toFixed(2);
var speedMbps = (speedKbps / 1024).toFixed(2);
if(speedMbps >= (testConnectionSpeed.max_mbps ? testConnectionSpeed.max_mbps : 1) ){
testConnectionSpeed.cb_gt ? testConnectionSpeed.cb_gt(speedMbps) : false;
}else {
testConnectionSpeed.cb_lt ? testConnectionSpeed.cb_lt(speedMbps) : false;
}
},
MeasureConnectionSpeed:function() {
var download = new Image();
download.onload = function () {
endTime = (new Date()).getTime();
testConnectionSpeed.result();
}
startTime = (new Date()).getTime();
var cacheBuster = "?nnn=" + startTime;
download.src = testConnectionSpeed.imageAddr + cacheBuster;
}
}
// start test immediatly, you could also call this on any event or whenever you want
testConnectionSpeed.run(1.5, function(mbps){console.log(">= 1.5Mbps ("+mbps+"Mbps)")}, function(mbps){console.log("< 1.5Mbps("+mbps+"Mbps)")} )
I used this successfuly to load lowres media for slow internet connections. You have to play around a bit because on the one hand, the larger the image, the more reasonable the test, on the other hand the test will take way much longer for slow connection and in my case I especially did not want slow connection users to load lots of MBs.
The image trick is cool but in my tests it was loading before some ajax calls I wanted to be complete.
The proper solution in 2017 is to use a worker (http://caniuse.com/#feat=webworkers).
The worker will look like:
/**
* This function performs a synchronous request
* and returns an object contain informations about the download
* time and size
*/
function measure(filename) {
var xhr = new XMLHttpRequest();
var measure = {};
xhr.open("GET", filename + '?' + (new Date()).getTime(), false);
measure.start = (new Date()).getTime();
xhr.send(null);
measure.end = (new Date()).getTime();
measure.len = parseInt(xhr.getResponseHeader('Content-Length') || 0);
measure.delta = measure.end - measure.start;
return measure;
}
/**
* Requires that we pass a base url to the worker
* The worker will measure the download time needed to get
* a ~0KB and a 100KB.
* It will return a string that serializes this informations as
* pipe separated values
*/
onmessage = function(e) {
measure0 = measure(e.data.base_url + '/test/0.bz2');
measure100 = measure(e.data.base_url + '/test/100K.bz2');
postMessage(
measure0.delta + '|' +
measure0.len + '|' +
measure100.delta + '|' +
measure100.len
);
};
The js file that will invoke the Worker:
var base_url = PORTAL_URL + '/++plone++experimental.bwtools';
if (typeof(Worker) === 'undefined') {
return; // unsupported
}
w = new Worker(base_url + "/scripts/worker.js");
w.postMessage({
base_url: base_url
});
w.onmessage = function(event) {
if (event.data) {
set_cookie(event.data);
}
};
Code taken from a Plone package I wrote:
https://github.com/collective/experimental.bwtools/blob/master/src/experimental/bwtools/browser/static/scripts/
It's better to use images for testing the speed. But if you have to deal with zip files, the below code works.
var fileURL = "your/url/here/testfile.zip";
var request = new XMLHttpRequest();
var avoidCache = "?avoidcache=" + (new Date()).getTime();;
request.open('GET', fileURL + avoidCache, true);
request.responseType = "application/zip";
var startTime = (new Date()).getTime();
var endTime = startTime;
request.onreadystatechange = function () {
if (request.readyState == 2)
{
//ready state 2 is when the request is sent
startTime = (new Date().getTime());
}
if (request.readyState == 4)
{
endTime = (new Date()).getTime();
var downloadSize = request.responseText.length;
var time = (endTime - startTime) / 1000;
var sizeInBits = downloadSize * 8;
var speed = ((sizeInBits / time) / (1024 * 1024)).toFixed(2);
console.log(downloadSize, time, speed);
}
}
request.send();
This will not work very well with files < 10MB. You will have to run aggregated results on multiple download attempts.
thanks to Punit S answer, for detecting dynamic connection speed change, you can use the following code :
navigator.connection.onchange = function () {
//do what you need to do ,on speed change event
console.log('Connection Speed Changed');
}
Improving upon John Smith's answer, a nice and clean solution which returns a Promise and thus can be used with async/await. Returns a value in Mbps.
const imageAddr = 'https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg';
const downloadSize = 2707459; // this must match with the image above
let startTime, endTime;
async function measureConnectionSpeed() {
startTime = (new Date()).getTime();
const cacheBuster = '?nnn=' + startTime;
const download = new Image();
download.src = imageAddr + cacheBuster;
// this returns when the image is finished downloading
await download.decode();
endTime = (new Date()).getTime();
const duration = (endTime - startTime) / 1000;
const bitsLoaded = downloadSize * 8;
const speedBps = (bitsLoaded / duration).toFixed(2);
const speedKbps = (speedBps / 1024).toFixed(2);
const speedMbps = (speedKbps / 1024).toFixed(2);
return Math.round(Number(speedMbps));
}
I needed something similar, so I wrote https://github.com/beradrian/jsbandwidth. This is a rewrite of https://code.google.com/p/jsbandwidth/.
The idea is to make two calls through Ajax, one to download and the other to upload through POST.
It should work with both jQuery.ajax or Angular $http.
//JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
var imageAddr = "https://i.ibb.co/sPbbkkZ/pexels-lisa-1540258.jpg";
var downloadSize = 10500000; //bytes
function ShowProgressMessage(msg) {
if (console) {
if (typeof msg == "string") {
console.log(msg);
} else {
for (var i = 0; i < msg.length; i++) {
console.log(msg[i]);
}
}
}
var oProgress = document.getElementById("progress");
if (oProgress) {
var actualHTML = (typeof msg == "string") ? msg : msg.join("<br />");
oProgress.innerHTML = actualHTML;
}
}
function InitiateSpeedDetection() {
ShowProgressMessage("Loading the image, please wait...");
window.setTimeout(MeasureConnectionSpeed, 1);
};
if (window.addEventListener) {
window.addEventListener('load', InitiateSpeedDetection, false);
} else if (window.attachEvent) {
window.attachEvent('onload', InitiateSpeedDetection);
}
function MeasureConnectionSpeed() {
var startTime, endTime;
var download = new Image();
download.onload = function () {
endTime = (new Date()).getTime();
showResults();
}
download.onerror = function (err, msg) {
ShowProgressMessage("Invalid image, or error downloading");
}
startTime = (new Date()).getTime();
var cacheBuster = "?nnn=" + startTime;
download.src = imageAddr + cacheBuster;
function showResults() {
var duration = (endTime - startTime) / 1000;
var bitsLoaded = downloadSize * 8;
var speedBps = (bitsLoaded / duration).toFixed(2);
var speedKbps = (speedBps / 1024).toFixed(2);
var speedMbps = (speedKbps / 1024).toFixed(2);
ShowProgressMessage([
"Your connection speed is:",
speedBps + " bps",
speedKbps + " kbps",
speedMbps + " Mbps"
]);
}
}
<h1 id="progress">JavaScript is turned off, or your browser is realllllly slow</h1>
Mini snippet:
var speedtest = {};
function speedTest_start(name) { speedtest[name]= +new Date(); }
function speedTest_stop(name) { return +new Date() - speedtest[name] + (delete
speedtest[name]?0:0); }
use like:
speedTest_start("test1");
// ... some code
speedTest_stop("test1");
// returns the time duration in ms
Also more tests possible:
speedTest_start("whole");
// ... some code
speedTest_start("part");
// ... some code
speedTest_stop("part");
// returns the time duration in ms of "part"
// ... some code
speedTest_stop("whole");
// returns the time duration in ms of "whole"

Html5 & JavaScript Text to Speech conversion [duplicate]

I am getting a problem when trying to use Speech Synthesis API in Chrome 33. It works perfectly with a shorter text, but if I try longer text, it just stops in the middle. After it has stopped once like that, the Speech Synthesis does not work anywhere within Chrome until the browser is restarted.
Example code (http://jsfiddle.net/Mdm47/1/):
function speak(text) {
var msg = new SpeechSynthesisUtterance();
var voices = speechSynthesis.getVoices();
msg.voice = voices[10];
msg.voiceURI = 'native';
msg.volume = 1;
msg.rate = 1;
msg.pitch = 2;
msg.text = text;
msg.lang = 'en-US';
speechSynthesis.speak(msg);
}
speak('Short text');
speak('Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without revolutionary ROI. Efficiently unleash cross-media information without cross-media value. Quickly maximize timely deliverables for real-time schemas. Dramatically maintain clicks-and-mortar solutions without functional solutions.');
speak('Another short text');
It stops speaking in the middle of the second text, and I can't get any other page to speak after that.
Is it a browser bug or some kind of security limitation?
I've had this issue for a while now with Google Chrome Speech Synthesis. After some investigation, I discovered the following:
The breaking of the utterances only happens when the voice is not a native voice,
The cutting out usually occurs between 200-300 characters,
When it does break you can un-freeze it by doing speechSynthesis.cancel();
The 'onend' event sometimes decides not to fire. A quirky work-around to this is to console.log() out the utterance object before speaking it. Also I found wrapping the speak invocation in a setTimeout callback helps smooth these issues out.
In response to these problems, I have written a function that overcomes the character limit, by chunking the text up into smaller utterances, and playing them one after another. Obviously you'll get some odd sounds sometimes as sentences might be chunked into two separate utterances with a small time delay in between each, however the code will try and split these points at punctuation marks as to make the breaks in sound less obvious.
Update
I've made this work-around publicly available at https://gist.github.com/woollsta/2d146f13878a301b36d7#file-chunkify-js. Many thanks to Brett Zamir for his contributions.
The function:
var speechUtteranceChunker = function (utt, settings, callback) {
settings = settings || {};
var newUtt;
var txt = (settings && settings.offset !== undefined ? utt.text.substring(settings.offset) : utt.text);
if (utt.voice && utt.voice.voiceURI === 'native') { // Not part of the spec
newUtt = utt;
newUtt.text = txt;
newUtt.addEventListener('end', function () {
if (speechUtteranceChunker.cancel) {
speechUtteranceChunker.cancel = false;
}
if (callback !== undefined) {
callback();
}
});
}
else {
var chunkLength = (settings && settings.chunkLength) || 160;
var pattRegex = new RegExp('^[\\s\\S]{' + Math.floor(chunkLength / 2) + ',' + chunkLength + '}[.!?,]{1}|^[\\s\\S]{1,' + chunkLength + '}$|^[\\s\\S]{1,' + chunkLength + '} ');
var chunkArr = txt.match(pattRegex);
if (chunkArr[0] === undefined || chunkArr[0].length <= 2) {
//call once all text has been spoken...
if (callback !== undefined) {
callback();
}
return;
}
var chunk = chunkArr[0];
newUtt = new SpeechSynthesisUtterance(chunk);
var x;
for (x in utt) {
if (utt.hasOwnProperty(x) && x !== 'text') {
newUtt[x] = utt[x];
}
}
newUtt.addEventListener('end', function () {
if (speechUtteranceChunker.cancel) {
speechUtteranceChunker.cancel = false;
return;
}
settings.offset = settings.offset || 0;
settings.offset += chunk.length - 1;
speechUtteranceChunker(utt, settings, callback);
});
}
if (settings.modifier) {
settings.modifier(newUtt);
}
console.log(newUtt); //IMPORTANT!! Do not remove: Logging the object out fixes some onend firing issues.
//placing the speak invocation inside a callback fixes ordering and onend issues.
setTimeout(function () {
speechSynthesis.speak(newUtt);
}, 0);
};
How to use it...
//create an utterance as you normally would...
var myLongText = "This is some long text, oh my goodness look how long I'm getting, wooooohooo!";
var utterance = new SpeechSynthesisUtterance(myLongText);
//modify it as you normally would
var voiceArr = speechSynthesis.getVoices();
utterance.voice = voiceArr[2];
//pass it into the chunking function to have it played out.
//you can set the max number of characters by changing the chunkLength property below.
//a callback function can also be added that will fire once the entire text has been spoken.
speechUtteranceChunker(utterance, {
chunkLength: 120
}, function () {
//some code to execute when done
console.log('done');
});
Hope people find this as useful.
I have solved the probleme while having a timer function which call the pause() and resume() function and callset the timer again. On the onend event I clear the timer.
var myTimeout;
function myTimer() {
window.speechSynthesis.pause();
window.speechSynthesis.resume();
myTimeout = setTimeout(myTimer, 10000);
}
...
window.speechSynthesis.cancel();
myTimeout = setTimeout(myTimer, 10000);
var toSpeak = "some text";
var utt = new SpeechSynthesisUtterance(toSpeak);
...
utt.onend = function() { clearTimeout(myTimeout); }
window.speechSynthesis.speak(utt);
...
This seem to work well.
A simple and effective solution is to resume periodically.
function resumeInfinity() {
window.speechSynthesis.resume();
timeoutResumeInfinity = setTimeout(resumeInfinity, 1000);
}
You can associate this with the onend and onstart events, so you will only be invoking the resume if necessary. Something like:
var utterance = new SpeechSynthesisUtterance();
utterance.onstart = function(event) {
resumeInfinity();
};
utterance.onend = function(event) {
clearTimeout(timeoutResumeInfinity);
};
I discovered this by chance!
Hope this help!
The problem with Peter's answer is it doesn't work when you have a queue of speech synthesis set up. The script will put the new chunk at the end of the queue, and thus out of order. Example: https://jsfiddle.net/1gzkja90/
<script type='text/javascript' src='http://code.jquery.com/jquery-2.1.0.js'></script>
<script type='text/javascript'>
u = new SpeechSynthesisUtterance();
$(document).ready(function () {
$('.t').each(function () {
u = new SpeechSynthesisUtterance($(this).text());
speechUtteranceChunker(u, {
chunkLength: 120
}, function () {
console.log('end');
});
});
});
/**
* Chunkify
* Google Chrome Speech Synthesis Chunking Pattern
* Fixes inconsistencies with speaking long texts in speechUtterance objects
* Licensed under the MIT License
*
* Peter Woolley and Brett Zamir
*/
var speechUtteranceChunker = function (utt, settings, callback) {
settings = settings || {};
var newUtt;
var txt = (settings && settings.offset !== undefined ? utt.text.substring(settings.offset) : utt.text);
if (utt.voice && utt.voice.voiceURI === 'native') { // Not part of the spec
newUtt = utt;
newUtt.text = txt;
newUtt.addEventListener('end', function () {
if (speechUtteranceChunker.cancel) {
speechUtteranceChunker.cancel = false;
}
if (callback !== undefined) {
callback();
}
});
}
else {
var chunkLength = (settings && settings.chunkLength) || 160;
var pattRegex = new RegExp('^[\\s\\S]{' + Math.floor(chunkLength / 2) + ',' + chunkLength + '}[.!?,]{1}|^[\\s\\S]{1,' + chunkLength + '}$|^[\\s\\S]{1,' + chunkLength + '} ');
var chunkArr = txt.match(pattRegex);
if (chunkArr[0] === undefined || chunkArr[0].length <= 2) {
//call once all text has been spoken...
if (callback !== undefined) {
callback();
}
return;
}
var chunk = chunkArr[0];
newUtt = new SpeechSynthesisUtterance(chunk);
var x;
for (x in utt) {
if (utt.hasOwnProperty(x) && x !== 'text') {
newUtt[x] = utt[x];
}
}
newUtt.addEventListener('end', function () {
if (speechUtteranceChunker.cancel) {
speechUtteranceChunker.cancel = false;
return;
}
settings.offset = settings.offset || 0;
settings.offset += chunk.length - 1;
speechUtteranceChunker(utt, settings, callback);
});
}
if (settings.modifier) {
settings.modifier(newUtt);
}
console.log(newUtt); //IMPORTANT!! Do not remove: Logging the object out fixes some onend firing issues.
//placing the speak invocation inside a callback fixes ordering and onend issues.
setTimeout(function () {
speechSynthesis.speak(newUtt);
}, 0);
};
</script>
<p class="t">MLA format follows the author-page method of in-text citation. This means that the author's last name and the page number(s) from which the quotation or paraphrase is taken must appear in the text, and a complete reference should appear on your Works Cited page. The author's name may appear either in the sentence itself or in parentheses following the quotation or paraphrase, but the page number(s) should always appear in the parentheses, not in the text of your sentence.</p>
<p class="t">Joe waited for the train.</p>
<p class="t">The train was late.</p>
<p class="t">Mary and Samantha took the bus.</p>
In my case, the answer was to "chunk" the string before adding them to the queue. See here: http://jsfiddle.net/vqvyjzq4/
Many props to Peter for the idea as well as the regex (which I still have yet to conquer.) I'm sure the javascript can be cleaned up, this is more of a proof of concept.
<script type='text/javascript' src='http://code.jquery.com/jquery-2.1.0.js'></script>
<script type='text/javascript'>
var chunkLength = 120;
var pattRegex = new RegExp('^[\\s\\S]{' + Math.floor(chunkLength / 2) + ',' + chunkLength + '}[.!?,]{1}|^[\\s\\S]{1,' + chunkLength + '}$|^[\\s\\S]{1,' + chunkLength + '} ');
$(document).ready(function () {
var element = this;
var arr = [];
var txt = replaceBlank($(element).text());
while (txt.length > 0) {
arr.push(txt.match(pattRegex)[0]);
txt = txt.substring(arr[arr.length - 1].length);
}
$.each(arr, function () {
var u = new SpeechSynthesisUtterance(this.trim());
window.speechSynthesis.speak(u);
});
});
</script>
<p class="t">MLA format follows the author-page method of in-text citation. This means that the author's last name and the page number(s) from which the quotation or paraphrase is taken must appear in the text, and a complete reference should appear on your Works Cited page. The author's name may appear either in the sentence itself or in parentheses following the quotation or paraphrase, but the page number(s) should always appear in the parentheses, not in the text of your sentence.</p>
<p class="t">Joe waited for the train.</p>
<p class="t">The train was late.</p>
<p class="t">Mary and Samantha took the bus.</p>
Here is what i ended up with, it simply splits my sentences on the period "."
var voices = window.speechSynthesis.getVoices();
var sayit = function ()
{
var msg = new SpeechSynthesisUtterance();
msg.voice = voices[10]; // Note: some voices don't support altering params
msg.voiceURI = 'native';
msg.volume = 1; // 0 to 1
msg.rate = 1; // 0.1 to 10
msg.pitch = 2; //0 to 2
msg.lang = 'en-GB';
msg.onstart = function (event) {
console.log("started");
};
msg.onend = function(event) {
console.log('Finished in ' + event.elapsedTime + ' seconds.');
};
msg.onerror = function(event)
{
console.log('Errored ' + event);
}
msg.onpause = function (event)
{
console.log('paused ' + event);
}
msg.onboundary = function (event)
{
console.log('onboundary ' + event);
}
return msg;
}
var speekResponse = function (text)
{
speechSynthesis.cancel(); // if it errors, this clears out the error.
var sentences = text.split(".");
for (var i=0;i< sentences.length;i++)
{
var toSay = sayit();
toSay.text = sentences[i];
speechSynthesis.speak(toSay);
}
}
2017 and this bug is still around. I happen to understand this problem quite well, being the developer of the award-winning Chrome extension Read Aloud. OK, just kidding about the award winning part.
Your speech will get stuck if it's longer than 15 seconds.
I discover that Chrome uses a 15 second idle timer to decide when to deactivate an extension's event/background page. I believe this is the culprit.
The workaround I've used is a fairly complicated chunking algorithm that respects punctuation. For Latin languages, I set max chunk size at 36 words. The code is open-source, if you're inclined: https://github.com/ken107/read-aloud/blob/315f1e1d5be6b28ba47fe0c309961025521de516/js/speech.js#L212
The 36-word limit works well most of the time, staying within 15 seconds. But there'll be cases where it still gets stuck. To recover from that, I use a 16 second timer.
I ended up chunking up the text and having some intelligence around handling of various punctucations like periods, commas, etc. For example, you don't want to break the text up on a comma if it's part of a number (i.e., $10,000).
I have tested it and it seems to work on arbitrarily large sets of input and it also appears to work not just on the desktop but on android phones and iphones.
Set up a github page for the synthesizer at: https://github.com/unk1911/speech
You can see it live at: http://edeliverables.com/tts/
new Vue({
el: "#app",
data: {
text: `Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without revolutionary ROI. Efficiently unleash cross-media information without cross-media value. Quickly maximize timely deliverables for real-time schemas. Dramatically maintain clicks-and-mortar solutions without functional solutions.`
},
methods:{
stop_reading() {
const synth = window.speechSynthesis;
synth.cancel();
},
talk() {
const synth = window.speechSynthesis;
const textInput = this.text;
const utterThis = new SpeechSynthesisUtterance(textInput);
utterThis.pitch = 0;
utterThis.rate = 1;
synth.speak(utterThis);
const resumeInfinity = () => {
window.speechSynthesis.resume();
const timeoutResumeInfinity = setTimeout(resumeInfinity, 1000);
}
utterThis.onstart = () => {
resumeInfinity();
};
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="talk">Speak</button>
<button #click="stop_reading">Stop</button>
</div>
As Michael proposed, Peter's solutions is really great except when your text is on different lines. Michael created demo to better illustrate the problem with it. - https://jsfiddle.net/1gzkja90/ and proposed another solution.
To add one maybe simpler way to solve this is to remove line breaks from textarea in Peter's solution and it works just great.
//javascript
var noLineBreaks = document.getElementById('mytextarea').replace(/\n/g,'');
//jquery
var noLineBreaks = $('#mytextarea').val().replace(/\n/g,'');
So in Peter's solution it might look the following way :
utterance.text = $('#mytextarea').val().replace(/\n/g,'');
But still there's problem with canceling the speech. It just goes to another sequence and won't stop.
Other suggestion do weird thing with dot or say DOT and do not respect speech intonnation on sentence end.
var CHARACTER_LIMIT = 200;
var lang = "en";
var text = "MLA format follows the author-page method of in-text citation. This means that the author's last name and the page number(s) from which the quotation or paraphrase is taken must appear in the text, and a complete reference should appear on your Works Cited page. The author's name may appear either in the sentence itself or in parentheses following the quotation or paraphrase, but the page number(s) should always appear in the parentheses, not in the text of your sentence. Joe waited for the train. The train was late. Mary and Samantha took the bus.";
speak(text, lang)
function speak(text, lang) {
//Support for multipart text (there is a limit on characters)
var multipartText = [];
if (text.length > CHARACTER_LIMIT) {
var tmptxt = text;
while (tmptxt.length > CHARACTER_LIMIT) {
//Split by common phrase delimiters
var p = tmptxt.search(/[:!?.;]+/);
var part = '';
//Coludn't split by priority characters, try commas
if (p == -1 || p >= CHARACTER_LIMIT) {
p = tmptxt.search(/[,]+/);
}
//Couldn't split by normal characters, then we use spaces
if (p == -1 || p >= CHARACTER_LIMIT) {
var words = tmptxt.split(' ');
for (var i = 0; i < words.length; i++) {
if (part.length + words[i].length + 1 > CHARACTER_LIMIT)
break;
part += (i != 0 ? ' ' : '') + words[i];
}
} else {
part = tmptxt.substr(0, p + 1);
}
tmptxt = tmptxt.substr(part.length, tmptxt.length - part.length);
multipartText.push(part);
//console.log(part.length + " - " + part);
}
//Add the remaining text
if (tmptxt.length > 0) {
multipartText.push(tmptxt);
}
} else {
//Small text
multipartText.push(text);
}
//Play multipart text
for (var i = 0; i < multipartText.length; i++) {
//Use SpeechSynthesis
//console.log(multipartText[i]);
//Create msg object
var msg = new SpeechSynthesisUtterance();
//msg.voice = profile.systemvoice;
//msg.voiceURI = profile.systemvoice.voiceURI;
msg.volume = 1; // 0 to 1
msg.rate = 1; // 0.1 to 10
// msg.rate = usersetting || 1; // 0.1 to 10
msg.pitch = 1; //0 to 2*/
msg.text = multipartText[i];
msg.speak = multipartText;
msg.lang = lang;
msg.onend = self.OnFinishedPlaying;
msg.onerror = function (e) {
console.log('Error');
console.log(e);
};
/*GC*/
msg.onstart = function (e) {
var curenttxt = e.currentTarget.text;
console.log(curenttxt);
//highlight(e.currentTarget.text);
//$('#showtxt').text(curenttxt);
//console.log(e);
};
//console.log(msg);
speechSynthesis.speak(msg);
}
}
https://jsfiddle.net/onigetoc/9r27Ltqz/
I want to say that through Chrome Extensions and Applications, I solved this quite irritating issue through using chrome.tts, since chrome.tts allows you to speak through the browser, instead of the window which stops the talk when you close the window.
Using the below code, you can fix the above issue with large speakings:
chrome.tts.speak("Abnormally large string, over 250 characters, etc...");
setInterval(() => { chrome.tts.resume(); }, 100);
I'm sure that will work, but I did this just to be safe:
var largeData = "";
var smallChunks = largeData.match(/.{1,250}/g);
for (var chunk of smallChunks) {
chrome.tts.speak(chunk, {'enqueue': true});
}
Hope this helps someone! It helped make my application work more functionally, and epicly.
Yes, the google synthesis api will stop at some point during speaking a long text.
We can see onend event, onpause and onerror event of SpeechSynthesisUtterance won't be fired normally when the sudden stop happens, so does the speechSynthesis onerror event.
After several trials, found speechSynthesis.paused is working, and speechSynthesis.resume() can help resume the speaking.
Hence we just need to have a timer to check the pause status during the speaking, and calling speechSynthesis.resume() to continue.
The interval should be small enough to prevent glitch when continuing the speak.
let timer = null;
let reading = false;
let readText = function(text) {
if (!reading) {
speechSynthesis.cancel();
if (timer) {
clearInterval(timer);
}
let msg = new SpeechSynthesisUtterance();
let voices = window.speechSynthesis.getVoices();
msg.voice = voices[82];
msg.voiceURI = 'native';
msg.volume = 1; // 0 to 1
msg.rate = 1.0; // 0.1 to 10
msg.pitch = 1; //0 to 2
msg.text = text;
msg.lang = 'zh-TW';
msg.onerror = function(e) {
speechSynthesis.cancel();
reading = false;
clearInterval(timer);
};
msg.onpause = function(e) {
console.log('onpause in ' + e.elapsedTime + ' seconds.');
}
msg.onend = function(e) {
console.log('onend in ' + e.elapsedTime + ' seconds.');
reading = false;
clearInterval(timer);
};
speechSynthesis.onerror = function(e) {
console.log('speechSynthesis onerror in ' + e.elapsedTime + ' seconds.');
speechSynthesis.cancel();
reading = false;
clearInterval(timer);
};
speechSynthesis.speak(msg);
timer = setInterval(function(){
if (speechSynthesis.paused) {
console.log("#continue")
speechSynthesis.resume();
}
}, 100);
reading = true;
}
}

How to start multiple audio tags simultaneously?

I have several tracks to a song that I want to play together and be able to mute some and play others. So I need to be able to start them all at the same time. Right now, they all start slightly out of sync:
// Start playing
for ( i = 0; i < 5; i++ ) {
tracks[i].audio.play();
}
Even this is apparently not fast enough to start them all at the same time.
Is there any way in javascript to guarantee that HTML5 audio tags will start playing simultaneously?
Not sure if you're already doing this, but Here's some sample code for preloading audio.
var audios = [];
var loading = 0;
AddNote("2C");
AddNote("2E");
AddNote("2G");
AddNote("3C");
function AddNote(name) {
loading++;
var audio = document.createElement("audio");
audio.loop = true;
audio.addEventListener("canplaythrough", function () {
loading--;
if (loading == 0) // All files are preloaded
StartPlayingAll();
}, false);
audio.src = "piano/" + name + ".mp3";
audios.push(audio);
}
function StartPlayingAll() {
for (var i = 0; i < audios.length; i++)
audios[i].play();
}
}
The other thing you can try is setting audio.currentTime on each of the tracks to manually sync up the audio.
You could use setTimeout to sync them after a brief delay in the beginning (you may want to wait for all the audio objects to load though).
JSFiddle: http://jsfiddle.net/bmAYb/35/
var au1 = document.getElementById('au1');
var au2 = document.getElementById('au2');
au1.volume = 1;
au2.volume = 0; //mute
au1.play();
au2.play();
var notfirstRun = false;
//sync for the first time
setTimeout(function() {
au2.currentTime = au1.currentTime;
au2.volume = 1;
}, 250);
My initial thought was to sync every x miliseconds using setInterval, but the audio pops when you do that if volume is set to 1 (audible).
My fiddle isn't totally in sync, but it's pretty close. You can get it 100% in sync but you either need to mute the audio on the other tracks or deal with popping.
The code (and music in the fiddle) are from Hungry Media.
I had the same issue and found a solution using the Audio API.
The problem is that the audio output has a delay of a few milliseconds, so it is impossible to start multiple audios at the same time. However, you can get around this by merging the audio sources into one using a ChannelMergerNode. By putting GainNodes in between, you can control the volume of each audio source separately.
I wrote a simple javascript class for this. This is how you can use it:
var audioMerger = new AudioMerger(["file1.ogg", "file2.mp3", "file3.mp3",
"file4.ogg", "file5.mp3"]);
audioMerger.onBuffered(() => audioMerger.play());
// Make sure it's always in sync (delay should be less than 50 ms)
setInterval(() => {
if (audioMerger.getDelay() >= 0.05) {
audioMerger.setTime(audioMerger.getTime());
}
}, 200);
// Set volume of 3rd audio to 50%
audioMerger.setVolume(0.5, 2);
// When you want to turn it off:
audioMerger.pause();
This code reduced the delay between the audios to less than 10 milliseconds in Firefox on my PC. This delay is so small you won't notice it. Unfortunately, it doesn't work in older browsers like Internet Explorer.
And here's the code for the class:
class AudioMerger {
constructor(files) {
this.files = files;
this.audios = files.map(file => new Audio(file));
var AudioContext = window.AudioContext || window.webkitAudioContext;
var ctx = new AudioContext();
this.merger = ctx.createChannelMerger(this.audios.length);
this.merger.connect(ctx.destination);
this.gains = this.audios.map(audio => {
var gain = ctx.createGain();
var source = ctx.createMediaElementSource(audio);
source.connect(gain);
gain.connect(this.merger);
return gain;
});
this.buffered = false;
var load = files.length;
this.audios.forEach(audio => {
audio.addEventListener("canplaythrough", () => {
load--;
if (load === 0) {
this.buffered = true;
if (this.bufferCallback != null) this.bufferCallback();
}
});
});
}
onBuffered(callback) {
if (this.buffered) callback();
else this.bufferCallback = callback;
}
play() {
this.audios.forEach(audio => audio.play());
}
pause() {
this.audios.forEach(audio => audio.pause());
}
getTime() {
return this.audios[0].currentTime;
}
setTime(time) {
this.audios.forEach(audio => audio.currentTime = time);
}
getDelay() {
var times = [];
for (var i = 0; i < this.audios.length; i++) {
times.push(this.audios[i].currentTime);
}
var minTime = Math.min.apply(Math, times);
var maxTime = Math.max.apply(Math, times);
return maxTime - minTime;
}
setVolume(volume, audioID) {
this.gains[audioID].gain.value = volume;
}
}

How do I make JavaScript beep?

I want my web page to beep whenever a user exceeds the maximum character limit of my <textarea>.
Solution
You can now use base64 files to produce sounds when imported as data URI. The solution is almost the same as the previous ones, except you do not need to import an external audio file.
function beep() {
var snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
snd.play();
}
beep();
Compatibility
Data URI is supported on almost every browser now. More information on http://caniuse.com/datauri
Demo
http://jsfiddle.net/7EAgz/
Conversion Tool
And here is where you can convert mp3 or wav files into Data URI format:
https://dopiaza.org/tools/datauri/index.php
It's not possible to do directly in JavaScript. You'll need to embed a short WAV file in the HTML, and then play that via code.
An Example:
<script>
function PlaySound(soundObj) {
var sound = document.getElementById(soundObj);
sound.Play();
}
</script>
<embed src="success.wav" autostart="false" width="0" height="0" id="sound1"
enablejavascript="true">
You would then call it from JavaScript code as such:
PlaySound("sound1");
This should do exactly what you want - you'll just need to find/create the beep sound yourself, which should be trivial.
/*if you want to beep without using a wave file*/
var context = new AudioContext();
var oscillator = context.createOscillator();
oscillator.type = "sine";
oscillator.frequency.value = 800;
oscillator.connect(context.destination);
oscillator.start();
// Beep for 500 milliseconds
setTimeout(function () {
oscillator.stop();
}, 100);
The top answer was correct at the time but is now wrong; you can do it in pure javascript. But the one answer using javascript doesn't work any more, and the other answers are pretty limited or don't use pure javascript.
I made my own solution that works well and lets you control the volume, frequency, and wavetype.
//if you have another AudioContext class use that one, as some browsers have a limit
var audioCtx = new (window.AudioContext || window.webkitAudioContext || window.audioContext);
//All arguments are optional:
//duration of the tone in milliseconds. Default is 500
//frequency of the tone in hertz. default is 440
//volume of the tone. Default is 1, off is 0.
//type of tone. Possible values are sine, square, sawtooth, triangle, and custom. Default is sine.
//callback to use on end of tone
function beep(duration, frequency, volume, type, callback) {
var oscillator = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
if (volume){gainNode.gain.value = volume;}
if (frequency){oscillator.frequency.value = frequency;}
if (type){oscillator.type = type;}
if (callback){oscillator.onended = callback;}
oscillator.start(audioCtx.currentTime);
oscillator.stop(audioCtx.currentTime + ((duration || 500) / 1000));
};
Someone suggested I edit this to note it only works on some browsers. However Audiocontext seems to be supported on all modern browsers, as far as I can tell. It isn't supported on IE, but that has been discontinued by Microsoft. If you have any issues with this on a specific browser please report it.
I wrote a function to beep with the new Audio API.
var beep = (function () {
var ctxClass = window.audioContext ||window.AudioContext || window.AudioContext || window.webkitAudioContext
var ctx = new ctxClass();
return function (duration, type, finishedCallback) {
duration = +duration;
// Only 0-4 are valid types.
type = (type % 5) || 0;
if (typeof finishedCallback != "function") {
finishedCallback = function () {};
}
var osc = ctx.createOscillator();
osc.type = type;
//osc.type = "sine";
osc.connect(ctx.destination);
if (osc.noteOn) osc.noteOn(0); // old browsers
if (osc.start) osc.start(); // new browsers
setTimeout(function () {
if (osc.noteOff) osc.noteOff(0); // old browsers
if (osc.stop) osc.stop(); // new browsers
finishedCallback();
}, duration);
};
})();
jsFiddle.
Using Houshalter's suggestion, I made this simple tone synthesizer demo.
Screenshot
Here is a screenshot. Try the live demo further down in this Answer (click Run code snippet).
Demo code
audioCtx = new(window.AudioContext || window.webkitAudioContext)();
show();
function show() {
frequency = document.getElementById("fIn").value;
document.getElementById("fOut").innerHTML = frequency + ' Hz';
switch (document.getElementById("tIn").value * 1) {
case 0: type = 'sine'; break;
case 1: type = 'square'; break;
case 2: type = 'sawtooth'; break;
case 3: type = 'triangle'; break;
}
document.getElementById("tOut").innerHTML = type;
volume = document.getElementById("vIn").value / 100;
document.getElementById("vOut").innerHTML = volume;
duration = document.getElementById("dIn").value;
document.getElementById("dOut").innerHTML = duration + ' ms';
}
function beep() {
var oscillator = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
gainNode.gain.value = volume;
oscillator.frequency.value = frequency;
oscillator.type = type;
oscillator.start();
setTimeout(
function() {
oscillator.stop();
},
duration
);
};
frequency
<input type="range" id="fIn" min="40" max="6000" oninput="show()" />
<span id="fOut"></span><br>
type
<input type="range" id="tIn" min="0" max="3" oninput="show()" />
<span id="tOut"></span><br>
volume
<input type="range" id="vIn" min="0" max="100" oninput="show()" />
<span id="vOut"></span><br>
duration
<input type="range" id="dIn" min="1" max="5000" oninput="show()" />
<span id="dOut"></span>
<br>
<button onclick='beep();'>Play</button>
You can clone and tweak the code here:
Tone synthesizer demo on JS Bin
Have fun!
Compatible browsers:
Chrome mobile & desktop
Firefox mobile & desktop
Opera mobile, mini & desktop
Android browser
Microsoft Edge browser
Safari on iPhone or iPad
Not Compatible
Internet Explorer version 11 (but does work on the Edge browser)
This will enable you to play the sound multiple times, in contrast to the top-voted answer:
var playSound = (function beep() {
var snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
return function() {
snd.play();
}
})();
playSound(); // Play first time
playSound(); // Play second time
As we read in this answer, HTML5 will solve this for you if you're open to that route. HTML5 audio is supported in all modern browsers.
Here's a copy of the example:
var snd = new Audio("file.wav"); // buffers automatically when created
snd.play();
Now it easy enough with JavaScript AudioContext API. It fully supported by major desktop and mobile web browsers...
let context = null;
const beep = (freq = 520, duration = 200, vol = 100) => {
const oscillator = context.createOscillator();
const gain = context.createGain();
oscillator.connect(gain);
oscillator.frequency.value = freq;
oscillator.type = "square";
gain.connect(context.destination);
gain.gain.value = vol * 0.01;
oscillator.start(context.currentTime);
oscillator.stop(context.currentTime + duration * 0.001);
}
document.querySelector('button').addEventListener('click', function () {
context = new AudioContext();
beep();
});
I wrote a small application that plays music from the Mario game without any audio file, just runtime. In my opinion it’s interesting, you can see the source code and listen it.
Using CSS you can do it if you add the following style to a tag, but you will need a wav file:
<style type="text/css">
.beep {cue: url("beep.wav") }
</style>
var body=document.getElementByTagName("body");
body.className=body.className + " " + "beep";
Here's how I get it to beep using HTML5:
First I copy and convert the windows wav file to mp3, then I use this code:
var _beep = window.Audio("Content/Custom/Beep.mp3")
function playBeep() { _beep.play()};
It's faster to declare the sound file globally and refer to it as needed.
This code supports sequencing of multiple beeps, as well as gradual change in frequency ('ramp' flag). Both examples are given below.
<script>
var audioContext = null;
var oscillatorNode = null;
var stopTime = 0;
function beep (frequency, durationSec, ramp=false)
{
if (oscillatorNode == null) {
audioContext = new (window.AudioContext || window.webkitAudioContext) ();
stopTime = audioContext.currentTime;
oscillatorNode = audioContext.createOscillator();
oscillatorNode.type = "sine";
oscillatorNode.connect (audioContext.destination);
if (ramp) {
oscillatorNode.frequency.setValueAtTime (frequency, stopTime);
}
oscillatorNode.start ();
oscillatorNode.onended = function() {
oscillatorNode = null;
audioContext = null;
}
}
if (ramp) {
oscillatorNode.frequency.linearRampToValueAtTime (frequency, stopTime); // value in hertz
} else {
oscillatorNode.frequency.setValueAtTime (frequency, stopTime); // value in hertz
}
stopTime += durationSec;
oscillatorNode.stop (stopTime);
}
function test1()
{
beep (250, 0.5);
beep (1000, 0.2);
beep (550, 0.5);
}
function test2()
{
beep (50, 2, true);
beep (5000, 2, true);
beep (50, 0, true);
}
</script>
<button onclick='test1()'>Beep!</button>
<button onclick='test2()'>Beep(ramped)!</button>
There's no crossbrowser way to achieve this with pure javascript. Instead you could use a small .wav file that you play using embed or object tags.
function beep(wavFile){
wavFile = wavFile || "beep.wav"
if (navigator.appName == 'Microsoft Internet Explorer'){
var e = document.createElement('BGSOUND');
e.src = wavFile;
e.loop =1;
document.body.appendChild(e);
document.body.removeChild(e);
}else{
var e = document.createElement('AUDIO');
var src1 = document.createElement('SOURCE');
src1.type= 'audio/wav';
src1.src= wavFile;
e.appendChild(src1);
e.play();
}
}
Works on Chrome,IE,Mozilla using Win7 OS.
Requires a beep.wav file on the server.
function Sound(url, vol, autoplay, loop)
{
var that = this;
that.url = (url === undefined) ? "" : url;
that.vol = (vol === undefined) ? 1.0 : vol;
that.autoplay = (autoplay === undefined) ? true : autoplay;
that.loop = (loop === undefined) ? false : loop;
that.sample = null;
if(that.url !== "")
{
that.sync = function(){
that.sample.volume = that.vol;
that.sample.loop = that.loop;
that.sample.autoplay = that.autoplay;
setTimeout(function(){ that.sync(); }, 60);
};
that.sample = document.createElement("audio");
that.sample.src = that.url;
that.sync();
that.play = function(){
if(that.sample)
{
that.sample.play();
}
};
that.pause = function(){
if(that.sample)
{
that.sample.pause();
}
};
}
}
var test = new Sound("http://mad-hatter.fr/Assets/projects/FreedomWings/Assets/musiques/freedomwings.mp3");
test.play();
http://jsfiddle.net/sv9j638j/
Note:put this code in your javascript at the point you want the beep to occur.
and remember to specify the directory or folder where the beep sound is stored(source).
<script>
//Appending HTML5 Audio Tag in HTML Body
$('<audio id="chatAudio"><source src="sound/notify.ogg" type="audio/ogg"><source src="sound/notify.mp3" type="audio/mpeg"><source src="sound/notify.wav" type="audio/wav"></audio>').appendTo('body');
$('#chatAudio')[0].play();
</script>
Reference:http://www.9lessons.info/2013/04/play-notification-sound-using-jquery.html.
I implemented this in a social media i am developing and it works find, a notification like that of facebook when chatting, notifying you that you have a new chat message
<html>
<head>
<script src='https://surikov.github.io/webaudiofont/npm/dist/WebAudioFontPlayer.js'></script>
<script src='https://surikov.github.io/webaudiofontdata/sound/0000_JCLive_sf2_file.js'></script>
<script>
var selectedPreset=_tone_0000_JCLive_sf2_file;
var AudioContextFunc = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContextFunc();
var player=new WebAudioFontPlayer();
player.loader.decodeAfterLoading(audioContext, '_tone_0000_JCLive_sf2_file');
</script>
</head>
<body>
<p>Play a note</p>
<hr/>
<p>source</p>
</body>
listen here
https://jsbin.com/lamidog/1/edit?html,output
function beep(freq = 660, duration = 90, vol = 50) {
var context = new(window.AudioContext || window.webkitAudioContext);
const oscillator = context.createOscillator();
const gain = context.createGain();
gain.gain.setValueAtTime(0, context.currentTime);
gain.gain.linearRampToValueAtTime(1, context.currentTime + 0.002);
oscillator.connect(gain);
oscillator.frequency.value = freq;
oscillator.type = "square";
gain.connect(context.destination);
oscillator.start(context.currentTime);
oscillator.stop(context.currentTime + duration * .001);
oscillator.onended = () => context.close();
}
<br>
<center><button onclick="beep()">Beep!</button></center>
You need a sound file to be served from somewhere. Here's the code from Scriptaculous's Sound library:
//Default:
<embed style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>
//For Gecko:
if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){
if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 }))
Sound.template = new Template('<object id="sound_#{track}_#{id}" width="0" height="0" type="audio/mpeg" data="#{url}"/>');
else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('Windows Media') != -1 }))
Sound.template = new Template('<object id="sound_#{track}_#{id}" type="application/x-mplayer2" data="#{url}"></object>');
else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('RealPlayer') != -1 }))
Sound.template = new Template('<embed type="audio/x-pn-realaudio-plugin" style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>');
else
Sound.play = function(){};
}

Categories