Create sound on the fly with javascript / html5

Is it possible to generate a constant audio stream using javascript / html5? For example, to generate an eternal sine wave, I will have a callback function that will be called whenever the output buffer is about to become empty:

function getSampleAt(timestep) { return Math.sin(timestep); } 

(The idea is to use this to create an interactive synthesizer. I don't know in advance how long the key will be pressed, so I cannot use a fixed-length buffer)

+64
javascript html html5 audio
Jun 14 '11 at 12:27
source share
7 answers

Using an HTML5 Audio Element

It is currently not possible to use generator sound with an enhanced browser using JavaScript and the audio element, as Stephen Wittens notes in a blog post about creating a JavaScript synthesizer:

"... there is no way to queue fragments of synthesized audio for seamless playback."

Using the web audio API

The web audio API has been designed to facilitate the synthesis of JavaScript audio. The Mozilla Developer Network has a web-based tone generator that works in Firefox 4+ [ demo 1 ]. Add these two lines to this code, and you have a working synthesizer with a generative stable sound when you press the key [ demo 2 - works only in Firefox 4, first click the "Results" area, then press any key]:

 window.onkeydown = start; window.onkeyup = stop; 

The BBC page in the web audio API is also worth considering. Unfortunately, support for the Web Audio API does not yet apply to other browsers.

Possible workarounds

To create a cross-browser synthesizer at this time, you may have to discard the pre-recorded sound with:

  • Using long pre-recorded tones of the ogg / mp3 sample, embedding them in separate audio elements and starting and stopping them when you press a key.
  • Insert a SWF file containing audio elements and control playback through JavaScript. (This is apparently a method that uses Google Les Paul Doodle .)
+25
Jun 14 2018-11-11T00:
source share

In most browsers, you can now use the Web Audio API ( except IE and Opera Mini ).

Try this code:

 // one context per document var context = new (window.AudioContext || window.webkitAudioContext)(); var osc = context.createOscillator(); // instantiate an oscillator osc.type = 'sine'; // this is the default - also square, sawtooth, triangle osc.frequency.value = 440; // Hz osc.connect(context.destination); // connect it to the destination osc.start(); // start the oscillator osc.stop(context.currentTime + 2); // stop 2 seconds after the current time 

If you want to decrease the volume, you can do something like this:

 var context = new webkitAudioContext(); var osc = context.createOscillator(); var vol = context.createGain(); vol.gain.value = 0.1; // from 0 to 1, 1 full volume, 0 is muted osc.connect(vol); // connect osc to vol vol.connect(context.destination); // connect vol to context destination osc.start(context.currentTime + 3); // start it three seconds from now 

I got most of this experience from experimenting in chrome by reading the Web API API of a working project , which I found from the @brainjam link.

Hope this helps. Finally, it is very useful to check various objects in the chrome inspector (ctrl-shift-i).

+52
May 15 '13 at 19:19
source share

Web Audio API is suitable for Chrome. See http://googlechrome.imtqy.com/web-audio-samples/samples/audio/index.html

Follow the instructions in the Getting Started section and then watch some very impressive demos.

Update (2017):, now it is a much more mature interface. The API is documented at https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API

+11
Jun 14 2018-11-11T00:
source share

Sure! You can use a tone synthesizer in this demo:

enter image description here

 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> 

Have some fun!

I got a solution from Houshalter here: How to make a Javascript beep?

You can clone and customize the code here: a demo version of the Tone synthesizer on JS Bin

Compatible browsers:

  • Chrome for mobile and desktop
  • Firefox for mobile and desktop PCs for mobile, mini and desktop computers
  • Android browser
  • Microsoft Edge Browser
  • Safari on iPhone or iPad

Not compatible

  • Internet Explorer version 11 (but works in Edge browser)
+8
Dec 12 '16 at 4:09
source share

You can generate the wav-e file on the fly and play it ( src )

 // Legend // DUR - duration in seconds SPS - sample per second (default 44100) // NCH - number of channels BPS - bytes per sample // t - is number from range [0, DUR), return number in range [0, 1] function getSampleAt(t,DUR,SPS) { return Math.sin(6000*t); } function genWAVUrl(fun, DUR=1, NCH=1, SPS=44100, BPS=1) { let size = DUR*NCH*SPS*BPS; let put = (n,l=4) => [(n<<24),(n<<16),(n<<8),n].filter((x,i)=>i<l).map(x=> String.fromCharCode(x>>>24)).join(''); let p = (...a) => a.map( b=> put(...[b].flat()) ).join(''); let data = 'RIFF${put(44+size)}WAVEfmt ${p(16,[1,2],[NCH,2],SPS,NCH*BPS*SPS,[NCH*BPS,2],[BPS*8,2])}data${put(size)}' for (let i = 0; i < DUR*SPS; i++) { let f= Math.min(Math.max(fun(i/SPS,DUR,SPS),0),1); data += put(Math.floor( f * (2**(BPS*8)-1)), BPS); } return "data:Audio/WAV;base64," + btoa(data); } var WAV = new Audio( genWAVUrl(getSampleAt,5) ); // 5s WAV.setAttribute("controls", "controls"); document.body.appendChild(WAV); //WAV.play() 

Here is the visualization

 function getSampleAt(t,DUR,SPS) { return 0.5+Math.sin(15*t)/(1+t*t); } // ---------------------------------------------- function genWAVUrl(fun, DUR=1, NCH=1, SPS=44100, BPS=1) { let size = DUR*NCH*SPS*BPS; let put = (n,l=4) => [(n<<24),(n<<16),(n<<8),n].filter((x,i)=>i<l).map(x=> String.fromCharCode(x>>>24)).join(''); let p = (...a) => a.map( b=> put(...[b].flat()) ).join(''); let data = 'RIFF${put(44+size)}WAVEfmt ${p(16,[1,2],[NCH,2],SPS,NCH*BPS*SPS,[NCH*BPS,2],[BPS*8,2])}data${put(size)}' for (let i = 0; i < DUR*SPS; i++) { let f= Math.min(Math.max(fun(i/SPS,DUR,SPS),0),1); data += put(Math.floor( f * (2**(BPS*8)-1)), BPS); } return "data:Audio/WAV;base64," + btoa(data); } function draw(fun, DUR=1, NCH=1, SPS=44100, BPS=1) { time.innerHTML=DUR+'s'; time.setAttribute('x',DUR-0.3); svgCh.setAttribute('viewBox','0 0 ${DUR} 1'); let p='', n=100; // n how many points to ommit for (let i = 0; i < DUR*SPS/n; i++) p+= ' ${DUR*(n*i/SPS)/DUR}, ${1-fun(n*i/SPS, DUR,SPS)}'; chart.setAttribute('points', p); } function frame() { let t=WAV.currentTime; point.setAttribute('cx',t) point.setAttribute('cy',1-getSampleAt(t)) window.requestAnimationFrame(frame); } function changeStart(e) { var r = e.target.getBoundingClientRect(); var x = e.clientX - r.left; WAV.currentTime = dur*x/r.width; WAV.play() } var dur=5; // seconds var WAV = new Audio(genWAVUrl(getSampleAt,dur)); draw(getSampleAt,dur); frame(); 
 .chart { border: 1px dashed #ccc; } .axis { font-size: 0.2px} audio { outline: none; } 
 Click at blue line (make volume to max): <svg class="chart" id="svgCh" onclick="changeStart(event)"> <circle cx="0" cy="-1" r="0.05" style="fill: rgba(255,0,0,1)" id="point"></circle> <polyline id="chart" fill="none" stroke="#0074d9" stroke-width="0.01" points=""/> <text x="0.03" y="0.9" class="axis">0</text> <text x="0.03" y="0.2" class="axis">1</text> <text x="4.8" y="0.9" class="axis" id="time"></text> </svg><br> 
+2
May 7 '19 at 7:38
source share

This is not a real answer to your question because you asked for a JavaScript solution, but you can use ActionScript. It should work on all major browsers.

You can call ActionScript functions from JavaScript.

That way, you can wrap the ActionScript sound generation functions and implement the JavaScript implementation. Just use Adobe Flex to create a tiny swf, and then use this as a backend for your JavaScript code.

+1
Dec 16 '15 at 1:57
source share

This is what I have been looking for forever, and in the end I managed to do it myself as I wanted. Maybe you will like it too. Simple slider with frequency and pressing on / off:

 buttonClickResult = function () { var button = document.getElementById('btn1'); button.onclick = function buttonClicked() { if(button.className=="off") { button.className="on"; oscOn (); } else if(button.className=="on") { button.className="off"; oscillator.disconnect(); } } }; buttonClickResult(); var oscOn = function(){ window.AudioContext = window.AudioContext || window.webkitAudioContext; var context = new AudioContext(); var gainNode = context.createGain ? context.createGain() : context.createGainNode(); //context = new window.AudioContext(); oscillator = context.createOscillator(), oscillator.type ='sine'; oscillator.frequency.value = document.getElementById("fIn").value; //gainNode = createGainNode(); oscillator.connect(gainNode); gainNode.connect(context.destination); gainNode.gain.value = 1; oscillator.start(0); }; 
 <p class="texts">Frekvence [Hz]</p> <input type="range" id="fIn" min="20" max="20000" step="100" value="1234" oninput="show()" /> <span id="fOut"></span><br> <input class="off" type="button" id="btn1" value="Start / Stop" /> 
0
Mar 28 '17 at 21:10
source share



All Articles