Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: third_party/WebKit/LayoutTests/webaudio/Panner/panner-automation-position.html

Issue 2895963003: Apply layout-test-tidy to LayoutTests/webaudio (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 <!doctype html> 1 <!DOCTYPE html>
2 <html> 2 <html>
3 <head> 3 <head>
4 <title>
5 Test Automation of PannerNode Positions
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 Automation of PannerNode Positions</title>
10 </head> 12 </head>
13 <body>
14 <script id="layout-test-code">
15 let sampleRate = 48000;
16 // 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 let renderFrames = 256;
19 let renderDuration = renderFrames / sampleRate;
11 20
12 <body> 21 let context;
13 <script> 22 let panner;
14 var sampleRate = 48000;
15 // These tests are quite slow, so don't run for many frames. 256 frames s hould be enough to
16 // demonstrate that automations are working.
17 var renderFrames = 256;
18 var renderDuration = renderFrames / sampleRate;
19 23
20 var context; 24 let audit = Audit.createTaskRunner();
21 var panner;
22 25
23 var audit = Audit.createTaskRunner(); 26 // Set of tests for the panner node with automations applied to the
27 // position of the source.
28 let testConfigs = [
29 {
30 // Distance model parameters for the panner
31 distanceModel: {model: 'inverse', rolloff: 1},
32 // Initial location of the source
33 startPosition: [0, 0, 1],
34 // Final position of the source. For this test, we only want to move
35 // on the z axis which
36 // doesn't change the azimuth angle.
37 endPosition: [0, 0, 10000],
38 },
39 {
40 distanceModel: {model: 'inverse', rolloff: 1},
41 startPosition: [0, 0, 1],
42 // An essentially random end position, but it should be such that
43 // azimuth angle changes as
44 // we move from the start to the end.
45 endPosition: [20000, 30000, 10000],
46 errorThreshold: [
47 {
48 // Error threshold for 1-channel case
49 relativeThreshold: 4.8124e-7
50 },
51 {
52 // Error threshold for 2-channel case
53 relativeThreshold: 4.3267e-7
54 }
55 ],
56 },
57 {
58 distanceModel: {model: 'exponential', rolloff: 1.5},
59 startPosition: [0, 0, 1],
60 endPosition: [20000, 30000, 10000],
61 errorThreshold:
62 [{relativeThreshold: 5.0783e-7}, {relativeThreshold: 5.2180e-7}]
63 },
64 {
65 distanceModel: {model: 'linear', rolloff: 1},
66 startPosition: [0, 0, 1],
67 endPosition: [20000, 30000, 10000],
68 errorThreshold: [
69 {relativeThreshold: 6.5324e-6}, {relativeThreshold: 6.5756e-6}
70 ]
71 }
72 ];
24 73
25 // Set of tests for the panner node with automations applied to the positi on of the source. 74 for (let k = 0; k < testConfigs.length; ++k) {
26 var testConfigs = [{ 75 let config = testConfigs[k];
27 // Distance model parameters for the panner 76 let tester = function(c, channelCount) {
28 distanceModel: {
29 model: "inverse",
30 rolloff: 1
31 },
32 // Initial location of the source
33 startPosition: [0, 0, 1],
34 // Final position of the source. For this test, we only want to move on the z axis which
35 // doesn't change the azimuth angle.
36 endPosition: [0, 0, 10000],
37 }, {
38 distanceModel: {
39 model: "inverse",
40 rolloff: 1
41 },
42 startPosition: [0, 0, 1],
43 // An essentially random end position, but it should be such that azimut h angle changes as
44 // we move from the start to the end.
45 endPosition: [20000, 30000, 10000],
46 errorThreshold: [{
47 // Error threshold for 1-channel case
48 relativeThreshold: 4.8124e-7
49 }, {
50 // Error threshold for 2-channel case
51 relativeThreshold: 4.3267e-7
52 }],
53 }, {
54 distanceModel: {
55 model: "exponential",
56 rolloff: 1.5
57 },
58 startPosition: [0, 0, 1],
59 endPosition: [20000, 30000, 10000],
60 errorThreshold: [{
61 relativeThreshold: 5.0783e-7
62 }, {
63 relativeThreshold: 5.2180e-7
64 }]
65 }, {
66 distanceModel: {
67 model: "linear",
68 rolloff: 1
69 },
70 startPosition: [0, 0, 1],
71 endPosition: [20000, 30000, 10000],
72 errorThreshold: [{
73 relativeThreshold: 6.5324e-6
74 }, {
75 relativeThreshold: 6.5756e-6
76 }]
77 }];
78
79 for (var k = 0; k < testConfigs.length; ++k) {
80 var config = testConfigs[k];
81 var tester = function (c, channelCount) {
82 return (task, should) => { 77 return (task, should) => {
83 runTest(should, c, channelCount) 78 runTest(should, c, channelCount).then(() => task.done());
84 .then(() => task.done());
85 } 79 }
86 }; 80 };
87 81
88 var baseTestName = config.distanceModel.model + " rolloff: " + config.di stanceModel.rolloff; 82 let baseTestName = config.distanceModel.model +
83 ' rolloff: ' + config.distanceModel.rolloff;
89 84
90 // Define tasks for both 1-channel and 2-channel 85 // Define tasks for both 1-channel and 2-channel
91 audit.define(k + ": 1-channel " + baseTestName, tester(config, 1)); 86 audit.define(k + ': 1-channel ' + baseTestName, tester(config, 1));
92 audit.define(k + ": 2-channel " + baseTestName, tester(config, 2)); 87 audit.define(k + ': 2-channel ' + baseTestName, tester(config, 2));
93 } 88 }
94 89
95 audit.run(); 90 audit.run();
96 91
97 function runTest(should, options, channelCount) { 92 function runTest(should, options, channelCount) {
98 // Output has 5 channels: channels 0 and 1 are for the stereo output of the panner node. 93 // Output has 5 channels: channels 0 and 1 are for the stereo output of
99 // Channels 2-5 are the for automation of the x,y,z coordinate so that w e have actual 94 // the panner node. Channels 2-5 are the for automation of the x,y,z
100 // coordinates used for the panner automation. 95 // coordinate so that we have actual coordinates used for the panner
96 // automation.
101 context = new OfflineAudioContext(5, renderFrames, sampleRate); 97 context = new OfflineAudioContext(5, renderFrames, sampleRate);
102 98
103 // Stereo source for the panner. 99 // Stereo source for the panner.
104 var source = context.createBufferSource(); 100 let source = context.createBufferSource();
105 source.buffer = createConstantBuffer(context, renderFrames, channelCount == 1 ? 1 : [1, 2]); 101 source.buffer = createConstantBuffer(
102 context, renderFrames, channelCount == 1 ? 1 : [1, 2]);
106 103
107 panner = context.createPanner(); 104 panner = context.createPanner();
108 panner.distanceModel = options.distanceModel.model; 105 panner.distanceModel = options.distanceModel.model;
109 panner.rolloffFactor = options.distanceModel.rolloff; 106 panner.rolloffFactor = options.distanceModel.rolloff;
110 panner.panningModel = "equalpower"; 107 panner.panningModel = 'equalpower';
111 108
112 // Source and gain node for the z-coordinate calculation. 109 // Source and gain node for the z-coordinate calculation.
113 var dist = context.createBufferSource(); 110 let dist = context.createBufferSource();
114 dist.buffer = createConstantBuffer(context, 1, 1); 111 dist.buffer = createConstantBuffer(context, 1, 1);
115 dist.loop = true; 112 dist.loop = true;
116 var gainX = context.createGain(); 113 let gainX = context.createGain();
117 var gainY = context.createGain(); 114 let gainY = context.createGain();
118 var gainZ = context.createGain(); 115 let gainZ = context.createGain();
119 dist.connect(gainX); 116 dist.connect(gainX);
120 dist.connect(gainY); 117 dist.connect(gainY);
121 dist.connect(gainZ); 118 dist.connect(gainZ);
122 119
123 // Set the gain automation to match the z-coordinate automation of the p anner. 120 // Set the gain automation to match the z-coordinate automation of the
121 // panner.
124 122
125 // End the automation some time before the end of the rendering so we ca n verify that 123 // End the automation some time before the end of the rendering so we
126 // automation has the correct end time and value. 124 // can verify that automation has the correct end time and value.
127 var endAutomationTime = 0.75 * renderDuration; 125 let endAutomationTime = 0.75 * renderDuration;
128 126
129 gainX.gain.setValueAtTime(options.startPosition[0], 0); 127 gainX.gain.setValueAtTime(options.startPosition[0], 0);
130 gainX.gain.linearRampToValueAtTime(options.endPosition[0], endAutomation Time); 128 gainX.gain.linearRampToValueAtTime(
129 options.endPosition[0], endAutomationTime);
131 gainY.gain.setValueAtTime(options.startPosition[1], 0); 130 gainY.gain.setValueAtTime(options.startPosition[1], 0);
132 gainY.gain.linearRampToValueAtTime(options.endPosition[1], endAutomation Time); 131 gainY.gain.linearRampToValueAtTime(
132 options.endPosition[1], endAutomationTime);
133 gainZ.gain.setValueAtTime(options.startPosition[2], 0); 133 gainZ.gain.setValueAtTime(options.startPosition[2], 0);
134 gainZ.gain.linearRampToValueAtTime(options.endPosition[2], endAutomation Time); 134 gainZ.gain.linearRampToValueAtTime(
135 options.endPosition[2], endAutomationTime);
135 136
136 dist.start(); 137 dist.start();
137 138
138 // Splitter and merger to map the panner output and the z-coordinate aut omation to the 139 // Splitter and merger to map the panner output and the z-coordinate
139 // correct channels in the destination. 140 // automation to the correct channels in the destination.
140 var splitter = context.createChannelSplitter(2); 141 let splitter = context.createChannelSplitter(2);
141 var merger = context.createChannelMerger(5); 142 let merger = context.createChannelMerger(5);
142 143
143 source.connect(panner); 144 source.connect(panner);
144 // Split the output of the panner to separate channels 145 // Split the output of the panner to separate channels
145 panner.connect(splitter); 146 panner.connect(splitter);
146 147
147 // Merge the panner outputs and the z-coordinate output to the correct d estination channels. 148 // Merge the panner outputs and the z-coordinate output to the correct
149 // destination channels.
148 splitter.connect(merger, 0, 0); 150 splitter.connect(merger, 0, 0);
149 splitter.connect(merger, 1, 1); 151 splitter.connect(merger, 1, 1);
150 gainX.connect(merger, 0, 2); 152 gainX.connect(merger, 0, 2);
151 gainY.connect(merger, 0, 3); 153 gainY.connect(merger, 0, 3);
152 gainZ.connect(merger, 0, 4); 154 gainZ.connect(merger, 0, 4);
153 155
154 merger.connect(context.destination); 156 merger.connect(context.destination);
155 157
156 // Initialize starting point of the panner. 158 // Initialize starting point of the panner.
157 panner.positionX.setValueAtTime(options.startPosition[0], 0); 159 panner.positionX.setValueAtTime(options.startPosition[0], 0);
158 panner.positionY.setValueAtTime(options.startPosition[1], 0); 160 panner.positionY.setValueAtTime(options.startPosition[1], 0);
159 panner.positionZ.setValueAtTime(options.startPosition[2], 0); 161 panner.positionZ.setValueAtTime(options.startPosition[2], 0);
160 162
161 // Automate z coordinate to move away from the listener 163 // Automate z coordinate to move away from the listener
162 panner.positionX.linearRampToValueAtTime(options.endPosition[0], 0.75 * renderDuration); 164 panner.positionX.linearRampToValueAtTime(
163 panner.positionY.linearRampToValueAtTime(options.endPosition[1], 0.75 * renderDuration); 165 options.endPosition[0], 0.75 * renderDuration);
164 panner.positionZ.linearRampToValueAtTime(options.endPosition[2], 0.75 * renderDuration); 166 panner.positionY.linearRampToValueAtTime(
167 options.endPosition[1], 0.75 * renderDuration);
168 panner.positionZ.linearRampToValueAtTime(
169 options.endPosition[2], 0.75 * renderDuration);
165 170
166 source.start(); 171 source.start();
167 172
168 // Go! 173 // Go!
169 return context.startRendering() 174 return context.startRendering().then(function(renderedBuffer) {
170 .then(function (renderedBuffer) { 175 // Get the panner outputs
171 // Get the panner outputs 176 let data0 = renderedBuffer.getChannelData(0);
172 var data0 = renderedBuffer.getChannelData(0); 177 let data1 = renderedBuffer.getChannelData(1);
173 var data1 = renderedBuffer.getChannelData(1); 178 let xcoord = renderedBuffer.getChannelData(2);
174 var xcoord = renderedBuffer.getChannelData(2); 179 let ycoord = renderedBuffer.getChannelData(3);
175 var ycoord = renderedBuffer.getChannelData(3); 180 let zcoord = renderedBuffer.getChannelData(4);
176 var zcoord = renderedBuffer.getChannelData(4);
177 181
178 // We're doing a linear ramp on the Z axis with the equalpower panne r, so the equalpower 182 // We're doing a linear ramp on the Z axis with the equalpower panner,
179 // panning gain remains constant. We only need to model the distanc e effect. 183 // so the equalpower panning gain remains constant. We only need to
184 // model the distance effect.
180 185
181 // Compute the distance gain 186 // Compute the distance gain
182 var distanceGain = new Float32Array(xcoord.length);; 187 let distanceGain = new Float32Array(xcoord.length);
188 ;
183 189
184 if (panner.distanceModel === "inverse") { 190 if (panner.distanceModel === 'inverse') {
185 for (var k = 0; k < distanceGain.length; ++k) { 191 for (let k = 0; k < distanceGain.length; ++k) {
186 distanceGain[k] = inverseDistance(panner, xcoord[k], ycoord[k], zcoord[k]) 192 distanceGain[k] =
187 } 193 inverseDistance(panner, xcoord[k], ycoord[k], zcoord[k])
188 } else if (panner.distanceModel === "linear") {
189 for (var k = 0; k < distanceGain.length; ++k) {
190 distanceGain[k] = linearDistance(panner, xcoord[k], ycoord[k], z coord[k])
191 }
192 } else if (panner.distanceModel === "exponential") {
193 for (var k = 0; k < distanceGain.length; ++k) {
194 distanceGain[k] = exponentialDistance(panner, xcoord[k], ycoord[ k], zcoord[k])
195 }
196 } 194 }
195 } else if (panner.distanceModel === 'linear') {
196 for (let k = 0; k < distanceGain.length; ++k) {
197 distanceGain[k] =
198 linearDistance(panner, xcoord[k], ycoord[k], zcoord[k])
199 }
200 } else if (panner.distanceModel === 'exponential') {
201 for (let k = 0; k < distanceGain.length; ++k) {
202 distanceGain[k] =
203 exponentialDistance(panner, xcoord[k], ycoord[k], zcoord[k])
204 }
205 }
197 206
198 // Compute the expected result. Since we're on the z-axis, the left and right channels 207 // Compute the expected result. Since we're on the z-axis, the left
199 // pass through the equalpower panner unchanged. Only need to apply the distance gain. 208 // and right channels pass through the equalpower panner unchanged.
200 var buffer0 = source.buffer.getChannelData(0); 209 // Only need to apply the distance gain.
201 var buffer1 = channelCount == 2 ? source.buffer.getChannelData(1) : buffer0; 210 let buffer0 = source.buffer.getChannelData(0);
211 let buffer1 =
212 channelCount == 2 ? source.buffer.getChannelData(1) : buffer0;
202 213
203 var azimuth = new Float32Array(buffer0.length); 214 let azimuth = new Float32Array(buffer0.length);
204
205 for (var k = 0; k < data0.length; ++k) {
206 azimuth[k] = calculateAzimuth([
207 xcoord[k],
208 ycoord[k],
209 zcoord[k]
210 ], [
211 context.listener.positionX.value,
212 context.listener.positionY.value,
213 context.listener.positionZ.value
214 ], [
215 context.listener.forwardX.value,
216 context.listener.forwardY.value,
217 context.listener.forwardZ.value
218 ], [
219 context.listener.upX.value,
220 context.listener.upY.value,
221 context.listener.upZ.value
222 ]);
223 }
224 215
225 var expected = applyPanner(azimuth, buffer0, buffer1, channelCount); 216 for (let k = 0; k < data0.length; ++k) {
226 var expected0 = expected.left; 217 azimuth[k] = calculateAzimuth(
227 var expected1 = expected.right; 218 [xcoord[k], ycoord[k], zcoord[k]],
228 219 [
229 for (var k = 0; k < expected0.length; ++k) { 220 context.listener.positionX.value,
230 expected0[k] *= distanceGain[k]; 221 context.listener.positionY.value,
231 expected1[k] *= distanceGain[k]; 222 context.listener.positionZ.value
232 } 223 ],
224 [
225 context.listener.forwardX.value,
226 context.listener.forwardY.value,
227 context.listener.forwardZ.value
228 ],
229 [
230 context.listener.upX.value, context.listener.upY.value,
231 context.listener.upZ.value
232 ]);
233 }
233 234
234 var info = options.distanceModel.model + ", rolloff: " + options.dis tanceModel.rolloff; 235 let expected = applyPanner(azimuth, buffer0, buffer1, channelCount);
235 var prefix = channelCount + "-channel " 236 let expected0 = expected.left;
236 + "[" + options.startPosition[0] + ", " 237 let expected1 = expected.right;
237 + options.startPosition[1] + ", "
238 + options.startPosition[2] + "] -> ["
239 + options.endPosition[0] + ", "
240 + options.endPosition[1] + ", "
241 + options.endPosition[2] + "]: ";
242 238
243 var errorThreshold = 0; 239 for (let k = 0; k < expected0.length; ++k) {
240 expected0[k] *= distanceGain[k];
241 expected1[k] *= distanceGain[k];
242 }
244 243
245 if (options.errorThreshold) 244 let info = options.distanceModel.model +
246 errorThreshold = options.errorThreshold[channelCount - 1] 245 ', rolloff: ' + options.distanceModel.rolloff;
246 let prefix = channelCount + '-channel ' +
247 '[' + options.startPosition[0] + ', ' + options.startPosition[1] +
248 ', ' + options.startPosition[2] + '] -> [' +
249 options.endPosition[0] + ', ' + options.endPosition[1] + ', ' +
250 options.endPosition[2] + ']: ';
247 251
248 should(data0, prefix + "distanceModel: " + info + ", left channel") 252 let errorThreshold = 0;
249 .beCloseToArray(expected0, { 253
250 absoluteThreshold: errorThreshold 254 if (options.errorThreshold)
251 }); 255 errorThreshold = options.errorThreshold[channelCount - 1]
252 should(data1, prefix + "distanceModel: " + info + ", right channel") 256
253 .beCloseToArray(expected1, { 257 should(data0, prefix + 'distanceModel: ' + info + ', left channel')
254 absoluteThreshold: errorThreshold 258 .beCloseToArray(expected0, {absoluteThreshold: errorThreshold});
255 }); 259 should(data1, prefix + 'distanceModel: ' + info + ', right channel')
256 }); 260 .beCloseToArray(expected1, {absoluteThreshold: errorThreshold});
261 });
257 } 262 }
258 </script> 263 </script>
259 </body> 264 </body>
260 </html> 265 </html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698