OLD | NEW |
1 <!doctype html> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
| 4 <title> |
| 5 Test Basic PannerNode with Automation Position Properties |
| 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 <script src="../resources/panner-formulas.js"></script> | 11 <script src="../resources/panner-formulas.js"></script> |
9 <title>Test Basic PannerNode with Automation Position Properties</title> | |
10 </head> | 12 </head> |
11 | |
12 <body> | 13 <body> |
13 <script> | 14 <script id="layout-test-code"> |
14 var sampleRate = 48000; | 15 let sampleRate = 48000; |
15 | 16 |
16 // These tests are quite slow, so don't run for many frames. 256 frames | 17 // These tests are quite slow, so don't run for many frames. 256 frames |
17 // should be enough to demonstrate that automations are working. | 18 // should be enough to demonstrate that automations are working. |
18 var renderFrames = 256; | 19 let renderFrames = 256; |
19 var renderDuration = renderFrames / sampleRate; | 20 let renderDuration = renderFrames / sampleRate; |
20 | 21 |
21 var audit = Audit.createTaskRunner(); | 22 let audit = Audit.createTaskRunner(); |
22 | 23 |
23 // Array of tests for setting the panner positions. These tests basically | 24 // Array of tests for setting the panner positions. These tests basically |
24 // verify that the position setters for the panner and listener are | 25 // verify that the position setters for the panner and listener are |
25 // working correctly. | 26 // working correctly. |
26 var testConfig = [ | 27 let testConfig = [ |
27 { | 28 { |
28 setter: 'positionX', | 29 setter: 'positionX', |
29 }, | 30 }, |
30 { | 31 { |
31 setter: 'positionY', | 32 setter: 'positionY', |
32 }, | 33 }, |
33 { | 34 { |
34 setter: 'positionZ', | 35 setter: 'positionZ', |
35 } | 36 } |
36 ]; | 37 ]; |
37 | 38 |
38 // Create tests for the panner position setters. Both mono and steroe | 39 // Create tests for the panner position setters. Both mono and steroe |
39 // sources are tested. | 40 // sources are tested. |
40 for (var k = 0; k < testConfig.length; ++k) { | 41 for (let k = 0; k < testConfig.length; ++k) { |
41 var config = testConfig[k]; | 42 let config = testConfig[k]; |
42 // Function to create the test to define the test. | 43 // Function to create the test to define the test. |
43 var tester = function(config, channelCount) { | 44 let tester = function(config, channelCount) { |
44 return (task, should) => { | 45 return (task, should) => { |
45 var nodes = createGraph(channelCount); | 46 let nodes = createGraph(channelCount); |
46 var {context, source, panner} = nodes; | 47 let {context, source, panner} = nodes; |
47 | 48 |
48 var message = channelCount == 1 ? 'Mono' : 'Stereo'; | 49 let message = channelCount == 1 ? 'Mono' : 'Stereo'; |
49 message += ' panner.' + config.setter; | 50 message += ' panner.' + config.setter; |
50 | 51 |
51 testPositionSetter(should, { | 52 testPositionSetter(should, { |
52 nodes: nodes, | 53 nodes: nodes, |
53 pannerSetter: panner[config.setter], | 54 pannerSetter: panner[config.setter], |
54 message: message | 55 message: message |
55 }).then(() => task.done()); | 56 }).then(() => task.done()); |
56 } | 57 } |
57 }; | 58 }; |
58 | 59 |
59 audit.define('Stereo panner.' + config.setter, tester(config, 2)); | 60 audit.define('Stereo panner.' + config.setter, tester(config, 2)); |
60 audit.define('Mono panner.' + config.setter, tester(config, 1)); | 61 audit.define('Mono panner.' + config.setter, tester(config, 1)); |
61 } | 62 } |
62 | 63 |
63 // Create tests for the listener position setters. Both mono and steroe | 64 // Create tests for the listener position setters. Both mono and steroe |
64 // sources are tested. | 65 // sources are tested. |
65 for (var k = 0; k < testConfig.length; ++k) { | 66 for (let k = 0; k < testConfig.length; ++k) { |
66 var config = testConfig[k]; | 67 let config = testConfig[k]; |
67 // Function to create the test to define the test. | 68 // Function to create the test to define the test. |
68 var tester = function(config, channelCount) { | 69 let tester = function(config, channelCount) { |
69 return (task, should) => { | 70 return (task, should) => { |
70 var nodes = createGraph(channelCount); | 71 let nodes = createGraph(channelCount); |
71 var {context, source, panner} = nodes; | 72 let {context, source, panner} = nodes; |
72 | 73 |
73 var message = channelCount == 1 ? 'Mono' : 'Stereo'; | 74 let message = channelCount == 1 ? 'Mono' : 'Stereo'; |
74 message += ' listener.' + config.setter; | 75 message += ' listener.' + config.setter; |
75 | 76 |
76 // Some relatively arbitrary (non-default) position for the source | 77 // Some relatively arbitrary (non-default) position for the source |
77 // location. | 78 // location. |
78 panner.setPosition(1, 0, 1); | 79 panner.setPosition(1, 0, 1); |
79 | 80 |
80 testPositionSetter(should, { | 81 testPositionSetter(should, { |
81 nodes: nodes, | 82 nodes: nodes, |
82 pannerSetter: context.listener[config.setter], | 83 pannerSetter: context.listener[config.setter], |
83 message: message | 84 message: message |
84 }).then(() => task.done()); | 85 }).then(() => task.done()); |
85 } | 86 } |
86 }; | 87 }; |
87 | 88 |
88 audit.define('Stereo listener.' + config.setter, tester(config, 2)); | 89 audit.define('Stereo listener.' + config.setter, tester(config, 2)); |
89 audit.define('Mono listener.' + config.setter, tester(config, 1)); | 90 audit.define('Mono listener.' + config.setter, tester(config, 1)); |
90 } | 91 } |
91 | 92 |
92 // Test setPosition method. | 93 // Test setPosition method. |
93 audit.define('setPosition', (task, should) => { | 94 audit.define('setPosition', (task, should) => { |
94 var {context, panner, source} = createGraph(2); | 95 let {context, panner, source} = createGraph(2); |
95 | 96 |
96 // Initialize source position (values don't really matter). | 97 // Initialize source position (values don't really matter). |
97 panner.setPosition(1, 1, 1); | 98 panner.setPosition(1, 1, 1); |
98 | 99 |
99 // After some (unimportant) time, move the panner to a (any) new | 100 // After some (unimportant) time, move the panner to a (any) new |
100 // location. | 101 // location. |
101 var suspendFrame = 128; | 102 let suspendFrame = 128; |
102 context.suspend(suspendFrame / sampleRate) | 103 context.suspend(suspendFrame / sampleRate) |
103 .then(function() { | 104 .then(function() { |
104 panner.setPosition(-100, 2000, 8000); | 105 panner.setPosition(-100, 2000, 8000); |
105 }) | 106 }) |
106 .then(context.resume.bind(context)); | 107 .then(context.resume.bind(context)); |
107 | 108 |
108 context.startRendering() | 109 context.startRendering() |
109 .then(function(resultBuffer) { | 110 .then(function(resultBuffer) { |
110 verifyPannerOutputChanged( | 111 verifyPannerOutputChanged( |
111 should, resultBuffer, | 112 should, resultBuffer, |
112 {message: 'setPosition', suspendFrame: suspendFrame}); | 113 {message: 'setPosition', suspendFrame: suspendFrame}); |
113 }) | 114 }) |
114 .then(() => task.done()); | 115 .then(() => task.done()); |
115 }); | 116 }); |
116 | 117 |
117 audit.define('orientation setter', (task, should) => { | 118 audit.define('orientation setter', (task, should) => { |
118 var {context, panner, source} = createGraph(2); | 119 let {context, panner, source} = createGraph(2); |
119 | 120 |
120 // For orientation to matter, we need to make the source directional, | 121 // For orientation to matter, we need to make the source directional, |
121 // and also move away from the listener (because the default location is | 122 // and also move away from the listener (because the default location is |
122 // 0,0,0). | 123 // 0,0,0). |
123 panner.setPosition(0, 0, 1); | 124 panner.setPosition(0, 0, 1); |
124 panner.coneInnerAngle = 0; | 125 panner.coneInnerAngle = 0; |
125 panner.coneOuterAngle = 360; | 126 panner.coneOuterAngle = 360; |
126 panner.coneOuterGain = .001; | 127 panner.coneOuterGain = .001; |
127 | 128 |
128 // After some (unimportant) time, change the panner orientation to a new | 129 // After some (unimportant) time, change the panner orientation to a new |
129 // orientation. The only constraint is that the orientation changes | 130 // orientation. The only constraint is that the orientation changes |
130 // from before. | 131 // from before. |
131 var suspendFrame = 128; | 132 let suspendFrame = 128; |
132 context.suspend(suspendFrame / sampleRate) | 133 context.suspend(suspendFrame / sampleRate) |
133 .then(function() { | 134 .then(function() { |
134 panner.orientationX.value = -100; | 135 panner.orientationX.value = -100; |
135 panner.orientationY.value = 2000; | 136 panner.orientationY.value = 2000; |
136 panner.orientationZ.value = 8000; | 137 panner.orientationZ.value = 8000; |
137 }) | 138 }) |
138 .then(context.resume.bind(context)); | 139 .then(context.resume.bind(context)); |
139 | 140 |
140 context.startRendering() | 141 context.startRendering() |
141 .then(function(resultBuffer) { | 142 .then(function(resultBuffer) { |
142 verifyPannerOutputChanged(should, resultBuffer, { | 143 verifyPannerOutputChanged(should, resultBuffer, { |
143 message: 'panner.orientation{XYZ}', | 144 message: 'panner.orientation{XYZ}', |
144 suspendFrame: suspendFrame | 145 suspendFrame: suspendFrame |
145 }); | 146 }); |
146 }) | 147 }) |
147 .then(() => task.done()); | 148 .then(() => task.done()); |
148 }); | 149 }); |
149 | 150 |
150 audit.define('forward setter', (task, should) => { | 151 audit.define('forward setter', (task, should) => { |
151 var {context, panner, source} = createGraph(2); | 152 let {context, panner, source} = createGraph(2); |
152 | 153 |
153 // For orientation to matter, we need to make the source directional, | 154 // For orientation to matter, we need to make the source directional, |
154 // and also move away from the listener (because the default location is | 155 // and also move away from the listener (because the default location is |
155 // 0,0,0). | 156 // 0,0,0). |
156 panner.setPosition(0, 0, 1); | 157 panner.setPosition(0, 0, 1); |
157 panner.coneInnerAngle = 0; | 158 panner.coneInnerAngle = 0; |
158 panner.coneOuterAngle = 360; | 159 panner.coneOuterAngle = 360; |
159 panner.coneOuterGain = .001; | 160 panner.coneOuterGain = .001; |
160 | 161 |
161 // After some (unimportant) time, change the panner orientation to a new | 162 // After some (unimportant) time, change the panner orientation to a new |
162 // orientation. The only constraint is that the orientation changes | 163 // orientation. The only constraint is that the orientation changes |
163 // from before. | 164 // from before. |
164 var suspendFrame = 128; | 165 let suspendFrame = 128; |
165 context.suspend(suspendFrame / sampleRate) | 166 context.suspend(suspendFrame / sampleRate) |
166 .then(function() { | 167 .then(function() { |
167 context.listener.forwardX.value = -100; | 168 context.listener.forwardX.value = -100; |
168 context.listener.forwardY.value = 2000; | 169 context.listener.forwardY.value = 2000; |
169 context.listener.forwardZ.value = 8000; | 170 context.listener.forwardZ.value = 8000; |
170 }) | 171 }) |
171 .then(context.resume.bind(context)); | 172 .then(context.resume.bind(context)); |
172 | 173 |
173 context.startRendering() | 174 context.startRendering() |
174 .then(function(resultBuffer) { | 175 .then(function(resultBuffer) { |
175 verifyPannerOutputChanged(should, resultBuffer, { | 176 verifyPannerOutputChanged(should, resultBuffer, { |
176 message: 'listener.forward{XYZ}', | 177 message: 'listener.forward{XYZ}', |
177 suspendFrame: suspendFrame | 178 suspendFrame: suspendFrame |
178 }); | 179 }); |
179 }) | 180 }) |
180 .then(() => task.done()); | 181 .then(() => task.done()); |
181 }); | 182 }); |
182 | 183 |
183 audit.define('up setter', (task, should) => { | 184 audit.define('up setter', (task, should) => { |
184 var {context, panner, source} = createGraph(2); | 185 let {context, panner, source} = createGraph(2); |
185 | 186 |
186 // For orientation to matter, we need to make the source directional, | 187 // For orientation to matter, we need to make the source directional, |
187 // and also move away from the listener (because the default location is | 188 // and also move away from the listener (because the default location is |
188 // 0,0,0). | 189 // 0,0,0). |
189 panner.setPosition(0, 0, 1); | 190 panner.setPosition(0, 0, 1); |
190 panner.coneInnerAngle = 0; | 191 panner.coneInnerAngle = 0; |
191 panner.coneOuterAngle = 360; | 192 panner.coneOuterAngle = 360; |
192 panner.coneOuterGain = .001; | 193 panner.coneOuterGain = .001; |
193 panner.setPosition(1, 0, 1); | 194 panner.setPosition(1, 0, 1); |
194 | 195 |
195 // After some (unimportant) time, change the panner orientation to a new | 196 // After some (unimportant) time, change the panner orientation to a new |
196 // orientation. The only constraint is that the orientation changes | 197 // orientation. The only constraint is that the orientation changes |
197 // from before. | 198 // from before. |
198 var suspendFrame = 128; | 199 let suspendFrame = 128; |
199 context.suspend(suspendFrame / sampleRate) | 200 context.suspend(suspendFrame / sampleRate) |
200 .then(function() { | 201 .then(function() { |
201 context.listener.upX.value = 100; | 202 context.listener.upX.value = 100; |
202 context.listener.upY.value = 100; | 203 context.listener.upY.value = 100; |
203 context.listener.upZ.value = 100; | 204 context.listener.upZ.value = 100; |
204 ; | 205 ; |
205 }) | 206 }) |
206 .then(context.resume.bind(context)); | 207 .then(context.resume.bind(context)); |
207 | 208 |
208 context.startRendering() | 209 context.startRendering() |
209 .then(function(resultBuffer) { | 210 .then(function(resultBuffer) { |
210 verifyPannerOutputChanged( | 211 verifyPannerOutputChanged( |
211 should, resultBuffer, | 212 should, resultBuffer, |
212 {message: 'listener.up{XYZ}', suspendFrame: suspendFrame}); | 213 {message: 'listener.up{XYZ}', suspendFrame: suspendFrame}); |
213 }) | 214 }) |
214 .then(() => task.done()); | 215 .then(() => task.done()); |
215 }); | 216 }); |
216 | 217 |
217 audit.run(); | 218 audit.run(); |
218 | 219 |
219 function createGraph(channelCount) { | 220 function createGraph(channelCount) { |
220 var context = new OfflineAudioContext(2, renderFrames, sampleRate); | 221 let context = new OfflineAudioContext(2, renderFrames, sampleRate); |
221 var panner = context.createPanner(); | 222 let panner = context.createPanner(); |
222 var source = context.createBufferSource(); | 223 let source = context.createBufferSource(); |
223 source.buffer = | 224 source.buffer = |
224 createConstantBuffer(context, 1, channelCount == 1 ? 1 : [1, 2]); | 225 createConstantBuffer(context, 1, channelCount == 1 ? 1 : [1, 2]); |
225 source.loop = true; | 226 source.loop = true; |
226 | 227 |
227 source.connect(panner); | 228 source.connect(panner); |
228 panner.connect(context.destination); | 229 panner.connect(context.destination); |
229 | 230 |
230 source.start(); | 231 source.start(); |
231 return {context: context, source: source, panner: panner}; | 232 return {context: context, source: source, panner: panner}; |
232 } | 233 } |
233 | 234 |
234 function testPositionSetter(should, options) { | 235 function testPositionSetter(should, options) { |
235 var {nodes, pannerSetter, message} = options; | 236 let {nodes, pannerSetter, message} = options; |
236 | 237 |
237 var {context, source, panner} = nodes; | 238 let {context, source, panner} = nodes; |
238 | 239 |
239 // Set panner x position. (Value doesn't matter); | 240 // Set panner x position. (Value doesn't matter); |
240 pannerSetter.value = 1; | 241 pannerSetter.value = 1; |
241 | 242 |
242 // Wait a bit and set a new position. (Actual time and position doesn't | 243 // Wait a bit and set a new position. (Actual time and position doesn't |
243 // matter). | 244 // matter). |
244 var suspendFrame = 128; | 245 let suspendFrame = 128; |
245 context.suspend(suspendFrame / sampleRate) | 246 context.suspend(suspendFrame / sampleRate) |
246 .then(function() { | 247 .then(function() { |
247 pannerSetter.value = 10000; | 248 pannerSetter.value = 10000; |
248 }) | 249 }) |
249 .then(context.resume.bind(context)); | 250 .then(context.resume.bind(context)); |
250 | 251 |
251 return context.startRendering().then(function(resultBuffer) { | 252 return context.startRendering().then(function(resultBuffer) { |
252 verifyPannerOutputChanged( | 253 verifyPannerOutputChanged( |
253 should, resultBuffer, | 254 should, resultBuffer, |
254 {message: message, suspendFrame: suspendFrame}); | 255 {message: message, suspendFrame: suspendFrame}); |
255 }); | 256 }); |
256 } | 257 } |
257 | 258 |
258 function verifyPannerOutputChanged(should, resultBuffer, options) { | 259 function verifyPannerOutputChanged(should, resultBuffer, options) { |
259 var {message, suspendFrame} = options; | 260 let {message, suspendFrame} = options; |
260 // Verify that the first part of output is constant. (Doesn't matter | 261 // Verify that the first part of output is constant. (Doesn't matter |
261 // what.) | 262 // what.) |
262 var data0 = resultBuffer.getChannelData(0); | 263 let data0 = resultBuffer.getChannelData(0); |
263 var data1 = resultBuffer.getChannelData(1); | 264 let data1 = resultBuffer.getChannelData(1); |
264 | 265 |
265 var middle = '[0, ' + suspendFrame + ') '; | 266 let middle = '[0, ' + suspendFrame + ') '; |
266 should( | 267 should( |
267 data0.slice(0, suspendFrame), | 268 data0.slice(0, suspendFrame), |
268 message + '.value frame ' + middle + 'channel 0') | 269 message + '.value frame ' + middle + 'channel 0') |
269 .beConstantValueOf(data0[0]); | 270 .beConstantValueOf(data0[0]); |
270 should( | 271 should( |
271 data1.slice(0, suspendFrame), | 272 data1.slice(0, suspendFrame), |
272 message + '.value frame ' + middle + 'channel 1') | 273 message + '.value frame ' + middle + 'channel 1') |
273 .beConstantValueOf(data1[0]); | 274 .beConstantValueOf(data1[0]); |
274 | 275 |
275 // The rest after suspendTime should be constant and different from the | 276 // The rest after suspendTime should be constant and different from the |
276 // first part. | 277 // first part. |
277 middle = '[' + suspendFrame + ', ' + renderFrames + ') '; | 278 middle = '[' + suspendFrame + ', ' + renderFrames + ') '; |
278 should( | 279 should( |
279 data0.slice(suspendFrame), | 280 data0.slice(suspendFrame), |
280 message + '.value frame ' + middle + 'channel 0') | 281 message + '.value frame ' + middle + 'channel 0') |
281 .beConstantValueOf(data0[suspendFrame]); | 282 .beConstantValueOf(data0[suspendFrame]); |
282 should( | 283 should( |
283 data1.slice(suspendFrame), | 284 data1.slice(suspendFrame), |
284 message + '.value frame ' + middle + 'channel 1') | 285 message + '.value frame ' + middle + 'channel 1') |
285 .beConstantValueOf(data1[suspendFrame]); | 286 .beConstantValueOf(data1[suspendFrame]); |
286 should( | 287 should( |
287 data0[suspendFrame], | 288 data0[suspendFrame], |
288 message + ': Output at frame ' + suspendFrame + ' channel 0') | 289 message + ': Output at frame ' + suspendFrame + ' channel 0') |
289 .notBeEqualTo(data0[0]); | 290 .notBeEqualTo(data0[0]); |
290 should( | 291 should( |
291 data1[suspendFrame], | 292 data1[suspendFrame], |
292 message + ': Output at frame ' + suspendFrame + ' channel 1') | 293 message + ': Output at frame ' + suspendFrame + ' channel 1') |
293 .notBeEqualTo(data1[0]); | 294 .notBeEqualTo(data1[0]); |
294 } | 295 } |
295 | |
296 </script> | 296 </script> |
297 </body> | 297 </body> |
298 </html> | 298 </html> |
OLD | NEW |