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