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

Unified Diff: LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html

Issue 1277443005: Use interpolation for setValueCurveAtTime (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Corrected test thresholds and results Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
diff --git a/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html b/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
new file mode 100644
index 0000000000000000000000000000000000000000..de4a6e2b55b29d59bef54d3cd5b8938f2af60e4a
--- /dev/null
+++ b/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
@@ -0,0 +1,254 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Test Interpolation for AudioParam.setValueCurveAtTime</title>
+ <script src="../resources/js-test.js"></script>
+ <script src="resources/compatibility.js"></script>
+ <script src="resources/audio-testing.js"></script>
+ </head>
+
+ <body>
+ <script>
+ description("Test Interpolation for AudioParam.setValueCurveAtTime");
+ window.jsTestIsAsync = true;
+
+ // Play a constant signal through a gain node that is automated using setValueCurveAtTime with
+ // a 2-element curve. The output should be a linear change.
+
+ // Choose a sample rate that is a multiple of 128, the rendering quantum size. This makes the
+ // math work out to be nice numbers.
+ var sampleRate = 25600;
+ var testDurationSec = 1;
+ var testDurationFrames = testDurationSec * sampleRate;
+
+ // Where the curve starts and its duration. This MUST be less than the total rendering time.
+ var curveStartTime = 256 / sampleRate;
+ var curveDuration = 300 / sampleRate;;
+ var curveValue = 0.75;
+
+ // At this time, the gain node goes to gain 1. This is used to make sure the value curve is
+ // propagated correctly until the next event.
+ var fullGainTime = 0.75;
+
+ // Thresholds use to determine if the test passes; these are experimentally determined. The
+ // SNR between the actual and expected result should be at least |snrThreshold|. The maximum
+ // difference betwen them should not exceed |maxErrorThreshold|.
+ var snrThreshold = 10000;
+ var maxErrorThreshold = 0;
+
+ var context;
+ var actualResult;
+ var expectedResult;
+
+ var audit = Audit.createTaskRunner();
+
+ // Array of test configs. Each config must specify curveStartTime, curveDuration,
+ // curveLength, fullGainTime, maxErrorThreshold, and snrThreshold.
+ var testConfigs = [{
+ // The main test
+ curveStartTime: 256 / sampleRate,
+ curveDuration: 300 / sampleRate,
+ curveLength: 2,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 0,
+ snrThreshold: 10000
+ }, {
+ // Increase the curve length
+ curveStartTime: 256 / sampleRate,
+ curveDuration: 300 / sampleRate,
+ curveLength: 3,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 0,
+ snrThreshold: 10000
+ }, {
+ // Increase the curve length
+ curveStartTime: 256 / sampleRate,
+ curveDuration: 300 / sampleRate,
+ curveLength: 16,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 5.961e-8,
+ snrThreshold: 172.746
+ }, {
+ // Increase the curve length
+ curveStartTime: 256 / sampleRate,
+ curveDuration: 300 / sampleRate,
+ curveLength: 100,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 5.961e-8,
+ snrThreshold: 172.799
+ }, {
+ // Corner case with duration less than a frame!
+ curveStartTime: 256 / sampleRate,
+ curveDuration: 0.25 / sampleRate,
+ curveLength: 2,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 0,
+ snrThreshold: 10000
+ }, {
+ // Short duration test
+ curveStartTime: 256 / sampleRate,
+ curveDuration: 2 / sampleRate,
+ curveLength: 2,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 0,
+ snrThreshold: 10000
+ }, {
+ // Short duration test with many points.
+ curveStartTime: 256 / sampleRate,
+ curveDuration: 2 / sampleRate,
+ curveLength: 8,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 0,
+ snrThreshold: 10000
+ }, {
+ // Long duration, big curve
+ curveStartTime: 256 / sampleRate,
+ curveDuration: .5,
+ curveLength: 1000,
+ fullGainTime: 0.75,
+ maxErrorThreshold: 5.961e-8,
+ snrThreshold: 155.310
+ }];
+
+ // Creates a function based on the test config that is suitable for use by defineTask().
+ function createTaskFunction(config) {
+ return function (done) {
+ runTest(config).then(done);
+ };
+ }
+
+ // Define a task for each config, in the order listed in testConfigs.
+ for (var k = 0; k < testConfigs.length; ++k) {
+ var config = testConfigs[k];
+ var name = k + ":curve=" + config.curveLength + ",duration=" + (config.curveDuration * sampleRate);
+ audit.defineTask(name, createTaskFunction(config));
+ }
+
+ // Must be the last defined task.
+ audit.defineTask("end", function (done) {
+ finishJSTest();
+ done();
+ });
+
+ function runTest(config) {
+ context = new OfflineAudioContext(1, testDurationFrames, sampleRate);
+
+ // A constant audio source of value 1.
+ var source = context.createBufferSource();
+ source.buffer = createConstantBuffer(context, 1, 1);
+ source.loop = true;
+
+ // The value curve for testing. Just to make things easy for testing, make the curve a
+ // simple ramp up to curveValue.
+ // TODO(rtoy): Maybe allow more complicated curves?
+ var curve = new Float32Array(config.curveLength);
+ for (var k = 0; k < config.curveLength; ++k) {
+ curve[k] = curveValue / (config.curveLength - 1) * k;
+ }
+
+ // A gain node that is to be automated using setValueCurveAtTime.
+ var gain = context.createGain();
+ gain.gain.value = 0;
+ gain.gain.setValueCurveAtTime(curve, config.curveStartTime, config.curveDuration);
+ // This is to verify that setValueCurveAtTime ends appropriately.
+ gain.gain.setValueAtTime(1, config.fullGainTime);
+
+ source.connect(gain);
+ gain.connect(context.destination);
+ source.start();
+
+ // Some consistency checks on the test parameters
+ Should("Check: Curve end time", config.curveStartTime + config.curveDuration)
+ .beLessThanOrEqualTo(testDurationSec);
+ Should("Check: Full gain start time", config.fullGainTime).beLessThanOrEqualTo(testDurationSec);
+ Should("Check: Full gain start time", config.fullGainTime).beGreaterThanOrEqualTo(config.curveStartTime + config.curveDuration);
+
+ // Rock and roll!
+ return context.startRendering().then(checkResult(config));
+ }
+
+ // Return a function to check that the rendered result matches the expected result.
+ function checkResult(config) {
+ return function (renderedBuffer) {
+ var success = true;
+
+ actualResult = renderedBuffer.getChannelData(0);
+ expectedResult = computeExpectedResult(config);
+
+ // Compute the SNR and max absolute difference between the actual and expected result.
+ var SNR = 10*Math.log10(computeSNR(actualResult, expectedResult));
+ var maxDiff = -1;
+ var posn = -1;
+
+ for (var k = 0; k < actualResult.length; ++k) {
+ var diff = Math.abs(actualResult[k] - expectedResult[k]);
+ if (maxDiff < diff) {
+ maxDiff = diff;
+ posn = k;
+ }
+ }
+
+ success = success && Should("SNR", SNR).beGreaterThanOrEqualTo(config.snrThreshold);
+
+ if (maxDiff <= config.maxErrorThreshold) {
+ testPassed("Max difference is less than or equal to " + config.maxErrorThreshold + ".");
+ } else {
+ testFailed("Max difference (" + maxDiff + ") NOT less than or equal to " +
+ config.maxErrorThreshold + " at frame " + posn + ".");
+ success = false;
+ }
+
+ var message = "Test: curve length = " + config.curveLength + "; duration frames = " +
+ config.curveDuration * sampleRate + ".\n";
+
+ if (success)
+ testPassed(message);
+ else
+ testFailed(message);
+ }
+ }
+
+ // Compute the expected result based on the config settings.
+ function computeExpectedResult(config) {
+ // The automation curve starts at |curveStartTime| and has duration |curveDuration|. So,
+ // the output should be zero until curveStartTime, linearly ramp up from there to
+ // |curveValue|, and then be constant 1 from then to the end of the buffer.
+
+ var expected = new Float32Array(testDurationFrames);
+
+ var curveStartFrame = config.curveStartTime * sampleRate;
+ var curveEndFrame = Math.floor((config.curveStartTime + config.curveDuration) * sampleRate);
+ var fullGainFrame = config.fullGainTime * sampleRate;
+
+ // TODO(crbug.com/517491): setValueAtTime is off by one rendering quantum.
+ fullGainFrame += 128;
+
+ var k;
+
+ // Zero out the start.
+ for (k = 0; k < curveStartFrame; ++k)
+ expected[k] = 0;
+
+ // Linearly ramp now. This assumes that the actual curve used is a linear ramp, even if
+ // there are many curve points.
+ var stepSize = curveValue / (config.curveDuration * sampleRate - 1);
+ for (; k < curveEndFrame; ++k)
+ expected[k] = stepSize * (k - curveStartFrame);
+
+ // Hold it constant until the next event
+ for (; k < fullGainFrame; ++k)
+ expected[k] = curveValue;
+
+ // Amplitude is one for the rest of the test.
+ for (; k < testDurationFrames; ++k)
+ expected[k] = 1;
+
+ return expected;
+ }
+
+ audit.runTasks();
+
+ successfullyParsed = true;
+ </script>
+ </body>
+</html>

Powered by Google App Engine
This is Rietveld 408576698