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