blob: 8c51cb95fdafcda72728d7fcf73d697f3d3d2546 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>
Test Different PeriodicWave Lengths at Different Sample Rates
</title>
<script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../resources/audit-util.js"></script>
<script src="../resources/audit.js"></script>
</head>
<body>
<script id="layout-test-code">
// 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.
let renderLength = 1;
let context;
let 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.
let 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.
{
name: '192khz-test-3',
sampleRate: 192000,
bigWave: 8192,
smallWave: 8191,
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(should, sampleRate, bigLength, smallLength) {
return function(buffer) {
let prefix = generatePrefix(sampleRate, bigLength, smallLength);
should(isBufferZero(buffer), prefix + 'are identical')
.beEqualTo(true);
}
}
// Returns a function the verifies that the result is non-zero. The
// parameters control what is printed in the messages.
function resultShouldBeNonZero(
should, sampleRate, bigLength, smallLength) {
return function(buffer) {
let prefix = generatePrefix(sampleRate, bigLength, smallLength);
should(!isBufferZero(buffer), prefix + 'are different')
.beEqualTo(true);
}
}
// 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 (task, should) => {
// Create the audio graph, render it, and then verify that the output
// is the expected result.
createAudioGraph(sampleRate, bigLength, smallLength);
return context.startRendering()
.then(verifier(should, sampleRate, bigLength, smallLength))
.then(() => task.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.
let smallWaveRealCoef = new Float32Array(smallPeriodicWaveLength);
let smallWaveImagCoef = new Float32Array(smallPeriodicWaveLength);
let bigWaveRealCoef = new Float32Array(bigPeriodicWaveLength);
let bigWaveImagCoef = new Float32Array(bigPeriodicWaveLength);
// Set up the Fourier coefficients for a sawtooth wave. We use
// sawtooth because all coefficients are non-zero
bigWaveImagCoef[0] = 0;
for (let k = 1; k < bigPeriodicWaveLength; k++) {
let piFactor = 2 / (Math.PI * k);
bigWaveImagCoef[k] = piFactor * ((k % 2 === 0) ? -1 : 1);
if (k < smallPeriodicWaveLength)
smallWaveImagCoef[k] = bigWaveImagCoef[k];
}
let smallPeriodicWave =
context.createPeriodicWave(smallWaveRealCoef, smallWaveImagCoef);
let bigPeriodicWave =
context.createPeriodicWave(bigWaveRealCoef, bigWaveImagCoef);
// Create oscillators using these PeriodicWave's.
let smallOscillator = context.createOscillator();
let 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.
let 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 (let k = 0; k < testSet.length; ++k) {
let {name, sampleRate, bigWave, smallWave, verifier} = testSet[k];
let actualName = actualTestName(name, k);
audit.define(
actualName,
createAuditTestFunction(
sampleRate, bigWave, smallWave, verifier));
}
}
defineAuditTests();
audit.run();
</script>
</body>
</html>