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

Unified 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 4 years 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-cancel-and-hold.html
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-cancel-and-hold.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-cancel-and-hold.html
new file mode 100644
index 0000000000000000000000000000000000000000..c904e6eb8e752d355b15a89c9eb049d161bcfbab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-cancel-and-hold.html
@@ -0,0 +1,470 @@
+<!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.
+<html>
+ <head>
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script src="../resources/audit-util.js"></script>
+ <script src="../resources/audit.js"></script>
+ <title>Test CancelValuesAndHoldAtTime</title>
+ </head>
+
+ <body>
+ <script>
+ var sampleRate = 48000;
+ var renderDuration = 0.5;
+
+ var audit = Audit.createTaskRunner();
+
+ // The first few tasks test the cancellation of each relevant automation function. For the
+ // test, a simple linear ramp from 0 to 1 is used to start things off. Then the automation to
+ // be tested is scheduled and cancelled.
+
+ audit.define("linear", function (task, should) {
+ task.describe("Cancel linearRampToValueAtTime");
+ cancelTest(should, linearRampTest("linearRampToValueAtTime"), {
+ valueThreshold: 8.3998e-5,
+ curveThreshold: 0
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("exponential", function (task, should) {
+ task.describe("Cancel exponentialRampAtTime");
+ // Cancel an exponential ramp. The thresholds are experimentally determined.
+ cancelTest(should, function (g, v0, t0, cancelTime) {
+ // Initialize values to 0.
+ g[0].gain.setValueAtTime(0, 0);
+ g[1].gain.setValueAtTime(0, 0);
+ // Schedule a short linear ramp to start things off.
+ g[0].gain.linearRampToValueAtTime(v0, t0);
+ g[1].gain.linearRampToValueAtTime(v0, t0);
+
+ // After the linear ramp, schedule an exponential ramp to the end. (This is the event
+ // that will be be cancelled.
+ var v1 = 0.001;
+ var t1 = renderDuration;
+
+ g[0].gain.exponentialRampToValueAtTime(v1, t1);
+ g[1].gain.exponentialRampToValueAtTime(v1, t1);
+
+ expectedConstant = Math.fround(v0 * Math.pow(v1 / v0, (cancelTime - t0) / (t1 -
+ t0)));
+ return {
+ expectedConstant: expectedConstant,
+ autoMessage: "exponentialRampToValue(" + v1 + ", " + t1 + ")",
+ summary: "exponentialRampToValueAtTime",
+ };
+ }, {
+ valueThreshold: 1.8664e-6,
+ curveThreshold: 5.9605e-8
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("setTarget", function (task, should) {
+ task.describe("Cancel setTargetAtTime");
+ // Cancel a setTarget event.
+ cancelTest(should, function (g, v0, t0, cancelTime) {
+ // Initialize values to 0.
+ g[0].gain.setValueAtTime(0, 0);
+ g[1].gain.setValueAtTime(0, 0);
+ // Schedule a short linear ramp to start things off.
+ g[0].gain.linearRampToValueAtTime(v0, t0);
+ g[1].gain.linearRampToValueAtTime(v0, t0);
+
+ // At the end of the linear ramp, schedule a setTarget. (This is the event that will be
+ // cancelled.)
+ var v1 = 0;
+ var t1 = t0;
+ var timeConstant = 0.05;
+
+ g[0].gain.setTargetAtTime(v1, t1, timeConstant);
+ g[1].gain.setTargetAtTime(v1, t1, timeConstant);
+
+ expectedConstant = Math.fround(v1 + (v0 - v1) * Math.exp(-(cancelTime - t0) /
+ timeConstant));
+ return {
+ expectedConstant: expectedConstant,
+ autoMessage: "setTargetAtTime(" + v1 + ", " + t1 + ", " + timeConstant + ")",
+ summary: "setTargetAtTime",
+ };
+ }, {
+ valueThreshold: 4.5267e-7, //1.1317e-7,
+ curveThreshold: 0
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("setValueCurve", function (task, should) {
+ task.describe("Cancel setValueCurveAtTime");
+ // Cancel a setValueCurve event.
+ cancelTest(should, function (g, v0, t0, cancelTime) {
+ // Initialize values to 0.
+ g[0].gain.setValueAtTime(0, 0);
+ g[1].gain.setValueAtTime(0, 0);
+ // Schedule a short linear ramp to start things off.
+ g[0].gain.linearRampToValueAtTime(v0, t0);
+ g[1].gain.linearRampToValueAtTime(v0, t0);
+
+ // After the linear ramp, schedule a setValuesCurve. (This is the event that will be
+ // cancelled.)
+ var v1 = 0;
+ var duration = renderDuration - t0;
+
+ // For simplicity, a 2-point curve so we get a linear interpolated result.
+ var curve = Float32Array.from([v0, 0]);
+
+ g[0].gain.setValueCurveAtTime(curve, t0, duration);
+ g[1].gain.setValueCurveAtTime(curve, t0, duration);
+
+ var index = Math.floor((curve.length - 1) / duration * (cancelTime - t0));
+
+ var curvePointsPerFrame = (curve.length - 1) / duration / sampleRate;
+ var virtualIndex = (cancelTime - t0) * sampleRate * curvePointsPerFrame;
+
+ var delta = virtualIndex - index;
+ expectedConstant = curve[0] + (curve[1] - curve[0]) * delta;
+ return {
+ expectedConstant: expectedConstant,
+ autoMessage: "setValueCurveAtTime([" + curve + "], " + t0 + ", " + duration + ")",
+ summary: "setValueCurveAtTime",
+ };
+ }, {
+ valueThreshold: 9.5368e-9,
+ curveThreshold: 0
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("setValueCurve after end", function (task, should) {
+ task.describe("Cancel setValueCurveAtTime after the end");
+ cancelTest(should, function (g, v0, t0, cancelTime) {
+ // Initialize values to 0.
+ g[0].gain.setValueAtTime(0, 0);
+ g[1].gain.setValueAtTime(0, 0);
+ // Schedule a short linear ramp to start things off.
+ g[0].gain.linearRampToValueAtTime(v0, t0);
+ g[1].gain.linearRampToValueAtTime(v0, t0);
+
+ // After the linear ramp, schedule a setValuesCurve. (This is the event that will be
+ // cancelled.) Make sure the curve ends before the cancellation time.
+ var v1 = 0;
+ var duration = cancelTime - t0 - 0.125;
+
+ // For simplicity, a 2-point curve so we get a linear interpolated result.
+ var curve = Float32Array.from([v0, 0]);
+
+ g[0].gain.setValueCurveAtTime(curve, t0, duration);
+ g[1].gain.setValueCurveAtTime(curve, t0, duration);
+
+ expectedConstant = curve[1];
+ return {
+ expectedConstant: expectedConstant,
+ autoMessage: "setValueCurveAtTime([" + curve + "], " + t0 + ", " + duration + ")",
+ summary: "setValueCurveAtTime",
+ };
+ }, {
+ valueThreshold: 0,
+ curveThreshold: 0
+ }).then(task.done.bind(task));
+ });
+
+ // Special case where we schedule a setTarget and there is no earlier automation event. This
+ // tests that we pick up the starting point correctly from the last setting of the AudioParam
+ // value attribute.
+
+
+ audit.define("initial setTarget", function (task, should) {
+ task.describe("Cancel with initial setTargetAtTime");
+ cancelTest(should, function (g, v0, t0, cancelTime) {
+ var t0 = 0;
+ var v1 = 0;
+ var timeConstant = 0.1;
+ g[0].gain.value = 1;
+ g[0].gain.setTargetAtTime(v1, t0, timeConstant);
+ g[1].gain.value = 1;
+ g[1].gain.setTargetAtTime(v1, t0, timeConstant);
+
+ var expectedConstant = Math.fround(v1 + (v0 - v1) * Math.exp(-(cancelTime - t0) /
+ timeConstant));
+
+ return {
+ expectedConstant: expectedConstant,
+ autoMessage: "setTargetAtTime(" + v1 + ", " + t0 + ", " + timeConstant + ")",
+ summary: "Initial setTargetAtTime",
+ };
+ }, {
+ valueThreshold: 1.0892e-6, //9.0767e-7,
+ curveThreshold: 0
+ }).then(task.done.bind(task));
+ });
+
+ // Test automations scheduled after the call to cancelValuesAndHoldAtTime. Very similar to the
+ // above tests, but we also schedule an event after cancelValuesAndHoldAtTime and verify that
+ // curve after cancellation has the correct values.
+
+ audit.define("post cancel: Linear", function (task, should) {
+ // Run the cancel test using a linearRamp as the event to be cancelled. Then schedule
+ // another linear ramp after the cancellation.
+ task.describe("LinearRamp after cancelling");
+ cancelTest(should, linearRampTest("Post cancellation linearRampToValueAtTime"), {
+ valueThreshold: 8.3998e-5,
+ curveThreshold: 0
+ }, function (g, cancelTime, expectedConstant) {
+ // Schedule the linear ramp on g[0], and do the same for g[2], using the starting point
+ // given by expectedConstant.
+ var v2 = 2;
+ var t2 = cancelTime + 0.125;
+ g[0].gain.linearRampToValueAtTime(v2, t2);
+ g[2].gain.setValueAtTime(expectedConstant, cancelTime);
+ g[2].gain.linearRampToValueAtTime(v2, t2);
+ return {
+ constantEndTime: cancelTime,
+ message: "Post linearRamp(" + v2 + ", " + t2 + ")"
+ };
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("post cancel: Exponential", function (task, should) {
+ task.describe("ExponentialRamp after cancelling");
+ // Run the cancel test using a linearRamp as the event to be cancelled. Then schedule
+ // an exponential ramp after the cancellation.
+ cancelTest(should, linearRampTest("Post cancel exponentialRampToValueAtTime"), {
+ valueThreshold: 8.3998e-5,
+ curveThreshold: 0
+ }, function (g, cancelTime, expectedConstant) {
+ // Schedule the exponential ramp on g[0], and do the same for g[2], using the starting
+ // point given by expectedConstant.
+ var v2 = 2;
+ var t2 = cancelTime + 0.125;
+ g[0].gain.exponentialRampToValueAtTime(v2, t2);
+ g[2].gain.setValueAtTime(expectedConstant, cancelTime);
+ g[2].gain.exponentialRampToValueAtTime(v2, t2);
+ return {
+ constantEndTime: cancelTime,
+ message: "Post exponentialRamp(" + v2 + ", " + t2 + ")"
+ };
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("post cancel: ValueCurve", function (task, should) {
+ // Run the cancel test using a linearRamp as the event to be cancelled. Then schedule
+ // a setValueCurve after the cancellation.
+ cancelTest(should, linearRampTest("Post cancel setValueCurveAtTime"), {
+ valueThreshold: 8.3998e-5,
+ curveThreshold: 0
+ }, function (g, cancelTime, expectedConstant) {
+ // Schedule the exponential ramp on g[0], and do the same for g[2], using the starting
+ // point given by expectedConstant.
+ var t2 = cancelTime + 0.125;
+ var duration = 0.125;
+ var curve = Float32Array.from([.125, 2]);
+ g[0].gain.setValueCurveAtTime(curve, t2, duration);
+ g[2].gain.setValueAtTime(expectedConstant, cancelTime);
+ g[2].gain.setValueCurveAtTime(curve, t2, duration);
+ return {
+ constantEndTime: cancelTime,
+ message: "Post setValueCurve([" + curve + "], " + t2 + ", " + duration + ")",
+ errorThreshold: 8.3998e-5
+ };
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("post cancel: setTarget", function (task, should) {
+ // Run the cancel test using a linearRamp as the event to be cancelled. Then schedule
+ // a setTarget after the cancellation.
+ cancelTest(should, linearRampTest("Post cancel setTargetAtTime"), {
+ valueThreshold: 8.3998e-5,
+ curveThreshold: 0
+ }, function (g, cancelTime, expectedConstant) {
+ // Schedule the exponential ramp on g[0], and do the same for g[2], using the starting
+ // point given by expectedConstant.
+ var v2 = 0.125;
+ var t2 = cancelTime + 0.125;
+ var timeConstant = 0.1;
+ g[0].gain.setTargetAtTime(v2, t2, timeConstant);
+ g[2].gain.setValueAtTime(expectedConstant, cancelTime);
+ g[2].gain.setTargetAtTime(v2, t2, timeConstant);
+ return {
+ constantEndTime: cancelTime + 0.125,
+ message: "Post setTargetAtTime(" + v2 + ", " + t2 + ", " + timeConstant + ")",
+ errorThreshold: 8.4037e-5
+ };
+ }).then(task.done.bind(task));
+ });
+
+ audit.define("post cancel: setValue", function (task, should) {
+ // Run the cancel test using a linearRamp as the event to be cancelled. Then schedule
+ // a setTarget after the cancellation.
+ cancelTest(should, linearRampTest("Post cancel setValueAtTime"), {
+ valueThreshold: 8.3998e-5,
+ curveThreshold: 0
+ }, function (g, cancelTime, expectedConstant) {
+ // Schedule the exponential ramp on g[0], and do the same for g[2], using the starting
+ // point given by expectedConstant.
+ var v2 = 0.125;
+ var t2 = cancelTime + 0.125;
+ g[0].gain.setValueAtTime(v2, t2);
+ g[2].gain.setValueAtTime(expectedConstant, cancelTime);
+ g[2].gain.setValueAtTime(v2, t2);
+ return {
+ constantEndTime: cancelTime + 0.125,
+ message: "Post setValueAtTime(" + v2 + ", " + t2 + ")"
+ };
+ }).then(task.done.bind(task));
+ });
+
+ audit.run();
+
+ // Common function for doing a linearRamp test. This just does a linear ramp from 0 to v0 at
+ // from time 0 to t0. Then another linear ramp is scheduled from v0 to 0 from time t0 to t1.
+ // This is the ramp that is to be cancelled.
+ function linearRampTest(message) {
+ return function (g, v0, t0, cancelTime) {
+ g[0].gain.setValueAtTime(0, 0);
+ g[1].gain.setValueAtTime(0, 0);
+ g[0].gain.linearRampToValueAtTime(v0, t0);
+ g[1].gain.linearRampToValueAtTime(v0, t0);
+
+ var v1 = 0;
+ var t1 = renderDuration;
+ g[0].gain.linearRampToValueAtTime(v1, t1);
+ g[1].gain.linearRampToValueAtTime(v1, t1);
+
+ expectedConstant = Math.fround(v0 + (v1 - v0) * (cancelTime - t0) / (t1 - t0));
+
+ return {
+ expectedConstant: expectedConstant,
+ autoMessage: "linearRampToValue(" + v1 + ", " + t1 + ")",
+ summary: message,
+ };
+ }
+ }
+
+ // 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.
+ //
+ // |testFunction| is a function that generates the automation to be tested. It is given an
+ // array of 3 gain nodes, the value and time of an initial linear ramp, and the time where the
+ // cancellation should occur. The function must do the automations for the first two gain
+ // nodes. It must return a dictionary with |expectedConstant| being the value at the
+ // cancellation time, |autoMessage| for message to describe the test, and |summary| for
+ // general summary message to be printed at the end of the test.
+ //
+ // |thresholdOptions| is a property bag that specifies the error threshold to
+ // use. |thresholdOptions.valueThreshold| is the error threshold for comparing the actual
+ // constant output after cancelling to the expected value. |thresholdOptions.curveThreshold|
+ // is the error threshold for comparing the actual and expected automation curves before the
+ // cancelation point.
+ //
+ // For cancellation tests, |postCancelTest| is a function that schedules some automation after
+ // the cancellation. It takes 3 arguments: an array of the gain nodes, the cancellation time,
+ // and the expected value at the cancellation time. This function must return a dictionary
+ // consisting of |constantEndtime| indicating when the held constant from cancellation stops
+ // being constant, |message| giving a summary of what automation is being used, and
+ // |errorThreshold| that is the error threshold between the expected curve and the actual
+ // curve.
+ //
+ function cancelTest(should, testerFunction, thresholdOptions, postCancelTest) {
+ // Create a context with three channels. Channel 0 is the test channel containing the
+ // actual output that includes the cancellation of events. Channel 1 is the expected data
+ // upto the cancellation so we can verify the cancellation produced the correct result.
+ // Channel 2 is for verifying events inserted after the cancellation so we can verify that
+ // automations are correctly generated after the cancellation point.
+ var context = new OfflineAudioContext(3, renderDuration * sampleRate, sampleRate);
+
+ // Test source is a constant signal
+ var src = context.createBufferSource();
+ src.buffer = createConstantBuffer(context, 1, 1);
+ src.loop = true;
+
+ // We'll do the automation tests with three gain nodes. One (g0) will have
+ // cancelValuesAndHoldAtTime and the other (g1) will not. g1 is used as the expected result for
+ // that automation up to the cancellation point. They should be the same. The third node
+ // (g2) is used for testing automations inserted after the cancellation point, if any. g2
+ // is the expected result from the cancellation point to the end of the test.
+
+ var g0 = context.createGain();
+ var g1 = context.createGain();
+ var g2 = context.createGain();
+ var v0 = 1;
+ var t0 = 0.01;
+
+ var cancelTime = renderDuration / 2;
+
+ // Test automation here. The tester function is responsible for setting up the gain nodes
+ // with the desired automation for testing.
+ autoResult = testerFunction([g0, g1, g2], v0, t0, cancelTime);
+ var expectedConstant = autoResult.expectedConstant;
+ var autoMessage = autoResult.autoMessage;
+ var summaryMessage = autoResult.summary;
+
+ // Cancel scheduled events somewhere in the middle of the test automation.
+ g0.gain.cancelValuesAndHoldAtTime(cancelTime);
+
+ var constantEndTime;
+ if (postCancelTest) {
+ postResult = postCancelTest([g0, g1, g2], cancelTime, expectedConstant);
+ constantEndTime = postResult.constantEndTime;
+ }
+
+ // Connect everything together (with a merger to make a two-channel result). Channel 0 is
+ // the test (with cancelValuesAndHoldAtTime) and channel 1 is the reference (without
+ // cancelValuesAndHoldAtTime). Channel 1 is used to verify that everything up to the
+ // cancellation has the correct values.
+ src.connect(g0);
+ src.connect(g1);
+ src.connect(g2);
+ var merger = context.createChannelMerger(3);
+ g0.connect(merger, 0, 0);
+ g1.connect(merger, 0, 1);
+ g2.connect(merger, 0, 2);
+ merger.connect(context.destination);
+
+ // Go!
+ src.start();
+
+ return context.startRendering().then(function (buffer) {
+ var actual = buffer.getChannelData(0);
+ var expected = buffer.getChannelData(1);
+
+ // The actual output should be a constant from the cancel time to the end. We use the
+ // last value of the actual output as the constant, but we also want to compare that with
+ // what we thought it should really be.
+
+ var cancelFrame = Math.ceil(cancelTime * sampleRate);
+
+ // Verify that the curves up to the cancel time are "identical". The should be but
+ // round-off may make them differ slightly due to the way cancelling is done.
+ var endFrame = Math.floor(cancelTime * sampleRate);
+ should(actual.slice(0, endFrame),
+ autoMessage + " up to time " + cancelTime)
+ .beCloseToArray(expected.slice(0, endFrame), {absoluteThreshold: thresholdOptions.curveThreshold});
+
+ // Verify the output after the cancellation is a constant.
+ var actualTail;
+
+ if (postCancelTest) {
+ var constantEndFrame = Math.ceil(constantEndTime * sampleRate);
+ actualTail = actual.slice(cancelFrame, constantEndFrame);
+ } else {
+ actualTail = actual.slice(cancelFrame);
+ }
+
+ var actualConstant = actual[cancelFrame];
+
+ should(actualTail, "Cancelling " + autoMessage + " at time " + cancelTime)
+ .beConstantValueOf(actualConstant);
+
+ // Verify that the constant is the value we expect.
+ should(actualConstant, "Expected value for cancelling " + autoMessage + " at time " +
+ cancelTime)
+ .beCloseTo(expectedConstant, {threshold: thresholdOptions.valueThreshold});
+
+ // Verify the curve after the constantEndTime matches our expectations.
+ if (postCancelTest) {
+ var c2 = buffer.getChannelData(2);
+ should(actual.slice(constantEndFrame), postResult.message)
+ .beCloseToArray(c2.slice(constantEndFrame), {absoluteThreshold: postResult.errorThreshold || 0});
+ }
+
+ });
+ }
+ </script>
+ </body>
+</html>

Powered by Google App Engine
This is Rietveld 408576698