| OLD | NEW |
| (Empty) |
| 1 <!doctype html> | |
| 2 <html> | |
| 3 <head> | |
| 4 <script src="../resources/js-test.js"></script> | |
| 5 <script src="resources/compatibility.js"></script> | |
| 6 <script src="resources/audit-util.js"></script> | |
| 7 <script src="resources/audio-testing.js"></script> | |
| 8 <script src="resources/realtimeanalyser-testing.js"></script> | |
| 9 <script src="resources/fft.js"></script> | |
| 10 <title>Test Analyser getFloatFrequencyData and getByteFrequencyData, No Smoo
thing</title> | |
| 11 </head> | |
| 12 | |
| 13 <body> | |
| 14 <script> | |
| 15 description("Test AnalyserNode getFloatFrequencyData and getByteFrequencyD
ata, no Smoothing"); | |
| 16 window.jsTestIsAsync = true; | |
| 17 | |
| 18 // Use a power of two to eliminate any round-off in the computation of the
times for | |
| 19 // context.suspend(). | |
| 20 var sampleRate = 32768; | |
| 21 | |
| 22 // The largest FFT size for the analyser node is 32768. We want to render
longer than this so | |
| 23 // that we have at least one complete buffer of data of 32768 samples. | |
| 24 var renderFrames = 2 * 32768; | |
| 25 var renderDuration = renderFrames / sampleRate; | |
| 26 | |
| 27 var audit = Audit.createTaskRunner(); | |
| 28 | |
| 29 // Options for basic tests of the AnalyserNode frequency domain data. The
thresholds are | |
| 30 // experimentally determined. | |
| 31 var testConfig = [{ | |
| 32 order: 5, | |
| 33 // For this order, need to specify a higher minDecibels value for the an
alyser because the | |
| 34 // FFT doesn't get that small. This allows us to test that (a changed) m
inDecibels has an | |
| 35 // effect and that we properly clip the byte data. | |
| 36 minDecibels: -50, | |
| 37 floatRelError: 6.8964e-7, | |
| 38 }, { | |
| 39 order: 6, | |
| 40 floatRelError: 6.8366e-6 | |
| 41 }, { | |
| 42 order: 7, | |
| 43 floatRelError: 1.4602e-6 | |
| 44 }, { | |
| 45 order: 8, | |
| 46 floatRelError: 8.4828e-7 | |
| 47 }, { | |
| 48 order: 9, | |
| 49 floatRelError: 2.3906e-5 | |
| 50 }, { | |
| 51 order: 10, | |
| 52 floatRelError: 2.0483e-5 | |
| 53 }, { | |
| 54 order: 11, | |
| 55 floatRelError: 1.3456e-5 | |
| 56 }, { | |
| 57 order: 12, | |
| 58 floatRelError: 4.6116e-7 | |
| 59 }, { | |
| 60 order: 13, | |
| 61 floatRelError: 3.2106e-7 | |
| 62 }, { | |
| 63 order: 14, | |
| 64 floatRelError: 1.1756e-7 | |
| 65 }, { | |
| 66 order: 15, | |
| 67 floatRelError: 1.1756e-7 | |
| 68 }]; | |
| 69 | |
| 70 // True if all of the basic tests passed. | |
| 71 var basicTestsPassed = true; | |
| 72 | |
| 73 // Generate tests for each entry in testConfig. | |
| 74 for (var k = 0; k < testConfig.length; ++k) { | |
| 75 var name = testConfig[k].order + "-order FFT"; | |
| 76 (function (config) { | |
| 77 audit.defineTask(name, function (done) { | |
| 78 basicFFTTest(config).then(done); | |
| 79 }); | |
| 80 })(testConfig[k]); | |
| 81 } | |
| 82 | |
| 83 // Just print a summary of the result of the above tests. | |
| 84 audit.defineTask("summarize basic tests", function (done) { | |
| 85 if (basicTestsPassed) | |
| 86 testPassed("Basic frequency data computed correctly.\n"); | |
| 87 else | |
| 88 testFailed("Basic frequency data computed incorrectly.\n"); | |
| 89 done(); | |
| 90 }); | |
| 91 | |
| 92 // Test that smoothing isn't done and we have the expected data, calling g
etFloatFrequencyData | |
| 93 // twice at different times. | |
| 94 audit.defineTask("no smoothing", function (done) { | |
| 95 // Use 128-point FFT for the test. The actual order doesn't matter (but
the error threshold | |
| 96 // depends on the order). | |
| 97 var options = { | |
| 98 order: 7, | |
| 99 smoothing: 0, | |
| 100 floatRelError: 1.2548e-6 | |
| 101 }; | |
| 102 var graph = createGraph(options); | |
| 103 var context = graph.context; | |
| 104 var analyser = graph.analyser; | |
| 105 | |
| 106 // Be sure to suspend after the analyser fftSize so we get a full buffer
of data. We will | |
| 107 // grab the FFT data to prime the pump for smoothing. We don't need to
check the results | |
| 108 // (because this is tested above in the basicFFTTests). | |
| 109 var suspendFrame = Math.max(128, analyser.fftSize); | |
| 110 context.suspend(suspendFrame / sampleRate).then(function () { | |
| 111 // Grab the time and frequency data. But we don't care what values we
get now; we just | |
| 112 // want to prime the analyser. | |
| 113 var freqData = new Float32Array(analyser.frequencyBinCount); | |
| 114 | |
| 115 // Grab the frequency domain data | |
| 116 analyser.getFloatFrequencyData(freqData); | |
| 117 }).then(context.resume.bind(context)); | |
| 118 | |
| 119 // Grab another set of data after one rendering quantum. We will test t
his to make sure | |
| 120 // smoothing was not done. | |
| 121 suspendFrame += 128; | |
| 122 context.suspend(suspendFrame / sampleRate).then(function () { | |
| 123 var timeData = new Float32Array(analyser.fftSize); | |
| 124 var freqData = new Float32Array(analyser.frequencyBinCount); | |
| 125 | |
| 126 // Grab the time domain and frequency domain data | |
| 127 analyser.getFloatTimeDomainData(timeData); | |
| 128 analyser.getFloatFrequencyData(freqData); | |
| 129 | |
| 130 var expected = computeFFTMagnitude(timeData, options.order).map(linear
ToDb); | |
| 131 var comparison = compareFloatFreq(Math.pow(2, options.order) + "-point
float FFT", | |
| 132 freqData, expected, options); | |
| 133 basicTestsPassed = basicTestsPassed && comparison.success; | |
| 134 | |
| 135 if (comparison.success) | |
| 136 testPassed("Smoothing constant of 0 correctly handled.\n"); | |
| 137 else | |
| 138 testFailed("Smoothing constant of 0 incorrectly handled.\n"); | |
| 139 }).then(context.resume.bind(context)); | |
| 140 | |
| 141 context.startRendering().then(done); | |
| 142 }); | |
| 143 | |
| 144 audit.defineTask("finish", function (done) { | |
| 145 finishJSTest(); | |
| 146 done(); | |
| 147 }); | |
| 148 | |
| 149 audit.runTasks(); | |
| 150 | |
| 151 // Run a simple test of the AnalyserNode's frequency domain data. Both th
e float and byte | |
| 152 // frequency data are tested. The byte tests depend on the float tests be
ing correct. | |
| 153 // | |
| 154 // The parameters of the test are given by |options| which is a property b
ag consisting of the | |
| 155 // following: | |
| 156 // | |
| 157 // order: Order of the FFT to test. | |
| 158 // smoothing: smoothing time constant for the analyser. | |
| 159 // minDecibels: min decibels value for the analyser. | |
| 160 // floatRelError: max allowed relative error for the float FFT data | |
| 161 function basicFFTTest(options) { | |
| 162 var graph = createGraph(options); | |
| 163 var context = graph.context; | |
| 164 var analyser = graph.analyser; | |
| 165 | |
| 166 var suspendTime = Math.max(128, analyser.fftSize) / sampleRate; | |
| 167 context.suspend(suspendTime).then(function () { | |
| 168 var timeData = new Float32Array(analyser.fftSize); | |
| 169 var freqData = new Float32Array(analyser.frequencyBinCount); | |
| 170 | |
| 171 // Grab the time domain and frequency domain data | |
| 172 analyser.getFloatTimeDomainData(timeData); | |
| 173 analyser.getFloatFrequencyData(freqData); | |
| 174 | |
| 175 var expected = computeFFTMagnitude(timeData, options.order).map(linear
ToDb); | |
| 176 var comparison = compareFloatFreq(Math.pow(2, options.order) + "-point
float FFT", | |
| 177 freqData, expected, options); | |
| 178 basicTestsPassed = basicTestsPassed && comparison.success; | |
| 179 var expected = comparison.expected; | |
| 180 | |
| 181 // For the byte test to be better, check that there are some samples t
hat are outside the | |
| 182 // range of minDecibels and maxDecibels. If there aren't the test sho
uld update the | |
| 183 // minDecibels and maxDecibels values for the analyser. | |
| 184 | |
| 185 var minValue = Math.min(...expected); | |
| 186 var maxValue = Math.max(...expected); | |
| 187 | |
| 188 basicTestsPassed = Should("Min FFT value", minValue, { | |
| 189 brief: true | |
| 190 }) | |
| 191 .beLessThanOrEqualTo(analyser.minDecibels) && basicTestsPassed; | |
| 192 basicTestsPassed = Should("Max FFT value", maxValue, { | |
| 193 brief: true | |
| 194 }) | |
| 195 .beGreaterThanOrEqualTo(analyser.maxDecibels) && basicTestsPassed; | |
| 196 | |
| 197 // Test the byte frequency data. | |
| 198 var byteFreqData = new Uint8Array(analyser.frequencyBinCount); | |
| 199 var expectedByteData = new Float32Array(analyser.frequencyBinCount); | |
| 200 analyser.getByteFrequencyData(byteFreqData); | |
| 201 | |
| 202 // Convert the expected float frequency data to byte data. | |
| 203 var expectedByteData = convertFloatToByte(expected, analyser.minDecibe
ls, | |
| 204 analyser.maxDecibels); | |
| 205 | |
| 206 basicTestsPassed = Should(analyser.fftSize + "-point byte FFT", byteFr
eqData) | |
| 207 .beCloseToArray(expectedByteData, 0) && basicTestsPassed; | |
| 208 | |
| 209 }).then(context.resume.bind(context)); | |
| 210 | |
| 211 return context.startRendering(); | |
| 212 } | |
| 213 </script> | |
| 214 </body> | |
| 215 </html> | |
| OLD | NEW |