blob: 5ecd7b3d579797955245b6f850e6f7c8c43ef9da [file] [log] [blame]
<!doctype html>
<html>
<head>
<title>Test Different PeriodicWave Lengths at Different Sample Rates</title>
<script src="../resources/js-test.js"></script>
<script src="resources/compatibility.js"></script>
<script src="resources/audio-testing.js"></script>
</head>
<body>
<script>
description("Test Different PeriodicWave Lengths at Different Sample Rates");
window.jsTestIsAsync = true;
// Test PeriodicWave objects with varying number of coefficients at different sample rates.
// Basically, verify that the coefficients are used at the appropriate sample rates. This is
// done by comparing the outputs of two periodic waves used in oscillators. The output should
// either be exactly zero or not depending on whether the coefficients were used.
var renderLength = 1;
var context;
var audit = Audit.createTaskRunner();
// The set of Audit tests to be run to verify that PeriodicWave is using the correct number of
// coefficients. The name does not have to be unique; the index of the entry is appended to
// the test. Every entry (except the last) needs sampleRate, bigWave, smallWave, and
// verifier values.
var testSet = [
// Tests for contexts at 192 kHz.
// Test that we use more than 2048 Fourier coefficients at 192 kHz sample rate. Basically
// verifies that 8192 is acceptable.
{
name: "192khz-test-1",
sampleRate: 192000,
bigWave: 8192,
smallWave: 2048,
verifier: resultShouldBeNonZero
},
// Test that we use at least 2049 Fourier coefficients at 192 kHz sample rate.
{
name: "192khz-test-2",
sampleRate: 192000,
bigWave: 2049,
smallWave: 2048,
verifier: resultShouldBeNonZero
},
// Test that we use all 8192 Fourier coefficients at 192 kHz sample rate. Ideally, we'd
// like to compare 8191 coefficients vs 8192 coefficients. However, due to single-precision
// arithmetic, the wave forms are identical in this case. Thus, use a somewhat smaller
// value where the wave forms are actually different.
{
name: "192khz-test-3",
sampleRate: 192000,
bigWave: 8192,
smallWave: (8 - 1 / 256) * 1024,
verifier: resultShouldBeNonZero
},
// Tests for contexts at 48 kHz.
// Test that we do not use more than 2048 Fourier coefficients at 48 kHz. This depends on
// the internal implementation where, for backward compatibility and speed, we only use 2048
// coefficients at 48 kHz. (This is also true for rates below 88.2 kHz.) Also tests that
// 8192 coefficients are allowed (but not all coefficients are used, of course).
{
name: "48khz-test-1",
sampleRate: 48000,
bigWave: 8192,
smallWave: 2048,
verifier: resultShouldBeZero
},
// Test that we do not use more than 2048 Fourier coefficients.
{
name: "48khz-test-2",
sampleRate: 48000,
bigWave: 2049,
smallWave: 2048,
verifier: resultShouldBeZero
},
// It's not immediately clear with single-preicison arithmetic that we can distinguish
// between 2049 and 2048 coefficients, so do one more test with slightly more coefficients.
{
name: "48khz-test-3",
sampleRate: 48000,
bigWave: (2 + 1 / 64) * 1024,
smallWave: 2048,
verifier: resultShouldBeZero
},
// Test that we use at least 2048 Fourier coefficients at 48 kHz. Ideally we want to
// compare 2047 and 2048 coefficients, but single-precision arithmetic makes the resulting
// waveforms the same. Hence use a smaller value that produces different waveforms.
{
name: "48khz-test-4",
sampleRate: 48000,
bigWave: 2048,
smallWave: 2046,
verifier: resultShouldBeNonZero
},
// Tests for contexts at 24 kHz.
// Test that we do not use more than 1024 Fourier coefficients at 24 kHz.
{
name: "24khz-test-1",
sampleRate: 24000,
bigWave: 8192,
smallWave: 1024,
verifier: resultShouldBeZero
},
// Test that we do not use more than 1024 Fourier coefficients at 24 kHz.
{
name: "24khz-test-2",
sampleRate: 24000,
bigWave: 1025,
smallWave: 1024,
verifier: resultShouldBeZero
},
// Test that we use at least 1024 Fourier coefficients at 24 kHz. Again, 1023 and 1024
// produce the same waveforms in single-precisiion so use a smaller wave table size.
{
name: "24khz-test-3",
sampleRate: 24000,
bigWave: 1024,
smallWave: 1022,
verifier: resultShouldBeNonZero
},
];
function generatePrefix (sampleRate, bigLength, smallLength) {
return "At " + (sampleRate / 1000) + " kHz, PeriodicWave with "
+ bigLength + " coefficients vs "
+ smallLength + ": ";
}
// Returns a function the verifies that the result is zero. The parameters control what is
// printed in the messages.
function resultShouldBeZero(sampleRate, bigLength, smallLength) {
return function (buffer) {
var prefix = generatePrefix(sampleRate, bigLength, smallLength);
if (isBufferZero(buffer))
testPassed(prefix + "identical as expected.");
else
testFailed(prefix + "unexpectedly differ.");
}
}
// Returns a function the verifies that the result is non-zero. The parameters control what is
// printed in the messages.
function resultShouldBeNonZero(sampleRate, bigLength, smallLength) {
return function (buffer) {
var prefix = generatePrefix(sampleRate, bigLength, smallLength);
if (!isBufferZero(buffer))
testPassed(prefix + "differ as expected.");
else
testFailed(prefix + "unexpectedly are identical.");
}
}
// Creates a function that is used to run an Audit test for a given sample rate, periodic wave
// sizes, and verifier.
function createAuditTestFunction(sampleRate, bigLength, smallLength, verifier) {
return function (done) {
// Create the audio graph, render it, and then verify that the output is the expected
// result.
createAudioGraph(sampleRate, bigLength, smallLength);
context.startRendering()
.then(verifier(sampleRate, bigLength, smallLength))
.then(done);
}
}
// Create the audio graph for the test.
function createAudioGraph(sampleRate, bigPeriodicWaveLength, smallPeriodicWaveLength) {
context = new OfflineAudioContext(1, renderLength * sampleRate, sampleRate);
// Two PeriodicWave objects are created with different sizes (small and big). The contents
// are the same except that the samll sized PeriodicWave has fewer coefficients.
var smallWaveRealCoef = new Float32Array(smallPeriodicWaveLength);
var smallWaveImagCoef = new Float32Array(smallPeriodicWaveLength);
var bigWaveRealCoef = new Float32Array(bigPeriodicWaveLength);
var bigWaveImagCoef = new Float32Array(bigPeriodicWaveLength);
// Set up the Fourier coefficients for a square wave.
for (var k = 0; k < bigPeriodicWaveLength; k += 2) {
bigWaveImagCoef[k] = 4 / Math.PI / k;
if (k < smallPeriodicWaveLength)
smallWaveImagCoef[k] = bigWaveImagCoef[k];
}
var smallPeriodicWave = context.createPeriodicWave(smallWaveRealCoef, smallWaveImagCoef);
var bigPeriodicWave = context.createPeriodicWave(bigWaveRealCoef, bigWaveImagCoef);
// Create oscillators using these PeriodicWave's.
var smallOscillator = context.createOscillator();
var bigOscillator = context.createOscillator();
smallOscillator.setPeriodicWave(smallPeriodicWave);
bigOscillator.setPeriodicWave(bigPeriodicWave);
// Use a frequency of 1 Hz to make the distinction easier. Can't tell from this test, but
// if you plot the signals from these oscillators, it's very clear that they are different.
smallOscillator.frequency.value = 1;
bigOscillator.frequency.value = 1;
// The desired output is the difference between these oscillators.
var gain = context.createGain();
gain.gain.value = -1;
smallOscillator.connect(gain);
gain.connect(context.destination);
bigOscillator.connect(context.destination);
// Start the oscillators.
smallOscillator.start();
bigOscillator.start();
}
// Return true if the buffer is exactly zero.
function isBufferZero(buffer) {
if (buffer.getChannelData(0).find(function (x) { return x != 0; }))
return false;
return true;
}
// Ensure the actual Audit test name is unique by prepending an index to the provided test
// name.
function actualTestName(name, index) {
return index + ":" + name;
}
// Define the tasks based on the entries in testSet.
function defineAuditTests () {
for (var k = 0; k < testSet.length; ++k) {
var test = testSet[k];
var actualName = actualTestName(test.name, k);
audit.defineTask(actualName,
createAuditTestFunction(test.sampleRate, test.bigWave, test.smallWave, test.verifier));
}
// Define the finish test last.
audit.defineTask(actualTestName("finish-tests", testSet.length), function (done) {
finishJSTest();
done();
});
}
defineAuditTests();
audit.runTasks();
successfullyParsed = true;
</script>
</body>
</html>