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 |