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