blob: 0a56884cc427f8ea63ad2eb743d3078fcedec6ce [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script>
<script src="../resources/js-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script>
// These are global to make debugging a little easier.
var context;
var buffer;
var source;
var renderedData;
var trueData;
var signalEnergy;
var noiseEnergy;
var maxError;
// Context sample rate.
var sampleRate = 48000;
// The sample rate of the buffer.
var bufferRate = 3000;
// The audio buffer is a sine wave of this frequency.
var toneFrequency = 440;
// How long test is
var lengthInSeconds = 0.5;
// The maximum allowed peak error between the actual and true output. This value was
// experimentally determined for the given bufferRate.
var peakThreshold = 0.11;
// The minimum SNR allowed between the actual and true output.
var snrThreshold = 22.35;
description("Test resampling of an AudioBuffer at " + bufferRate + " Hz");
function log10(x) {
return Math.log(x)/Math.LN10;
}
// Generate a sine wave in an AudioBuffer using the given |freq|. The AudioBuffer has the
// sample rate of |rate|.
function createSineBuffer(context, freq, rate) {
var buf = context.createBuffer(1, lengthInSeconds * rate, rate);
var omega = 2 * Math.PI * freq / rate;
var signal = buf.getChannelData(0);
var length = signal.length;
for (var k = 0; k < length; ++k)
signal[k] = Math.sin(omega * k);
return buf;
}
// Check the output against the expected output.
function checkResult(event) {
renderedData = event.renderedBuffer.getChannelData(0);
var length = renderedData.length;
// Generate a reference sine wave at the context rate
var trueReference = createSineBuffer(context, toneFrequency, context.sampleRate);
trueData = trueReference.getChannelData(0);
// To compare the actual output against the reference, we compute the peak error and the
// SNR between the two.
signalEnergy = 0;
noiseEnergy = 0;
maxError = -1;
var success = true;
// Compute the peak error and the SNR.
for (var k = 0; k < length / 2; ++k) {
var diff = renderedData[k] - trueData[k];
noiseEnergy += diff * diff;
signalEnergy += trueData[k] * trueData[k];
if (Math.abs(diff) > maxError)
maxError = Math.abs(diff);
}
var snr;
if (noiseEnergy == 0)
snr = 1000;
else
snr = 10 * log10(signalEnergy / noiseEnergy);
if (maxError < peakThreshold) {
testPassed("Peak error between actual and reference data below threshold of " +
peakThreshold + ".");
} else {
testFailed("Peak error of " + maxError + " exceeds threshold of " +
peakThreshold + ".");
success = false;
}
if (snr > snrThreshold) {
testPassed("SNR exceeds threshold of " + snrThreshold + " dB.");
} else {
testFailed("SNR of " + snr + " is below the threshold of " + snrThreshold + ".");
success = false;
}
if (success)
testPassed("AudioBuffer resampling is accurate for buffer rate of " +
bufferRate + " Hz.");
else
testFailed("AudioBuffer resampling is not accurate enough for buffer rate of " +
bufferRate + " Hz.");
finishJSTest();
}
function runTest() {
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
}
window.jsTestIsAsync = true;
context = new OfflineAudioContext(1, lengthInSeconds * sampleRate, sampleRate);
// Create a sine wave in a buffer that's different from the context rate to test
// resampling.
buffer = createSineBuffer(context, toneFrequency, bufferRate);
source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.start();
context.oncomplete = checkResult;
context.startRendering();
}
runTest();
successfullyParsed = true;
</script>
</body>
</html>