tone generator

Generates tone from a frequency and a duration in riff wave

by francisfortier

HTML

<audio id="tone" controls="controls"></audio>

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);