I saw that there's some singing voices in the Web Speech API using the voice "Good News" (and "Bad News"). But I'd like to know how I can make my own custom song. It seems to sing the same notes. Can I pass it what notes I'd like for each word?
edit: a comment below points out the "Good News" is a mac voice. So the below code might only work on Mac. I'm looking for a more generalized solution for both pc and mac.
if (!window.speechSynthesis) {
alert("Your browser doesn't support speechSynthesis !!");
}
var voices;
function loadVoices() {
voices = window.speechSynthesis.getVoices();
if (voices.length == 0) alert("cannot get voices !!");
console.log(voices.map(function (x) {return x.name;}));
}
var msg = new SpeechSynthesisUtterance("la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la-la");
function sing(name) {
speechSynthesis.cancel();
loadVoices();
msg.voice = voices[0];
for (var i = 0; i < voices.length; i++)
if (voices[i].name == name) msg.voice = voices[i];
speechSynthesis.speak(msg);
}
setTimeout(function() {
sing('Good News');
},1000); // let browser initialize for a sec
I noticed Web Speech api has something called pitch. But after messing with it, the word doesn't really "sing". You can see a codepen here. Also I don't think I could convert a frequency to a pitch, like for example Middle C is 261.6 Hz.
I also noticed another library called meSing.js but the voices sound too robotic:
http://usdivad.com/mesing/
I downloaded mesing.js from github, and I changed the hard coded voice that it uses to other voices that are given in the underlying voice library (meSpeak.js), and even though the voice changes, it still sounds robotic.
I like the sound quality of the first "Good News" but I'd like to know how to make a custom one, is it possible?
edit: maybe I can take 'Good News' with just one word. and then play that with different pitch settings. I'd have to see what the range of pitches are. still experimenting..
Related
The bounty expires in 2 days. Answers to this question are eligible for a +100 reputation bounty.
Basj is looking for a canonical answer.
I'm building a low-latency sampler in the browser (using Javascript, WASM, etc.).
How to choose, from Javascript, a specific audio output device for Chrome or Firefox?
I see there is Audio Output API but there are not many examples (and by the way navigator.mediaDevices.selectAudioOutput is undefined on my Chrome 109).
For example, how to make Chrome use Asio4All as main output device?
(Note: using an ASIO device such as the free Asio4All driver can make the latency drop from 30 milliseconds to 5 milliseconds, even on an old computer).
There is also Audio Output Devices API which can be used to achieved the similar functionality.
// First Create a new audio element
var audio = new Audio("https://samplelib.com/lib/preview/mp3/sample-3s.mp3");
// Get the list of available audio output devices
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
// Filter the devices to get only the audio output ones
var audioOutputDevices = devices.filter(function(device) {
return device.kind === "audiooutput";
});
// Log the devices to the console
console.log(audioOutputDevices);
// If there is at least one audio output device, use the first one as the output device
if (audioOutputDevices.length > 0) {
// Set the sink ID of the audio element to the device ID of the first audio output device
audio.setSinkId(audioOutputDevices[0].deviceId)
.then(function() {
// Play the audio
audio.play();
})
.catch(function(error) {
// Handle any errors
console.error(error);
});
}
})
The audioOutputDevices[] can be leveraged to choose between vaious output devices.
I have two sound sensors which both are Arduino compatible. One is AVR PIC F Arduino Sensitive Audio Sound Microphone Mic Sensor Detection Module, another is just a different brand comes with Arduino kit. I tried to use the following code with Johnny-five:
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
var mic = new five.Sensor("A0");
mic.on("data", function() {
console.log(this.value);
});
});
I connected Digital output to A1 and Analog output to A0, and I tried only connecting to A0 without digital too. However, the AO output which is the (this.value in the code) are appearing a bit fluctuating but mainly steady value that is not affected by sound input at all.
I tried C code to test the sensor, it works. So the hardware is good but I am sure the connection is correct or I need any extra code for this?
Anyone has a sound sensor working with Johnny-five, please advise.
Thank you so much!
I know there are many solutions can be found in the web regarding my problem, but none of them are working for me. That's why I'm asking this question.
First let me explain what I'm looking to achieve -
-> I'm developing a multi-user Web application [ASP.Net]
-> I'm using SignalR to get real-time database change notifications and SignalR instantly transmit the change notifications to all the users logged in the application.
-> Now in addition what I want to do is to play a notification sound for all the logged in users so that they can understand a new notification need attention.
This is what I've done so far -
JavaScript
<script>
function playSound(mysound) {
//thisSound = document.getElementById(mysound);
//thisSound.Play();
var audio = new Audio(mysound);
audio.play();
}
</script>
Code Behind -
ScriptManager.RegisterClientScriptBlock(Me, [GetType](), "OpenWindow", "javascript: playSound('./audio/notification.wav')", True)
The problem with this solution is that the user need to reload the page to hear the notification sound, which I think is pointless if the user can't hear them instantly like the SignalR processing notifications.
Is it possible to push the sound to all the clients so that they don't need to reload the page?
Any help would be highly appreciated. If you need any further clarification please let me know.
Finally I got it worked. I had to change the jquery a little bit -
<script type="text/javascript">
function playSound(mysound) {
//thisSound = document.getElementById(mysound);
//thisSound.Play();
var audio = new Audio(mysound);
audio.play();
}
$(function () {
var notify = $.connection.notificationsHub;
var audio;
notify.client.displayNotification = function (s_Not, s_Path) {
$("#newNot").html(s_Not);
audio = new Audio(s_Path);
var iLevel = "<%=System.Web.HttpContext.Current.Session("USER_LEVEL")%>";
var i_OldNot = "<%=System.Web.HttpContext.Current.Session("NOT_COUNT")%>";
if (iLevel == 2) {
//alert(i_OldNot + " " + s_Not);
if (i_OldNot < i_Not) {
playSound("/audio/notification.wav");
//i_OldNot == Number(s_not);
}
}
};
$.connection.hub.start();
});
</script>
In the code behind I had to set a Session Variable to store the number of last notification before update. If the previous and present number of notification is higher than the session value then notification sound play -
System.Web.HttpContext.Current.Session("NOT_COUNT")= i_LastNotCount
Now the sound is playing without reloading the page. Special thanks to rdans, because of his below comments I got this idea -
Then in a comment you say:
I already have implemented SignalR. So it's not the problem at all.
This suggests to me that you probably don't understand what signalR is doing because the whole point of signalR is to push to the browser without having to post back or use an ajax call.
The time you are executing the user logged in notification using signalR, after that you can Call javascript function from server .
Hope this is what you are looking for.
In web audio, I can't get the ScriptProcessor node to work in Chrome, although it works fine in Firefox.
// Create audio context (Chrome/Firefox)
var context;
if (window.AudioContext) {
context = new AudioContext();
} else {
context = new webkitAudioContext();
}
// Create oscillator and start it
oscillator = context.createOscillator();
oscillator.start(0);
// Set up a script node that sets output to white noise
var myscriptnode = context.createScriptProcessor(4096, 1, 1);
myscriptnode.onaudioprocess = function(event) {
console.log('Processing buffer');
var output = event.outputBuffer.getChannelData(0);
for (i = 0; i < output.length; i++) {
output[i] = Math.random() / 10;
}
};
// Connect oscillator to script node and script node to destination
// (should output white noise)
oscillator.connect(myscriptnode);
myscriptnode.connect(context.destination);
// NOTE: This commented-out code connects oscillator directly to
// destination, which works in Chrome as well as Firefox.
//oscillator.connect(context.destination);
Expected result of this sample is that it should play white noise at 1/10 volume (the oscillator is actually ignored).
You can try this code at http://jsfiddle.net/78yKV/3/ - be aware that on Firefox this URL will play white noise straight away! On Chrome 30, it doesn't give any errors, but also doesn't give any audio output. I also checked in Chrome 31 beta but saw the same results. The 'Processing buffer' log entry never appears.
To test the general audio system, if you uncomment the last line and connect the oscillator directly to the destination, it does play audio (the oscillator tone) correctly on Chrome. But I can't get the ScriptProcessor to work on Chrome.
I searched the net for tutorials etc. with ScriptProcessor but those I found either didn't come with runnable examples or didn't work (or were too complex).
(Just to make clear - this is a stripped-down sample and doesn't relate in any way to what I'm actually trying to do, so please don't tell me that I shouldn't use a ScriptProcessor to generate white noise. That's not what it's for; I do absolutely need ScriptProcessor to work for my real usage.)
I think most likely I am doing something very stupid like I have the wrong event name or something like that, but I can't find it. Can anyone help?
I now managed to check on several other machines and I think the problem is specific to the default audio device on my machine, which is a telephone handset using the Microsoft default USB audio driver. I've reported this to Google using the menu option in Chrome; my speculation is that the problem occurs because the handset only supports mono 16 kHz output, and somehow this causes Chrome to get confused.
I can reproduce the bug on a colleague's machine which has the same make of handset. To reiterate:
Firefox works correctly on both machines when using the handset.
Both machines work correctly in Chrome when you select a different output device.
The oscillator playback works correctly in Chrome even when using the telephone handset.
Final version of test code http://jsfiddle.net/78yKV/7/
function doStuff(osc) {
// Create audio context (Chrome/Firefox)
var context;
if (window.AudioContext) {
context = new AudioContext();
} else {
context = new webkitAudioContext();
}
// Set up a script node that sets output to white noise
var myscriptnode;
if (context.createScriptProcessor) {
myscriptnode = context.createScriptProcessor(4096, 1, 1);
} else {
myscriptnode = context.createJavaScriptNode(4096, 1, 1);
}
var buffer = 1;
myscriptnode.onaudioprocess = function(event) {
console.log('Processing buffer ' + (buffer++));
var output = event.outputBuffer.getChannelData(0);
for (i = 0; i < output.length; i++) {
output[i] = Math.random() / 10;
}
};
// Connect script node to destination
if (osc) {
oscillator = context.createOscillator();
oscillator.start(0);
oscillator.connect(context.destination);
} else {
myscriptnode.connect(context.destination);
}
}
The white noise playback from this script (well actually a slightly earlier test version but I think it's the same) works in Chrome 30 on Windows 7, Windows 8.1, Linux, and Android 4.1; on Firefox on Windows; on an iPad (latest OS); and on a Mac using Safari 6.0.5 as well (it breaks if you open the developer tools there, but as long as you don't, it works). It only fails when using the USB telephone handset (Polycom CX300) mentioned.
So in other words, as apsillers suggested, this still looks like a Chrome bug, but a rather specific one. (By the way I also tried the latest 'Canary' version of Chrome but it didn't help.)
How can I know, in Xul, if the network is (dis)connected?
--update
Using:
function observe(aSubject, aTopic, aState) {
if (aTopic == "network:offline-status-changed") {
write("STATUS CHANGED!");
}
}
var os = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
os.addObserver(observe, "network:offline-status-changed", false);
and the preference:
pref("network.manage-offline-status", true);
it's not working.. There's a bug report here, but I don't think it has something to do with it.
--
Actually I think it's not possible to be notified, as even in Firefox we're never notified, and the user need to manually mark "work offline" if he wants the browser to know that it's offline..
--
Screenshot my of Firefox "about:config" filtering for "offline" string, unfortunately, there no "network.manage-offline-status":
You should be able to use navigator.onLine. Here is the help page
https://developer.mozilla.org/en/Online_and_offline_events
navigator.onLine is a property that
maintains a true/false value (true for
online, false for offline). This
property is updated whenever the user
switches into "Offline Mode" by
selecting the corresponding menu item
(File -> Work Offline in Firefox).
Another solution (as commented by #Neil):
Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.addObserver(myFunction, "network:offline-status-changed", false);
The best way I found is to use the following javascript code, that behaves like a ping, and make the test with some big websites, and assume that if none of them answers, so the network must be disconnected.
var ping = {};
ping = {
img:null,
imgPreload:null,
timer:null,
init:function() {
var sess = new Date();
var nocache = sess.getTime();
var imguri = ping.img+"?time="+nocache;
var ping.imgPreload = new Image();
ping.imgPreload.onload = function() {
clearTimeout(ping.timer);
ping.timer = null;
alert("Domain is available");
};
ping.imgPreload.src = imguri;
ping.timer = setTimeout("ping.fail_to_ping()",60000);
},
fail_to_ping:function() {
clearTimeout(ping.timer);
ping.timer = null;
ping.imgPreload = null;
alert("Ping to domain failed!");
}
};
(from http://crynobone.com/ci/index.php/archive/view/852)
--update
But, as it's not a reliable solution (as you can't rely that the image will be in the website forever), the best solution might be to develop a new XPCom component.
Eh... as per HTML5 (read echmascript 5), the on-/offline events are available.
See it here at Mozilla Hacks
Edit 20/4/2011:
I just encountered an update for this answer, when i was watching a podcast from MS MIX11:
http://channel9.msdn.com/Events/MIX/MIX11/HTM14 around time 43:36, the lecturer is actually talking about the window.navigator.onLine property, where he uses it for detecting if the browser (and the computer) is online. Then he uses the online event to do something when he gets online again.
This method is only available in modern browsers, however. So IE 8 and below have to poll for the connection.