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

Unified Diff: third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js

Issue 1377903002: Use frames instead of time for running AudioParam timelines. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 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: third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js
index 3df3083d1a58ab9b635424046fda7041f064c712..abcbce13998ffeab488c0dfbb20abaa64acb7baf 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js
@@ -33,19 +33,6 @@ function renderLength(numberOfTests)
return timeToSampleFrame((numberOfTests + 1) * timeInterval, sampleRate);
}
-// Create a buffer containing the same constant value.
-function createConstantBuffer(context, constant, length) {
- var buffer = context.createBuffer(1, length, context.sampleRate);
- var n = buffer.length;
- var data = buffer.getChannelData(0);
-
- for (var k = 0; k < n; ++k) {
- data[k] = constant;
- }
-
- return buffer;
-}
-
// Create a constant reference signal with the given |value|. Basically the same as
// |createConstantBuffer|, but with the parameters to match the other create functions. The
// |endValue| is ignored.
@@ -55,25 +42,43 @@ function createConstantArray(startTime, endTime, value, endValue, sampleRate)
var endFrame = timeToSampleFrame(endTime, sampleRate);
var length = endFrame - startFrame;
- var buffer = createConstantBuffer(context, value, length);
+ var buffer = createConstantBuffer(context, length, value);
return buffer.getChannelData(0);
}
+function getStartEndFrames(startTime, endTime, sampleRate)
+{
+ // Start frame is the ceiling of the start time because the ramp
+ // starts at or after the sample frame. End frame is the ceiling
+ // because it's the exclusive ending frame of the automation.
+ var startFrame = Math.ceil(startTime * sampleRate);
+ var endFrame = Math.ceil(endTime * sampleRate);
+
+ return {startFrame: startFrame, endFrame: endFrame};
+}
+
// Create a linear ramp starting at |startValue| and ending at |endValue|. The ramp starts at time
// |startTime| and ends at |endTime|. (The start and end times are only used to compute how many
// samples to return.)
function createLinearRampArray(startTime, endTime, startValue, endValue, sampleRate)
{
- var startFrame = timeToSampleFrame(startTime, sampleRate);
- var endFrame = timeToSampleFrame(endTime, sampleRate);
+ var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
+ var startFrame = frameInfo.startFrame;
+ var endFrame = frameInfo.endFrame;
var length = endFrame - startFrame;
var array = new Array(length);
- var step = (endValue - startValue) / length;
+ var step = Math.fround((endValue - startValue) / (endTime - startTime) / sampleRate);
+ var start = Math.fround(startValue + (endValue - startValue) * (startFrame / sampleRate - startTime) / (endTime - startTime));
+
+ var slope = (endValue - startValue) / (endTime - startTime);
+ // v(t) = v0 + (v1 - v0)*(t-t0)/(t1-t0)
for (k = 0; k < length; ++k) {
- array[k] = startValue + k * step;
+ //array[k] = Math.fround(start + k * step);
+ var t = (startFrame + k) / sampleRate;
+ array[k] = startValue + slope * (t - startTime);
}
return array;
@@ -84,15 +89,20 @@ function createLinearRampArray(startTime, endTime, startValue, endValue, sampleR
// many samples to return.)
function createExponentialRampArray(startTime, endTime, startValue, endValue, sampleRate)
{
- var startFrame = timeToSampleFrame(startTime, sampleRate);
- var endFrame = timeToSampleFrame(endTime, sampleRate);
+ var deltaTime = endTime - startTime;
+
+ var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
+ var startFrame = frameInfo.startFrame;
+ var endFrame = frameInfo.endFrame;
var length = endFrame - startFrame;
var array = new Array(length);
- var multiplier = Math.pow(endValue / startValue, 1 / length);
-
+ var ratio = endValue / startValue;
+
+ // v(t) = v0*(v1/v0)^((t-t0)/(t1-t0))
for (var k = 0; k < length; ++k) {
- array[k] = startValue * Math.pow(multiplier, k);
+ var t = Math.fround((startFrame + k) / sampleRate);
+ array[k] = Math.fround(startValue * Math.pow(ratio, (t - startTime) / deltaTime));
}
return array;
@@ -109,17 +119,52 @@ function discreteTimeConstantForSampleRate(timeConstant, sampleRate)
// return.)
function createExponentialApproachArray(startTime, endTime, startValue, targetValue, sampleRate, timeConstant)
{
- var startFrame = timeToSampleFrame(startTime, sampleRate);
- var endFrame = timeToSampleFrame(endTime, sampleRate);
- var length = endFrame - startFrame;
+ var startFrameFloat = startTime * sampleRate;
+ var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
+ var startFrame = frameInfo.startFrame;
+ var endFrame = frameInfo.endFrame;
+ var length = Math.floor(endFrame - startFrame);
var array = new Array(length);
var c = discreteTimeConstantForSampleRate(timeConstant, sampleRate);
- var value = startValue;
-
+ var delta = startValue - targetValue;
+
+ // v(t) = v1 + (v0 - v1) * exp(-(t-t0)/tau)
for (var k = 0; k < length; ++k) {
+ var t = (startFrame + k) / sampleRate;
+ var value = targetValue + delta * Math.exp(-(t - startTime) / timeConstant);
array[k] = value;
- value += (targetValue - value) * c;
+ }
+
+ return array;
+}
+
+// Create a sine wave of the specified duration.
+function createReferenceSineArray(startTime, endTime, startValue, endValue, sampleRate)
+{
+ // Ignore |startValue| and |endValue| for the sine wave.
+ var curve = createSineWaveArray(endTime - startTime, freqHz, sineAmplitude, sampleRate);
+ // Sample the curve appropriately.
+ var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
+ var startFrame = frameInfo.startFrame;
+ var endFrame = frameInfo.endFrame;
+ var length = Math.floor(endFrame - startFrame);
+ var array = new Array(length);
+
+ // v(t) = linearly interpolate between V[k] and V[k + 1] where k = floor(N/duration*(t - t0))
+ var f = length / (endTime - startTime);
+
+ for (var k = 0; k < length; ++k) {
+ var t = (startFrame + k) / sampleRate;
+ var indexFloat = f * (t - startTime);
+ var index = Math.floor(indexFloat);
+ if (index + 1 < length) {
+ var v0 = curve[index];
+ var v1 = curve[index + 1];
+ array[k] = v0 + (v1 - v0) * (indexFloat - index);
+ } else {
+ array[k] = curve[length - 1];
+ }
}
return array;
@@ -153,6 +198,18 @@ function endValueDelta(timeIntervalIndex)
}
}
+// Relative error metric
+function relativeErrorMetric(actual, expected)
+{
+ return (actual - expected) / Math.abs(expected);
+}
+
+// Difference metric
+function differenceErrorMetric(actual, expected)
+{
+ return actual - expected;
+}
+
// Return the difference between the starting value at |timeIntervalIndex| and the starting value at
// the next time interval. Since we started at a large initial value, we decrease the value at each
// time interval.
@@ -162,7 +219,7 @@ function valueUpdate(timeIntervalIndex)
}
// Compare a section of the rendered data against our expected signal.
-function comparePartialSignals(rendered, expectedFunction, startTime, endTime, valueInfo, sampleRate)
+function comparePartialSignals(rendered, expectedFunction, startTime, endTime, valueInfo, sampleRate, errorMetric)
{
var startSample = timeToSampleFrame(startTime, sampleRate);
var expected = expectedFunction(startTime, endTime, valueInfo.startValue, valueInfo.endValue, sampleRate, timeConstant);
@@ -186,14 +243,14 @@ function comparePartialSignals(rendered, expectedFunction, startTime, endTime, v
testFailed("Nan or infinity for reference data at " + maxErrorIndex);
break;
}
- var error = Math.abs(rendered[startSample + k] - expected[k]);
+ var error = Math.abs(errorMetric(rendered[startSample + k], expected[k]));
if (error > maxError) {
maxError = error;
maxErrorIndex = k;
}
}
- return {maxError : maxError, index : maxErrorIndex};
+ return {maxError : maxError, index : maxErrorIndex, expected: expected};
}
// Find the discontinuities in the data and compare the locations of the discontinuities with the
@@ -270,21 +327,28 @@ function verifyDiscontinuities(values, times, threshold)
// values of each interval.
//
// breakThreshold - threshold to use for determining discontinuities.
-function compareSignals(testName, maxError, renderedData, expectedFunction, timeValueInfo, breakThreshold)
+function compareSignals(testName, maxError, renderedData, expectedFunction, timeValueInfo, breakThreshold, errorMetric)
{
var success = true;
var failedTestCount = 0;
var times = timeValueInfo.times;
var values = timeValueInfo.values;
var n = values.length;
+ var expectedSignal = [];
success = verifyDiscontinuities(renderedData, times, breakThreshold);
for (var k = 0; k < n; ++k) {
- var result = comparePartialSignals(renderedData, expectedFunction, times[k], times[k + 1], values[k], sampleRate);
+ var result = comparePartialSignals(renderedData, expectedFunction, times[k], times[k + 1], values[k], sampleRate, errorMetric);
+
+ expectedSignal = expectedSignal.concat(Array.prototype.slice.call(result.expected));
if (result.maxError > maxError) {
- testFailed("Incorrect value for test " + k + ". Max error = " + result.maxError + " at offset " + (result.index + timeToSampleFrame(times[k], sampleRate)));
+ var offset = result.index + timeToSampleFrame(times[k], sampleRate);
+ testFailed("Incorrect value for test " + k + ". Max error = " + result.maxError
+ + " at offset " + offset
+ + ": actual = " + renderedData[offset]
+ + ", expected = " + expectedSignal[offset] + ".");
++failedTestCount;
}
}
@@ -293,7 +357,7 @@ function compareSignals(testName, maxError, renderedData, expectedFunction, time
testFailed(failedTestCount + " tests failed out of " + n);
success = false;
} else {
- testPassed("All " + n + " tests passed within an acceptable tolerance.");
+ testPassed("All " + n + " tests passed within an acceptable relative tolerance of " + maxError + ".");
}
if (success) {
@@ -315,7 +379,7 @@ function compareSignals(testName, maxError, renderedData, expectedFunction, time
// jumpThreshold - optional parameter that specifies the threshold to use for detecting
// discontinuities. If not specified, defaults to discontinuityThreshold.
//
-function checkResultFunction(testName, error, referenceFunction, jumpThreshold)
+function checkResultFunction(testName, error, referenceFunction, jumpThreshold, errorMetric)
{
return function(event) {
var buffer = event.renderedBuffer;
@@ -329,7 +393,7 @@ function checkResultFunction(testName, error, referenceFunction, jumpThreshold)
threshold = jumpThreshold;
}
- compareSignals(testName, error, renderedData, referenceFunction, timeValueInfo, threshold);
+ compareSignals(testName, error, renderedData, referenceFunction, timeValueInfo, threshold, errorMetric);
finishJSTest();
}
@@ -395,7 +459,7 @@ function doAutomation(numberOfTests, initialValue, setValueFunction, automationF
// jumpThreshold - optional parameter that specifies the threshold to use for detecting
// discontinuities. If not specified, defaults to discontinuityThreshold.
//
-function createAudioGraphAndTest(numberOfTests, initialValue, setValueFunction, automationFunction, testName, maxError, referenceFunction, jumpThreshold)
+function createAudioGraphAndTest(numberOfTests, initialValue, setValueFunction, automationFunction, testName, maxError, referenceFunction, jumpThreshold, errorMetric)
{
if (window.testRunner) {
testRunner.dumpAsText();
@@ -406,7 +470,7 @@ function createAudioGraphAndTest(numberOfTests, initialValue, setValueFunction,
// Create offline audio context.
context = new OfflineAudioContext(2, renderLength(numberOfTests), sampleRate);
- var constantBuffer = createConstantBuffer(context, 1, renderLength(numberOfTests));
+ var constantBuffer = createConstantBuffer(context, renderLength(numberOfTests), 1);
// We use an AudioGainNode here simply as a convenient way to test the AudioParam
// automation, since it's easy to pass a constant value through the node, automate the
@@ -435,6 +499,7 @@ function createAudioGraphAndTest(numberOfTests, initialValue, setValueFunction,
context.oncomplete = checkResultFunction(testName,
maxError,
referenceFunction,
- jumpThreshold);
+ jumpThreshold,
+ errorMetric || relativeErrorMetric);
context.startRendering();
}

Powered by Google App Engine
This is Rietveld 408576698