blob: 5601d0255afd8a5c36499a821347c9ecb1b46d7d [file] [log] [blame]
<!DOCTYPE html>
<!--
Tests that AudioBufferSourceNode supports loop-points with .loopStart and .loopEnd.
-->
<html>
<head>
<script type="text/javascript" src="resources/audio-testing.js"></script>
</head>
<body>
<script>
window.onload = init;
var sampleRate = 44100.0;
var numberOfNotes = 72; // play over a 6 octave range
var noteDuration = 0.100;
var noteSpacing = noteDuration + 0.005; // leave 5ms of silence between each "note"
var lengthInSeconds = numberOfNotes * noteSpacing;
var context = 0;
var buffer = 0;
function createTestBuffer(frequency, sampleRate) {
// Create a buffer containing two periods at this frequency.
// The 1st half is a pure sine wave period scaled by a linear ramp from 0 -> 1.
// The 2nd half of the buffer corresponds exactly to one pure sine wave period.
var onePeriodDuration = 1 / frequency;
var sampleFrameLength = 2 * onePeriodDuration * sampleRate;
var audioBuffer = context.createBuffer(1, sampleFrameLength, sampleRate);
var n = audioBuffer.length;
var channelData = audioBuffer.getChannelData(0);
for (var i = 0; i < n; ++i) {
var sample = Math.sin(frequency * 2.0*Math.PI * i / sampleRate);
// Linear ramp from 0 -> 1 for the first period.
// Stay at 1 for the 2nd period.
var scale = i < n / 2 ? i / (n / 2) : 1;
sample *= scale;
channelData[i] = sample;
}
return audioBuffer;
}
function playNote(time, duration, playbackRate) {
var source = context.createBufferSource();
source.buffer = buffer;
source.playbackRate.value = playbackRate;
var gainNode = context.createGainNode();
source.connect(gainNode);
gainNode.connect(context.destination);
// Loop the 2nd half of the buffer.
// We should be able to hear any problems as glitches if the looping incorrectly indexes to
// anywhere outside of the desired loop-points, since only the 2nd half is a perfect sine-wave cycle,
// while the 1st half of the buffer contains a linear ramp of a sine-wave cycle.
source.loop = true;
source.loopStart = 0.5 * buffer.duration;
source.loopEnd = buffer.duration;
// Play for the given duration.
source.start(time);
source.stop(time + duration);
// Apply a quick linear fade-out to avoid a click at the end of the note.
gainNode.gain.value = 1;
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 webkitOfflineAudioContext(2, sampleRate * lengthInSeconds, sampleRate);
// Create the test buffer.
// We'll loop this with the loop-points set for the 2nd half of this buffer.
buffer = createTestBuffer(440.0, sampleRate);
// Play all the notes as a chromatic scale.
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>