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

Side by Side Diff: third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-cancel-and-hold.html

Issue 1533103002: Implement cancelValuesAndHoldAtTime (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 3 years, 11 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
(Empty)
1 <!doctype html>
2 <html>
3 <head>
4 <script src="../../resources/testharness.js"></script>
5 <script src="../../resources/testharnessreport.js"></script>
6 <script src="../resources/audit-util.js"></script>
7 <script src="../resources/audit.js"></script>
8 <title>Test CancelValuesAndHoldAtTime</title>
9 </head>
10
11 <body>
12 <script>
13 let sampleRate = 48000;
14 let renderDuration = 0.5;
15
16 let audit = Audit.createTaskRunner();
17
18 // The first few tasks test the cancellation of each relevant automation
19 // function. For the test, a simple linear ramp from 0 to 1 is used to
20 // start things off. Then the automation to be tested is scheduled and
21 // cancelled.
22
23 audit.define("linear", function (task, should) {
24 task.describe("Cancel linearRampToValueAtTime");
25 cancelTest(should, linearRampTest("linearRampToValueAtTime"), {
26 valueThreshold: 8.3998e-5,
27 curveThreshold: 0
28 }).then(task.done.bind(task));
29 });
30
31 audit.define("exponential", function (task, should) {
32 task.describe("Cancel exponentialRampAtTime");
33 // Cancel an exponential ramp. The thresholds are experimentally
34 // determined.
35 cancelTest(should, function (g, v0, t0, cancelTime) {
36 // Initialize values to 0.
37 g[0].gain.setValueAtTime(0, 0);
38 g[1].gain.setValueAtTime(0, 0);
39 // Schedule a short linear ramp to start things off.
40 g[0].gain.linearRampToValueAtTime(v0, t0);
41 g[1].gain.linearRampToValueAtTime(v0, t0);
42
43 // After the linear ramp, schedule an exponential ramp to the end.
44 // (This is the event that will be be cancelled.)
45 let v1 = 0.001;
46 let t1 = renderDuration;
47
48 g[0].gain.exponentialRampToValueAtTime(v1, t1);
49 g[1].gain.exponentialRampToValueAtTime(v1, t1);
50
51 expectedConstant = Math.fround(v0 * Math.pow(v1 / v0, (
52 cancelTime -
53 t0) / (t1 - t0)));
54 return {
55 expectedConstant: expectedConstant,
56 autoMessage: "exponentialRampToValue(" + v1 + ", " + t1 + ")",
57 summary: "exponentialRampToValueAtTime",
58 };
59 }, {
60 valueThreshold: 1.8664e-6,
61 curveThreshold: 5.9605e-8
62 }).then(task.done.bind(task));
63 });
64
65 audit.define("setTarget", function (task, should) {
66 task.describe("Cancel setTargetAtTime");
67 // Cancel a setTarget event.
68 cancelTest(should, function (g, v0, t0, cancelTime) {
69 // Initialize values to 0.
70 g[0].gain.setValueAtTime(0, 0);
71 g[1].gain.setValueAtTime(0, 0);
72 // Schedule a short linear ramp to start things off.
73 g[0].gain.linearRampToValueAtTime(v0, t0);
74 g[1].gain.linearRampToValueAtTime(v0, t0);
75
76 // At the end of the linear ramp, schedule a setTarget. (This is the
77 // event that will be cancelled.)
78 let v1 = 0;
79 let t1 = t0;
80 let timeConstant = 0.05;
81
82 g[0].gain.setTargetAtTime(v1, t1, timeConstant);
83 g[1].gain.setTargetAtTime(v1, t1, timeConstant);
84
85 expectedConstant = Math.fround(v1 + (v0 - v1) * Math.exp(-(
86 cancelTime - t0) / timeConstant));
87 return {
88 expectedConstant: expectedConstant,
89 autoMessage: "setTargetAtTime(" + v1 + ", " + t1 + ", " +
90 timeConstant + ")",
91 summary: "setTargetAtTime",
92 };
93 }, {
94 valueThreshold: 4.5267e-7, //1.1317e-7,
95 curveThreshold: 0
96 }).then(task.done.bind(task));
97 });
98
99 audit.define("setValueCurve", function (task, should) {
100 task.describe("Cancel setValueCurveAtTime");
101 // Cancel a setValueCurve event.
102 cancelTest(should, function (g, v0, t0, cancelTime) {
103 // Initialize values to 0.
104 g[0].gain.setValueAtTime(0, 0);
105 g[1].gain.setValueAtTime(0, 0);
106 // Schedule a short linear ramp to start things off.
107 g[0].gain.linearRampToValueAtTime(v0, t0);
108 g[1].gain.linearRampToValueAtTime(v0, t0);
109
110 // After the linear ramp, schedule a setValuesCurve. (This is the
111 // event that will be cancelled.)
112 let v1 = 0;
113 let duration = renderDuration - t0;
114
115 // For simplicity, a 2-point curve so we get a linear interpolated res ult.
116 let curve = Float32Array.from([v0, 0]);
117
118 g[0].gain.setValueCurveAtTime(curve, t0, duration);
119 g[1].gain.setValueCurveAtTime(curve, t0, duration);
120
121 let index = Math.floor((curve.length - 1) / duration * (
122 cancelTime - t0));
123
124 let curvePointsPerFrame = (curve.length - 1) / duration /
125 sampleRate;
126 let virtualIndex = (cancelTime - t0) * sampleRate *
127 curvePointsPerFrame;
128
129 let delta = virtualIndex - index;
130 expectedConstant = curve[0] + (curve[1] - curve[0]) * delta;
131 return {
132 expectedConstant: expectedConstant,
133 autoMessage: "setValueCurveAtTime([" + curve + "], " + t0 +
134 ", " + duration +
135 ")",
136 summary: "setValueCurveAtTime",
137 };
138 }, {
139 valueThreshold: 9.5368e-9,
140 curveThreshold: 0
141 }).then(task.done.bind(task));
142 });
143
144 audit.define("setValueCurve after end", function (task, should) {
145 task.describe("Cancel setValueCurveAtTime after the end");
146 cancelTest(should, function (g, v0, t0, cancelTime) {
147 // Initialize values to 0.
148 g[0].gain.setValueAtTime(0, 0);
149 g[1].gain.setValueAtTime(0, 0);
150 // Schedule a short linear ramp to start things off.
151 g[0].gain.linearRampToValueAtTime(v0, t0);
152 g[1].gain.linearRampToValueAtTime(v0, t0);
153
154 // After the linear ramp, schedule a setValuesCurve. (This is the
155 // event that will be cancelled.) Make sure the curve ends before the
156 // cancellation time.
157 let v1 = 0;
158 let duration = cancelTime - t0 - 0.125;
159
160 // For simplicity, a 2-point curve so we get a linear interpolated
161 // result.
162 let curve = Float32Array.from([v0, 0]);
163
164 g[0].gain.setValueCurveAtTime(curve, t0, duration);
165 g[1].gain.setValueCurveAtTime(curve, t0, duration);
166
167 expectedConstant = curve[1];
168 return {
169 expectedConstant: expectedConstant,
170 autoMessage: "setValueCurveAtTime([" + curve + "], " + t0 +
171 ", " + duration +
172 ")",
173 summary: "setValueCurveAtTime",
174 };
175 }, {
176 valueThreshold: 0,
177 curveThreshold: 0
178 }).then(task.done.bind(task));
179 });
180
181 // Special case where we schedule a setTarget and there is no earlier
182 // automation event. This tests that we pick up the starting point
183 // correctly from the last setting of the AudioParam value attribute.
184
185
186 audit.define("initial setTarget", function (task, should) {
187 task.describe("Cancel with initial setTargetAtTime");
188 cancelTest(should, function (g, v0, t0, cancelTime) {
189 let v1 = 0;
190 let timeConstant = 0.1;
191 g[0].gain.value = 1;
192 g[0].gain.setTargetAtTime(v1, t0, timeConstant);
193 g[1].gain.value = 1;
194 g[1].gain.setTargetAtTime(v1, t0, timeConstant);
195
196 let expectedConstant = Math.fround(v1 + (v0 - v1) * Math.exp(-
197 (cancelTime - t0) /
198 timeConstant));
199
200 return {
201 expectedConstant: expectedConstant,
202 autoMessage: "setTargetAtTime(" + v1 + ", " + t0 + ", " +
203 timeConstant + ")",
204 summary: "Initial setTargetAtTime",
205 };
206 }, {
207 valueThreshold: 1.2320e-6,
208 curveThreshold: 0
209 }).then(task.done.bind(task));
210 });
211
212 // Test automations scheduled after the call to cancelValuesAndHoldAtTime.
213 // Very similar to the above tests, but we also schedule an event after
214 // cancelValuesAndHoldAtTime and verify that curve after cancellation has
215 // the correct values.
216
217 audit.define("post cancel: Linear", function (task, should) {
218 // Run the cancel test using a linearRamp as the event to be cancelled.
219 // Then schedule another linear ramp after the cancellation.
220 task.describe("LinearRamp after cancelling");
221 cancelTest(should, linearRampTest(
222 "Post cancellation linearRampToValueAtTime"), {
223 valueThreshold: 8.3998e-5,
224 curveThreshold: 0
225 }, function (g, cancelTime, expectedConstant) {
226 // Schedule the linear ramp on g[0], and do the same for g[2], using t he starting point
227 // given by expectedConstant.
228 let v2 = 2;
229 let t2 = cancelTime + 0.125;
230 g[0].gain.linearRampToValueAtTime(v2, t2);
231 g[2].gain.setValueAtTime(expectedConstant, cancelTime);
232 g[2].gain.linearRampToValueAtTime(v2, t2);
233 return {
234 constantEndTime: cancelTime,
235 message: "Post linearRamp(" + v2 + ", " + t2 + ")"
236 };
237 }).then(task.done.bind(task));
238 });
239
240 audit.define("post cancel: Exponential", function (task, should) {
241 task.describe("ExponentialRamp after cancelling");
242 // Run the cancel test using a linearRamp as the event to be cancelled.
243 // Then schedule an exponential ramp after the cancellation.
244 cancelTest(should, linearRampTest(
245 "Post cancel exponentialRampToValueAtTime"), {
246 valueThreshold: 8.3998e-5,
247 curveThreshold: 0
248 }, function (g, cancelTime, expectedConstant) {
249 // Schedule the exponential ramp on g[0], and do the same for g[2],
250 // using the starting point given by expectedConstant.
251 let v2 = 2;
252 let t2 = cancelTime + 0.125;
253 g[0].gain.exponentialRampToValueAtTime(v2, t2);
254 g[2].gain.setValueAtTime(expectedConstant, cancelTime);
255 g[2].gain.exponentialRampToValueAtTime(v2, t2);
256 return {
257 constantEndTime: cancelTime,
258 message: "Post exponentialRamp(" + v2 + ", " + t2 + ")"
259 };
260 }).then(task.done.bind(task));
261 });
262
263 audit.define("post cancel: ValueCurve", function (task, should) {
264 // Run the cancel test using a linearRamp as the event to be cancelled.
265 // Then schedule a setValueCurve after the cancellation.
266 cancelTest(should, linearRampTest("Post cancel setValueCurveAtTime"), {
267 valueThreshold: 8.3998e-5,
268 curveThreshold: 0
269 }, function (g, cancelTime, expectedConstant) {
270 // Schedule the exponential ramp on g[0], and do the same for g[2],
271 // using the starting point given by expectedConstant.
272 let t2 = cancelTime + 0.125;
273 let duration = 0.125;
274 let curve = Float32Array.from([.125, 2]);
275 g[0].gain.setValueCurveAtTime(curve, t2, duration);
276 g[2].gain.setValueAtTime(expectedConstant, cancelTime);
277 g[2].gain.setValueCurveAtTime(curve, t2, duration);
278 return {
279 constantEndTime: cancelTime,
280 message: "Post setValueCurve([" + curve + "], " + t2 + ", " +
281 duration + ")",
282 errorThreshold: 8.3998e-5
283 };
284 }).then(task.done.bind(task));
285 });
286
287 audit.define("post cancel: setTarget", function (task, should) {
288 // Run the cancel test using a linearRamp as the event to be cancelled.
289 // Then schedule a setTarget after the cancellation.
290 cancelTest(should, linearRampTest("Post cancel setTargetAtTime"), {
291 valueThreshold: 8.3998e-5,
292 curveThreshold: 0
293 }, function (g, cancelTime, expectedConstant) {
294 // Schedule the exponential ramp on g[0], and do the same for g[2],
295 // using the starting point given by expectedConstant.
296 let v2 = 0.125;
297 let t2 = cancelTime + 0.125;
298 let timeConstant = 0.1;
299 g[0].gain.setTargetAtTime(v2, t2, timeConstant);
300 g[2].gain.setValueAtTime(expectedConstant, cancelTime);
301 g[2].gain.setTargetAtTime(v2, t2, timeConstant);
302 return {
303 constantEndTime: cancelTime + 0.125,
304 message: "Post setTargetAtTime(" + v2 + ", " + t2 + ", " +
305 timeConstant + ")",
306 errorThreshold: 8.4037e-5
307 };
308 }).then(task.done.bind(task));
309 });
310
311 audit.define("post cancel: setValue", function (task, should) {
312 // Run the cancel test using a linearRamp as the event to be cancelled.
313 // Then schedule a setTarget after the cancellation.
314 cancelTest(should, linearRampTest("Post cancel setValueAtTime"), {
315 valueThreshold: 8.3998e-5,
316 curveThreshold: 0
317 }, function (g, cancelTime, expectedConstant) {
318 // Schedule the exponential ramp on g[0], and do the same for g[2],
319 // using the starting point given by expectedConstant.
320 let v2 = 0.125;
321 let t2 = cancelTime + 0.125;
322 g[0].gain.setValueAtTime(v2, t2);
323 g[2].gain.setValueAtTime(expectedConstant, cancelTime);
324 g[2].gain.setValueAtTime(v2, t2);
325 return {
326 constantEndTime: cancelTime + 0.125,
327 message: "Post setValueAtTime(" + v2 + ", " + t2 + ")"
328 };
329 }).then(task.done.bind(task));
330 });
331
332 audit.run();
333
334 // Common function for doing a linearRamp test. This just does a linear
335 // ramp from 0 to v0 at from time 0 to t0. Then another linear ramp is
336 // scheduled from v0 to 0 from time t0 to t1. This is the ramp that is to
337 // be cancelled.
338 function linearRampTest(message) {
339 return function (g, v0, t0, cancelTime) {
340 g[0].gain.setValueAtTime(0, 0);
341 g[1].gain.setValueAtTime(0, 0);
342 g[0].gain.linearRampToValueAtTime(v0, t0);
343 g[1].gain.linearRampToValueAtTime(v0, t0);
344
345 let v1 = 0;
346 let t1 = renderDuration;
347 g[0].gain.linearRampToValueAtTime(v1, t1);
348 g[1].gain.linearRampToValueAtTime(v1, t1);
349
350 expectedConstant = Math.fround(v0 + (v1 - v0) * (cancelTime - t0) /
351 (t1 - t0));
352
353 return {
354 expectedConstant: expectedConstant,
355 autoMessage: "linearRampToValue(" + v1 + ", " + t1 + ")",
356 summary: message,
357 };
358 }
359 }
360
361 // Run the cancellation test. A set of automations is created and
362 // canceled.
363 //
364 // |testFunction| is a function that generates the automation to be
365 // tested. It is given an array of 3 gain nodes, the value and time of an
366 // initial linear ramp, and the time where the cancellation should occur.
367 // The function must do the automations for the first two gain nodes. It
368 // must return a dictionary with |expectedConstant| being the value at the
369 // cancellation time, |autoMessage| for message to describe the test, and
370 // |summary| for general summary message to be printed at the end of the
371 // test.
372 //
373 // |thresholdOptions| is a property bag that specifies the error threshold
374 // to use. |thresholdOptions.valueThreshold| is the error threshold for
375 // comparing the actual constant output after cancelling to the expected
376 // value. |thresholdOptions.curveThreshold| is the error threshold for
377 // comparing the actual and expected automation curves before the
378 // cancelation point.
379 //
380 // For cancellation tests, |postCancelTest| is a function that schedules
381 // some automation after the cancellation. It takes 3 arguments: an array
382 // of the gain nodes, the cancellation time, and the expected value at the
383 // cancellation time. This function must return a dictionary consisting
384 // of |constantEndtime| indicating when the held constant from
385 // cancellation stops being constant, |message| giving a summary of what
386 // automation is being used, and |errorThreshold| that is the error
387 // threshold between the expected curve and the actual curve.
388 //
389 function cancelTest(should, testerFunction, thresholdOptions,
390 postCancelTest) {
391 // Create a context with three channels. Channel 0 is the test channel
392 // containing the actual output that includes the cancellation of
393 // events. Channel 1 is the expected data upto the cancellation so we
394 // can verify the cancellation produced the correct result. Channel 2
395 // is for verifying events inserted after the cancellation so we can
396 // verify that automations are correctly generated after the
397 // cancellation point.
398 let context = new OfflineAudioContext(3, renderDuration * sampleRate,
399 sampleRate);
400
401 // Test source is a constant signal
402 let src = context.createBufferSource();
403 src.buffer = createConstantBuffer(context, 1, 1);
404 src.loop = true;
405
406 // We'll do the automation tests with three gain nodes. One (g0) will
407 // have cancelValuesAndHoldAtTime and the other (g1) will not. g1 is
408 // used as the expected result for that automation up to the
409 // cancellation point. They should be the same. The third node (g2) is
410 // used for testing automations inserted after the cancellation point,
411 // if any. g2 is the expected result from the cancellation point to the
412 // end of the test.
413
414 let g0 = context.createGain();
415 let g1 = context.createGain();
416 let g2 = context.createGain();
417 let v0 = 1;
418 let t0 = 0.01;
419
420 let cancelTime = renderDuration / 2;
421
422 // Test automation here. The tester function is responsible for setting
423 // up the gain nodes with the desired automation for testing.
424 autoResult = testerFunction([g0, g1, g2], v0, t0, cancelTime);
425 let expectedConstant = autoResult.expectedConstant;
426 let autoMessage = autoResult.autoMessage;
427 let summaryMessage = autoResult.summary;
428
429 // Cancel scheduled events somewhere in the middle of the test
430 // automation.
431 g0.gain.cancelValuesAndHoldAtTime(cancelTime);
432
433 let constantEndTime;
434 if (postCancelTest) {
435 postResult = postCancelTest([g0, g1, g2], cancelTime,
436 expectedConstant);
437 constantEndTime = postResult.constantEndTime;
438 }
439
440 // Connect everything together (with a merger to make a two-channel
441 // result). Channel 0 is the test (with cancelValuesAndHoldAtTime) and
442 // channel 1 is the reference (without cancelValuesAndHoldAtTime).
443 // Channel 1 is used to verify that everything up to the cancellation
444 // has the correct values.
445 src.connect(g0);
446 src.connect(g1);
447 src.connect(g2);
448 let merger = context.createChannelMerger(3);
449 g0.connect(merger, 0, 0);
450 g1.connect(merger, 0, 1);
451 g2.connect(merger, 0, 2);
452 merger.connect(context.destination);
453
454 // Go!
455 src.start();
456
457 return context.startRendering().then(function (buffer) {
458 let actual = buffer.getChannelData(0);
459 let expected = buffer.getChannelData(1);
460
461 // The actual output should be a constant from the cancel time to the
462 // end. We use the last value of the actual output as the constant,
463 // but we also want to compare that with what we thought it should
464 // really be.
465
466 let cancelFrame = Math.ceil(cancelTime * sampleRate);
467
468 // Verify that the curves up to the cancel time are "identical". The
469 // should be but round-off may make them differ slightly due to the
470 // way cancelling is done.
471 let endFrame = Math.floor(cancelTime * sampleRate);
472 should(actual.slice(0, endFrame),
473 autoMessage + " up to time " + cancelTime)
474 .beCloseToArray(expected.slice(0, endFrame), {
475 absoluteThreshold: thresholdOptions.curveThreshold
476 });
477
478 // Verify the output after the cancellation is a constant.
479 let actualTail;
480 let constantEndFrame;
481
482 if (postCancelTest) {
483 constantEndFrame = Math.ceil(constantEndTime * sampleRate);
484 actualTail = actual.slice(cancelFrame, constantEndFrame);
485 } else {
486 actualTail = actual.slice(cancelFrame);
487 }
488
489 let actualConstant = actual[cancelFrame];
490
491 should(actualTail, "Cancelling " + autoMessage + " at time " +
492 cancelTime)
493 .beConstantValueOf(actualConstant);
494
495 // Verify that the constant is the value we expect.
496 should(actualConstant, "Expected value for cancelling " +
497 autoMessage + " at time " +
498 cancelTime)
499 .beCloseTo(expectedConstant, {
500 threshold: thresholdOptions.valueThreshold
501 });
502
503 // Verify the curve after the constantEndTime matches our
504 // expectations.
505 if (postCancelTest) {
506 let c2 = buffer.getChannelData(2);
507 should(actual.slice(constantEndFrame), postResult.message)
508 .beCloseToArray(c2.slice(constantEndFrame), {
509 absoluteThreshold: postResult.errorThreshold || 0
510 });
511 }
512 });
513 }
514 </script>
515 </body>
516 </html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698