| <!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> |