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 <title>Test AnalyserNode getFloatTimeDomainData</title> | |
9 </head> | |
10 | |
11 <body> | |
12 <script> | |
13 description("Test AnalyserNode getFloatTimeDomainData"); | |
14 window.jsTestIsAsync = true; | |
15 | |
16 // Use a power of two to eliminate any round-off in the computation of the
times for | |
17 // context.suspend(). | |
18 var sampleRate = 32768; | |
19 | |
20 // The largest FFT size for the analyser node is 32768. We want to render
longer than this so | |
21 // that we have at least one complete buffer of data of 32768 samples. | |
22 var renderFrames = 2 * 32768; | |
23 var renderDuration = renderFrames / sampleRate; | |
24 | |
25 var audit = Audit.createTaskRunner(); | |
26 | |
27 // Test that getFloatTimeDomainData handles short and long vectors correct
ly. | |
28 audit.defineTask("short and long vector", function (done) { | |
29 var fftSize = 32; | |
30 var graphInfo = createGraph(fftSize); | |
31 var context = graphInfo.context; | |
32 var analyser = graphInfo.analyser; | |
33 var signalBuffer = graphInfo.signalBuffer; | |
34 var signal = signalBuffer.getChannelData(0); | |
35 | |
36 var success = true; | |
37 var sampleFrame = 128; | |
38 | |
39 context.suspend(sampleFrame / sampleRate).then(function () { | |
40 var shortData = new Float32Array(8); | |
41 // Initialize the array to Infinity to represent uninitialize data. | |
42 shortData.fill(Infinity); | |
43 testPassed(shortData.length + "-element short array initialized to Inf
inity."); | |
44 | |
45 analyser.getFloatTimeDomainData(shortData); | |
46 testPassed("getFloatTimeDomainData(<" + shortData.length + "-element v
ector>)."); | |
47 | |
48 // The short array should be filled with the expected data, with no er
rors thrown. | |
49 | |
50 var expected = signal.subarray(sampleFrame - fftSize, sampleFrame); | |
51 success = Should(shortData.length + "-element time domain data", short
Data) | |
52 .beEqualToArray(expected.subarray(0, shortData.length)) && success; | |
53 | |
54 var longData = new Float32Array(2 * fftSize); | |
55 // Initialize the array to Infinity to represent uninitialize data. | |
56 longData.fill(Infinity); | |
57 testPassed(longData.length + "-element long array initialized to Infin
ity."); | |
58 | |
59 analyser.getFloatTimeDomainData(longData); | |
60 testPassed("getFloatTimeDomainData(<" + longData.length + "-element ve
ctor>)."); | |
61 | |
62 // The long array should filled with the expected data but the extra e
lements should be | |
63 // untouched. | |
64 success = Should("longData.subarray(0, " + fftSize + ")", | |
65 longData.subarray(0, fftSize), { | |
66 numberOfArrayLog: 32 | |
67 }) | |
68 .beEqualToArray(expected) && success; | |
69 | |
70 success = Should("Unfilled elements longData.subarray(" + fftSize + ")
", | |
71 longData.subarray(fftSize)) | |
72 .beConstantValueOf(Infinity) && success; | |
73 }).then(context.resume.bind(context)); | |
74 | |
75 context.startRendering().then(function (buffer) { | |
76 if (success) | |
77 testPassed("Long and short time domain arrays handled correctly.\n")
; | |
78 else | |
79 testFailed("Long and short time domain arrays handled incorrectly.\n
"); | |
80 }).then(done); | |
81 }); | |
82 | |
83 var success = true; | |
84 | |
85 // Generate tests for all valid FFT sizes for an AnalyserNode. | |
86 for (var k = 5; k < 16; ++k) { | |
87 var fftSize = Math.pow(2, k); | |
88 (function (n) { | |
89 // We grab a sample at (roughly) half the rendering duration. | |
90 audit.defineTask("fftSize " + n, function (done) { | |
91 runTest(n, renderDuration / 2).then(done); | |
92 }); | |
93 })(fftSize); | |
94 } | |
95 | |
96 audit.defineTask("summarize size tests", function (done) { | |
97 if (success) | |
98 testPassed("Time domain data contained the correct data for each size.
\n"); | |
99 else | |
100 testFailed("Time domain data did not contain the correct data for each
size.\n"); | |
101 | |
102 done(); | |
103 }); | |
104 | |
105 // Special case for a large size, but the sampling point is early. The in
itial part of the | |
106 // buffer should be filled with zeroes. | |
107 | |
108 audit.defineTask("initial zeroes", function (done) { | |
109 // Somewhat arbitrary size for the analyser. It should be greater than
one rendering | |
110 // quantum. | |
111 var fftSize = 2048; | |
112 var graphInfo = createGraph(fftSize); | |
113 var context = graphInfo.context; | |
114 var analyser = graphInfo.analyser; | |
115 var signalBuffer = graphInfo.signalBuffer; | |
116 | |
117 var data = new Float32Array(fftSize); | |
118 | |
119 success = true; | |
120 // Suspend every rendering quantum and examine the analyser data. | |
121 for (var k = 128; k <= fftSize; k += 128) { | |
122 context.suspend(k / sampleRate).then(function () { | |
123 analyser.getFloatTimeDomainData(data); | |
124 var sampleFrame = context.currentTime * sampleRate; | |
125 | |
126 // Verify that the last k frames are not zero, but the first fftSize
- k frames are. | |
127 var prefix = "At frame " + (sampleFrame - 1) + ": data.subarray"; | |
128 if (sampleFrame < fftSize) { | |
129 success = Should(prefix + "(0, " + (fftSize - sampleFrame) + ")", | |
130 data.subarray(0, fftSize - sampleFrame)) | |
131 .beConstantValueOf(0) && success; | |
132 } | |
133 | |
134 var signal = signalBuffer.getChannelData(0); | |
135 success = Should(prefix + "(" + (fftSize - sampleFrame) + ", " + fft
Size + ")", | |
136 data.subarray(fftSize - sampleFrame, fftSize)) | |
137 .beEqualToArray(signal.subarray(0, sampleFrame)) && success; | |
138 }).then(context.resume.bind(context)); | |
139 } | |
140 | |
141 context.startRendering().then(function (b) { | |
142 if (success) { | |
143 testPassed( | |
144 "Time domain data contained initial zeroes and correct data as exp
ected.\n"); | |
145 } else { | |
146 testFailed( | |
147 "Time domain data did not contain initial zeroes and correct data
as expected.\n" | |
148 ); | |
149 } | |
150 | |
151 }).then(done); | |
152 }); | |
153 | |
154 audit.defineTask("finish", function (done) { | |
155 finishJSTest(); | |
156 done(); | |
157 }); | |
158 | |
159 audit.runTasks(); | |
160 | |
161 // Run test of an AnalyserNode with fftSize of |fftSize|, and with the dat
a from the node | |
162 // being requested at time |sampletime|. The result from the analyser nod
e is compared | |
163 // against the expected data. The result of startRendering() is returned. | |
164 function runTest(fftSize, sampleTime) { | |
165 var graphInfo = createGraph(fftSize); | |
166 var context = graphInfo.context; | |
167 var analyser = graphInfo.analyser; | |
168 var signalBuffer = graphInfo.signalBuffer; | |
169 | |
170 // Grab the data at the requested time. | |
171 context.suspend(sampleTime).then(function () { | |
172 var lastFrame = Math.floor(context.currentTime * sampleRate); | |
173 | |
174 // Grab the time domain data from the analyzer and compare against the
expected result. | |
175 var actualFloatData = new Float32Array(fftSize); | |
176 analyser.getFloatTimeDomainData(actualFloatData); | |
177 | |
178 // Compare against the expected result. | |
179 var signal = signalBuffer.getChannelData(0); | |
180 var message = actualFloatData.length + "-point analyser time domain da
ta"; | |
181 success = Should(message, actualFloatData) | |
182 .beEqualToArray(signal.subarray(lastFrame - actualFloatData.length,
lastFrame)) && success; | |
183 }).then(context.resume.bind(context)); | |
184 | |
185 return context.startRendering(); | |
186 } | |
187 | |
188 // Create the audio graph with an AnalyserNode with fftSize |fftSize|. A
simple | |
189 // integer-valued linear ramp is the source so we can easily verify the re
sults. A dictionary | |
190 // consisting of the context, the analyser node, and the signal is returne
d. | |
191 function createGraph(fftSize) { | |
192 var context = new OfflineAudioContext(1, renderFrames, sampleRate); | |
193 | |
194 var src = context.createBufferSource(); | |
195 | |
196 // Use a simple linear ramp as the source. For simplicity of inspecting
results, the ramp | |
197 // starts at 1 with an increment of 1. | |
198 var signalBuffer = context.createBuffer(1, renderFrames, context.sampleR
ate); | |
199 var data = signalBuffer.getChannelData(0); | |
200 for (var k = 0; k < data.length; ++k) { | |
201 data[k] = k + 1; | |
202 } | |
203 | |
204 src.buffer = signalBuffer; | |
205 | |
206 var analyser = context.createAnalyser(); | |
207 analyser.fftSize = fftSize; | |
208 | |
209 src.connect(analyser); | |
210 analyser.connect(context.destination); | |
211 src.start(); | |
212 | |
213 return { | |
214 context: context, | |
215 analyser: analyser, | |
216 signalBuffer: signalBuffer | |
217 }; | |
218 } | |
219 </script> | |
220 </body> | |
221 </html> | |
OLD | NEW |