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