blob: c3ecc0a333dce0d5938c2ec4992b80c9b64e02f7 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>
Test fftSize Changes Resetting AnalyserNode State
</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">
// Fairly arbitrary sample rate.
let sampleRate = 24000;
let audit = Audit.createTaskRunner();
// Verify that setting the fftSize resets the memory for the FFT smoothing
// operation. Only a few of the possible variations are tested.
audit.define('128->1024', (task, should) => {
testFFTSize(should, {
initialFFTSize: 128,
finalFFTSize: 1024,
errorThreshold: {relativeThreshold: 3.6296e-6}
}).then(() => task.done());
});
audit.define('512->256', (task, should) => {
testFFTSize(should, {
initialFFTSize: 512,
finalFFTSize: 256,
errorThreshold: {relativeThreshold: 1.8614e-6}
}).then(() => task.done());
});
function testFFTSize(should, options) {
let {initialFFTSize, finalFFTSize, errorThreshold} = options;
// The duration is fairly arbitrary as long as it's long enough for the
// FFT test.
let context = new OfflineAudioContext(1, sampleRate, sampleRate);
// Actual source doesn't matter but a sawtooth is a nice waveform with
// lots of harmonic content.
let osc = context.createOscillator();
osc.type = 'sawtooth';
// The analyser under test.
let testAnalyser = context.createAnalyser();
testAnalyser.fftSize = initialFFTSize;
// The reference analyser. The fftSize is fixed to the desired value,
// and we turn off smoothing so that we get the FFT of the current time
// data.
let refAnalyser = context.createAnalyser();
refAnalyser.fftSize = finalFFTSize;
refAnalyser.smoothingTimeConstant = 0;
// Setup the graph and start the oscillator.
osc.connect(testAnalyser).connect(context.destination);
osc.connect(refAnalyser).connect(context.destination);
osc.start();
// Let the analyser smooth a few FFTs (rather arbitrary, but should be
// more than one), then switch the size.
let suspendFrame = 4 * initialFFTSize;
context.suspend(suspendFrame / context.sampleRate)
.then(function() {
testAnalyser.fftSize = finalFFTSize;
})
.then(context.resume.bind(context));
// Wait some frames and grab the FFT data. This is fairly arbitrary
// too, and can be independent of the FFT sizes.
suspendFrame += 1024;
context.suspend(suspendFrame / context.sampleRate)
.then(function() {
let testFFT = new Float32Array(testAnalyser.frequencyBinCount);
let refFFT = new Float32Array(refAnalyser.frequencyBinCount)
let testSignal = new Float32Array(testAnalyser.fftSize);
let refSignal = new Float32Array(refAnalyser.fftSize);
testAnalyser.getFloatTimeDomainData(testSignal);
refAnalyser.getFloatTimeDomainData(refSignal);
testAnalyser.getFloatFrequencyData(testFFT);
refAnalyser.getFloatFrequencyData(refFFT);
// Convert the FFT data from dB to linear
testFFT = testFFT.map(x => Math.pow(10, x / 20));
refFFT = refFFT.map(x => Math.pow(10, x / 20));
// The test data has smoothing applied, but the reference doesn't.
// Apply the smoothing factor to the reference data.
let smoothing = 1 - testAnalyser.smoothingTimeConstant;
refFFT = refFFT.map(x => x * smoothing);
// First a basic sanity check that the time domain signals are
// exactly the same for both analysers.
should(testSignal, 'Time data').beCloseToArray(refSignal, 0);
should(
testFFT,
'Linear FFT data after setting fftSize = ' +
testAnalyser.fftSize)
.beCloseToArray(refFFT, errorThreshold);
})
.then(context.resume.bind(context));
return context.startRendering();
}
audit.run();
</script>
</body>
</html>