| OLD | NEW |
| (Empty) | |
| 1 <!doctype html> |
| 2 <html> |
| 3 <head> |
| 4 <title>Test fftSize Changes Resetting AnalyserNode State </title> |
| 5 <script src="../resources/testharness.js"></script> |
| 6 <script src="../resources/testharnessreport.js"></script> |
| 7 <script src="resources/audio-testing.js"></script> |
| 8 </head> |
| 9 |
| 10 <body> |
| 11 <script> |
| 12 // Fairly arbitrary sample rate. |
| 13 var sampleRate = 24000; |
| 14 |
| 15 var audit = Audit.createTaskRunner(); |
| 16 |
| 17 // Verify that setting the fftSize resets the memory for the FFT smoothing |
| 18 // operation. Only a few of the possible variations are tested. |
| 19 |
| 20 audit.defineTask("128->1024", function (taskDone) { |
| 21 testFFTSize({ |
| 22 initialFFTSize: 128, |
| 23 finalFFTSize: 1024, |
| 24 errorThreshold: { |
| 25 relativeThreshold: 1.9095e-6 |
| 26 } |
| 27 }).then(taskDone); |
| 28 }); |
| 29 |
| 30 audit.defineTask("512->256", function (taskDone) { |
| 31 testFFTSize({ |
| 32 initialFFTSize: 512, |
| 33 finalFFTSize: 256, |
| 34 errorThreshold: { |
| 35 relativeThreshold: 1.8166e-6 |
| 36 } |
| 37 }).then(taskDone); |
| 38 }); |
| 39 |
| 40 function testFFTSize(options) { |
| 41 var { |
| 42 initialFFTSize, finalFFTSize, errorThreshold |
| 43 } = options; |
| 44 |
| 45 // The duration is fairly arbitrary as long as it's long enough for the |
| 46 // FFT test. |
| 47 var context = new OfflineAudioContext(1, sampleRate, sampleRate); |
| 48 |
| 49 // Actual source doesn't matter but a sawtooth is a nice waveform with |
| 50 // lots of harmonic content. |
| 51 var osc = context.createOscillator(); |
| 52 osc.type = "sawtooth"; |
| 53 |
| 54 // The analyser under test. |
| 55 var testAnalyser = context.createAnalyser(); |
| 56 testAnalyser.fftSize = initialFFTSize; |
| 57 |
| 58 // The reference analyser. The fftSize is fixed to the desired value, |
| 59 // and we turn off smoothing so that we get the FFT of the current time |
| 60 // data. |
| 61 var refAnalyser = context.createAnalyser(); |
| 62 refAnalyser.fftSize = finalFFTSize; |
| 63 refAnalyser.smoothingTimeConstant = 0; |
| 64 |
| 65 // Setup the graph and start the oscillator. |
| 66 osc.connect(testAnalyser) |
| 67 .connect(context.destination); |
| 68 osc.connect(refAnalyser) |
| 69 .connect(context.destination); |
| 70 |
| 71 osc.start(); |
| 72 |
| 73 // Let the analyser smooth a few FFTs (rather arbitrary, but should be |
| 74 // more than one), then switch the size. |
| 75 |
| 76 var suspendFrame = 4 * initialFFTSize; |
| 77 context.suspend(suspendFrame / context.sampleRate) |
| 78 .then(function () { |
| 79 testAnalyser.fftSize = finalFFTSize; |
| 80 }) |
| 81 .then(context.resume.bind(context)); |
| 82 |
| 83 // Wait some frames and grab the FFT data. This is fairly arbitrary |
| 84 // too, and can be independent of the FFT sizes. |
| 85 suspendFrame += 1024; |
| 86 context.suspend(suspendFrame / context.sampleRate) |
| 87 .then(function () { |
| 88 var testFFT = new Float32Array(testAnalyser.frequencyBinCount); |
| 89 var refFFT = new Float32Array(refAnalyser.frequencyBinCount) |
| 90 var testSignal = new Float32Array(testAnalyser.fftSize); |
| 91 var refSignal = new Float32Array(refAnalyser.fftSize); |
| 92 |
| 93 testAnalyser.getFloatTimeDomainData(testSignal); |
| 94 refAnalyser.getFloatTimeDomainData(refSignal); |
| 95 |
| 96 testAnalyser.getFloatFrequencyData(testFFT); |
| 97 refAnalyser.getFloatFrequencyData(refFFT); |
| 98 |
| 99 // Convert the FFT data from dB to linear |
| 100 testFFT = testFFT.map(x => Math.pow(10, x / 20)); |
| 101 refFFT = refFFT.map(x => Math.pow(10, x / 20)); |
| 102 |
| 103 // The test data has smoothing applied, but the reference doesn't. |
| 104 // Apply the smoothing factor to the reference data. |
| 105 var smoothing = 1 - testAnalyser.smoothingTimeConstant; |
| 106 refFFT = refFFT.map(x => x * smoothing); |
| 107 |
| 108 var success = true; |
| 109 |
| 110 // First a basic sanity check that the time domain signals are |
| 111 // exactly the same for both analysers. |
| 112 success = Should("Time data", testSignal) |
| 113 .beCloseToArray(refSignal, 0) && success; |
| 114 |
| 115 success = Should("Linear FFT data after setting fftSize = " + testAn
alyser.fftSize, |
| 116 testFFT) |
| 117 .beCloseToArray(refFFT, errorThreshold) && success; |
| 118 |
| 119 Should("*** Changing fftSize from " + initialFFTSize + " to " + fina
lFFTSize, success) |
| 120 .summarize( |
| 121 "correctly reset the smoothing state", |
| 122 "did not correctly reset the smoothing state"); |
| 123 }) |
| 124 .then(context.resume.bind(context)); |
| 125 |
| 126 return context.startRendering(); |
| 127 } |
| 128 |
| 129 audit.runTasks(); |
| 130 </script> |
| 131 </body> |
| 132 </html> |
| OLD | NEW |