<!DOCTYPE html>

<!--
Tests that AudioBufferSourceNode can playback at different rates properly.
Render 72 notes over a 6 octave range.
-->

<html>
<head>
<script type="text/javascript" src="resources/audio-testing.js"></script>
<script type="text/javascript" src="resources/buffer-loader.js"></script>

</head>
<body>

<script>

window.onload = init;

var sampleRate = 44100.0;
var numberOfNotes = 72; // play over a 6 octave range
var noteDuration = 0.050;
var noteSpacing = noteDuration + 0.005; // leave 5ms of silence between each "note"
var lengthInSeconds = numberOfNotes * noteSpacing;

var context = 0;
var sinWaveBuffer = 0;

function createOneCycleSinWaveBuffer(frequency, sampleRate) {
    var duration = 1 / frequency;
    var sampleFrameLength = duration * sampleRate;
    
    var audioBuffer = context.createBuffer(2, sampleFrameLength, sampleRate);

    var n = audioBuffer.length;
    var channelL = audioBuffer.getChannelData(0);
    var channelR = audioBuffer.getChannelData(1);

    for (var i = 0; i < n; ++i) {
        channelL[i] = Math.sin(frequency * 2.0*Math.PI * i / sampleRate);
        channelR[i] = channelL[i];
    }

    return audioBuffer;
}

function playNote(time, duration, playbackRate) {
    var source = context.createBufferSource();
    source.buffer = sinWaveBuffer;
    source.playbackRate.value = playbackRate;
    
    var gainNode = context.createGain();
    source.connect(gainNode);
    gainNode.connect(context.destination);

    // Loop and play for the given duration.
    source.loop = true;
    source.start(time);
    source.stop(time + duration);
    
    // Apply quick fade-in and fade-out to avoid clicks.
    gainNode.gain.value = 0;
    gainNode.gain.setValueAtTime(0, time);
    gainNode.gain.linearRampToValueAtTime(1, time + 0.005);
    gainNode.gain.setValueAtTime(1, time + duration - 0.005);
    gainNode.gain.linearRampToValueAtTime(0, time + duration);
}

function init() {
    if (!window.testRunner)
        return;

    // Create offline audio context.
    context = new OfflineAudioContext(2, sampleRate * lengthInSeconds, sampleRate);

    // Create a single cycle of a sine wave.
    // We'll loop this to play notes of a given duration, at a given playback rate.
    sinWaveBuffer = createOneCycleSinWaveBuffer(440.0, sampleRate);

    // Play 48 notes over a 4 octave range.
    for (var i = 0; i < numberOfNotes; ++i) {
        var time = i * noteSpacing;

        var semitone = i - numberOfNotes/2; // start three octaves down
        
        // Convert from semitone to rate.
        var playbackRate = Math.pow(2, semitone / 12);

        playNote(time, noteDuration, playbackRate);
    }

    context.oncomplete = finishAudioTest;
    context.startRendering();

    testRunner.waitUntilDone();
}

</script>

</body>
</html>
