JavaScript
// RIFF WAVE template header with fmt and data chunks
HEADER = [82, 73, 70, 70, 0, 0, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 1, 0, 1, 0, 68, 172, 0, 0, 136, 88, 1, 0, 2, 0, 16, 0, 100, 97, 116, 97, 0, 0, 0, 0];
SAMPLE_RATE = 44100;
BLOCK_ALIGN = 2
AVG_BYTES_PER_SEC = SAMPLE_RATE * BLOCK_ALIGN;
window.BlobBuilder = window.BlobBuilder || window.mozBlobBuilder || window.WebKitBlobBuilder;
window.URL = window.URL || window.webkitURL;
var f = function(frequency, amplitude, duration) {
var tone = document.getElementById("tone");
var headerBuffer = new ArrayBuffer(HEADER.length);
var headerArray = new Uint8Array(headerBuffer);
for (var i = 0; i < headerArray.length; i++) {
headerArray[i] = HEADER[i];
}
var a = new Uint32Array(headerBuffer);
a[1] = AVG_BYTES_PER_SEC * duration + HEADER.length - 8; // RIFF size
a[10] = AVG_BYTES_PER_SEC * duration; // data size
var dataBuffer = new ArrayBuffer(AVG_BYTES_PER_SEC * duration);
var sampleArray = new Int16Array(dataBuffer);
var k = 2 * Math.PI * frequency / SAMPLE_RATE;
for (var i = 2; i < sampleArray.length; i++) {
sampleArray[i] = Math.sin(k * i) * amplitude;
}
var builder = new BlobBuilder();
builder.append(headerBuffer);
builder.append(dataBuffer);
var soundBlob = builder.getBlob("audio/wav");
var soundUrl = window.URL.createObjectURL(soundBlob);
tone.type = "audio/wav";
tone.src = soundUrl;
tone.play();
};
var keys = [261.626, 293.665, 329.628, 349.228, 391.995, 440.000, 493.883, 523.251];
var amplitudes = [0x0fff, 0x1fff, 0x2fff, 0x3fff, 0x4fff, 0x5fff, 0x6fff, 0x7fff];
document.getElementById("tone").addEventListener("ended", function() {
if (keys.length > 0) f(keys.shift(), amplitudes.shift(), 0.5);
}, false);
f(keys.shift(), amplitudes.shift(), 0.5);