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

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

Powered by Google App Engine
This is Rietveld 408576698