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