JSFiddle - React, Tailwind, and code Playground
by Ehsan Ziya
HTML
<p><strong>Please note that you need a recent Webkit browser for this to work.</strong></p>
<ol><li>Try to make a rhythm by clicking repeatedly on the left button: notice that it works. There is no perceptible delay.</li><li>Now try to do the same with the second button: there is too much delay!</li></ol>
<button onmousedown="this.innerHTML='Playing, release mouse to stop!'; playBuffer()" onmouseup="this.innerHTML='Play Buffer'; stopBuffer()">Play Buffer</button>
<button onmousedown="this.innerHTML='Playing, release mouse to stop!'; playLive();" onmouseup="this.innerHTML='Play Live'; stopLive()">Play Live</button>
JavaScript
var ac = new webkitAudioContext();
var Instrument = function(freq, ac)
{
this.ac = ac;
this.phase = 0;
this.delta_phase = freq / ac.sampleRate;
this.getSample = function()
{
return Math.sin(2*Math.PI*this.phase);
}
this.fillBuffer = function(buffer, length)
{
for(var i=0; i<length; i++)
{
buffer[i] = this.getSample();
this.phase += this.delta_phase;
}
};
};
/*
* Build an instrument to play a 440Hz A note
*/
var sineStrument = new Instrument(440, ac);
var bufferLength = ac.sampleRate; // 1 second
var buffer = ac.createBuffer(1, bufferLength, ac.sampleRate);
sineStrument.fillBuffer(buffer.getChannelData(0), buffer.length);
/*
* Setup offline processing
* We build a buffer then play it when the user clicks on the "Play Buffer" button
*/
var source;
function playBuffer()
{
source = ac.createBufferSource();
source.buffer = buffer;
source.connect(ac.destination);
source.start(0);
};
function stopBuffer()
{
source.stop(0);
};
/*
* Live processing
* We use the same algorithm to generate the tone,
* but keep generating it as long as the button is pressed.
*/
var processor;
function playLive()
{
processor = ac.createScriptProcessor(4096, 0, 1);
processor.onaudioprocess = function(e)
{
sineStrument.fillBuffer(e.outputBuffer.getChannelData(0), e.outputBuffer.length);
}
processor.connect(ac.destination);
};
function stopLive()
{
processor.disconnect();
};