blob: 0f7666e5d95f4889a0e3a69db29db1dd353f0586 [file] [log] [blame]
<!doctype html>
<html>
<head>
<title>Test fftSize Changes Resetting AnalyserNode State </title>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="resources/audio-testing.js"></script>
</head>
<body>
<script>
// Fairly arbitrary sample rate.
var sampleRate = 24000;
var 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.defineTask("128->1024", function (taskDone) {
testFFTSize({
initialFFTSize: 128,
finalFFTSize: 1024,
errorThreshold: {
relativeThreshold: 1.9095e-6
}
}).then(taskDone);
});
audit.defineTask("512->256", function (taskDone) {
testFFTSize({
initialFFTSize: 512,
finalFFTSize: 256,
errorThreshold: {
relativeThreshold: 1.8166e-6
}
}).then(taskDone);
});
function testFFTSize(options) {
var {
initialFFTSize, finalFFTSize, errorThreshold
} = options;
// The duration is fairly arbitrary as long as it's long enough for the
// FFT test.
var context = new OfflineAudioContext(1, sampleRate, sampleRate);
// Actual source doesn't matter but a sawtooth is a nice waveform with
// lots of harmonic content.
var osc = context.createOscillator();
osc.type = "sawtooth";
// The analyser under test.
var 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.
var 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.
var 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 () {
var testFFT = new Float32Array(testAnalyser.frequencyBinCount);
var refFFT = new Float32Array(refAnalyser.frequencyBinCount)
var testSignal = new Float32Array(testAnalyser.fftSize);
var 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.
var smoothing = 1 - testAnalyser.smoothingTimeConstant;
refFFT = refFFT.map(x => x * smoothing);
var success = true;
// First a basic sanity check that the time domain signals are
// exactly the same for both analysers.
success = Should("Time data", testSignal)
.beCloseToArray(refSignal, 0) && success;
success = Should("Linear FFT data after setting fftSize = " + testAnalyser.fftSize,
testFFT)
.beCloseToArray(refFFT, errorThreshold) && success;
Should("*** Changing fftSize from " + initialFFTSize + " to " + finalFFTSize, success)
.summarize(
"correctly reset the smoothing state",
"did not correctly reset the smoothing state");
})
.then(context.resume.bind(context));
return context.startRendering();
}
audit.runTasks();
</script>
</body>
</html>