| 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 b0461fc3a29421e27457719528c231ac90e39112..530c98d45a85aa3c149b85f321dc987b81766cdc 100644
|
| --- a/third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js
|
| +++ b/third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js
|
| @@ -1,26 +1,31 @@
|
| var sampleRate = 44100;
|
|
|
| -// Information about the starting/ending times and starting/ending values for each time interval.
|
| +// Information about the starting/ending times and starting/ending values for
|
| +// each time interval.
|
| var timeValueInfo;
|
|
|
| // The difference between starting values between each time interval.
|
| var startingValueDelta;
|
| -
|
| -// For any automation function that has an end or target value, the end value is based the starting
|
| -// value of the time interval. The starting value will be increased or decreased by
|
| -// |startEndValueChange|. We choose half of |startingValueDelta| so that the ending value will be
|
| -// distinct from the starting value for next time interval. This allows us to detect where the ramp
|
| -// begins and ends.
|
| +
|
| +// For any automation function that has an end or target value, the end value is
|
| +// based the starting value of the time interval. The starting value will be
|
| +// increased or decreased by |startEndValueChange|. We choose half of
|
| +// |startingValueDelta| so that the ending value will be distinct from the
|
| +// starting value for next time interval. This allows us to detect where the
|
| +// ramp begins and ends.
|
| var startEndValueChange;
|
|
|
| -// Default threshold to use for detecting discontinuities that should appear at each time interval.
|
| +// Default threshold to use for detecting discontinuities that should appear at
|
| +// each time interval.
|
| var discontinuityThreshold;
|
|
|
| -// Time interval between value changes. It is best if 1 / numberOfTests is not close to timeInterval.
|
| +// Time interval between value changes. It is best if 1 / numberOfTests is not
|
| +// close to timeInterval.
|
| var timeInterval = .03;
|
|
|
| -// Some suitable time constant so that we can see a significant change over a timeInterval. This is
|
| -// only needed by setTargetAtTime() which needs a time constant.
|
| +// Some suitable time constant so that we can see a significant change over a
|
| +// timeInterval. This is only needed by setTargetAtTime() which needs a time
|
| +// constant.
|
| var timeConstant = timeInterval / 3;
|
|
|
| var gainNode;
|
| @@ -28,343 +33,348 @@ var gainNode;
|
| var context;
|
|
|
| // Make sure we render long enough to capture all of our test data.
|
| -function renderLength(numberOfTests)
|
| -{
|
| - return timeToSampleFrame((numberOfTests + 1) * timeInterval, sampleRate);
|
| +function renderLength(numberOfTests) {
|
| + return timeToSampleFrame((numberOfTests + 1) * timeInterval, sampleRate);
|
| }
|
|
|
| -// 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.
|
| -function createConstantArray(startTime, endTime, value, endValue, sampleRate)
|
| -{
|
| - var startFrame = timeToSampleFrame(startTime, sampleRate);
|
| - var endFrame = timeToSampleFrame(endTime, sampleRate);
|
| - var length = endFrame - startFrame;
|
| +// 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.
|
| +function createConstantArray(startTime, endTime, value, endValue, sampleRate) {
|
| + var startFrame = timeToSampleFrame(startTime, sampleRate);
|
| + var endFrame = timeToSampleFrame(endTime, sampleRate);
|
| + var length = endFrame - startFrame;
|
|
|
| - var buffer = createConstantBuffer(context, length, value);
|
| + var buffer = createConstantBuffer(context, length, value);
|
|
|
| - return buffer.getChannelData(0);
|
| + 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);
|
| +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};
|
| + 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 frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
|
| - var startFrame = frameInfo.startFrame;
|
| - var endFrame = frameInfo.endFrame;
|
| - var length = endFrame - startFrame;
|
| - var array = new Array(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] = Math.fround(start + k * step);
|
| - var t = (startFrame + k) / sampleRate;
|
| - array[k] = startValue + slope * (t - startTime);
|
| - }
|
| -
|
| - return array;
|
| +// 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 frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
|
| + var startFrame = frameInfo.startFrame;
|
| + var endFrame = frameInfo.endFrame;
|
| + var length = endFrame - startFrame;
|
| + var array = new Array(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] = Math.fround(start + k * step);
|
| + var t = (startFrame + k) / sampleRate;
|
| + array[k] = startValue + slope * (t - startTime);
|
| + }
|
| +
|
| + return array;
|
| }
|
|
|
| -// Create an exponential 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 createExponentialRampArray(startTime, endTime, startValue, endValue, 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 ratio = endValue / startValue;
|
| -
|
| - // v(t) = v0*(v1/v0)^((t-t0)/(t1-t0))
|
| - for (var k = 0; k < length; ++k) {
|
| - var t = Math.fround((startFrame + k) / sampleRate);
|
| - array[k] = Math.fround(startValue * Math.pow(ratio, (t - startTime) / deltaTime));
|
| - }
|
| -
|
| - return array;
|
| +// Create an exponential 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 createExponentialRampArray(
|
| + startTime, endTime, startValue, endValue, 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 ratio = endValue / startValue;
|
| +
|
| + // v(t) = v0*(v1/v0)^((t-t0)/(t1-t0))
|
| + for (var k = 0; k < length; ++k) {
|
| + var t = Math.fround((startFrame + k) / sampleRate);
|
| + array[k] =
|
| + Math.fround(startValue * Math.pow(ratio, (t - startTime) / deltaTime));
|
| + }
|
| +
|
| + return array;
|
| }
|
|
|
| -function discreteTimeConstantForSampleRate(timeConstant, sampleRate)
|
| -{
|
| - return 1 - Math.exp(-1 / (sampleRate * timeConstant));
|
| +function discreteTimeConstantForSampleRate(timeConstant, sampleRate) {
|
| + return 1 - Math.exp(-1 / (sampleRate * timeConstant));
|
| }
|
|
|
| -// Create a signal that starts at |startValue| and exponentially approaches the target value of
|
| -// |targetValue|, using a time constant of |timeConstant|. 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 createExponentialApproachArray(startTime, endTime, startValue, targetValue, sampleRate, timeConstant)
|
| -{
|
| - 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 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;
|
| - }
|
| -
|
| - return array;
|
| +// Create a signal that starts at |startValue| and exponentially approaches the
|
| +// target value of |targetValue|, using a time constant of |timeConstant|. 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 createExponentialApproachArray(
|
| + startTime, endTime, startValue, targetValue, sampleRate, timeConstant) {
|
| + 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 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;
|
| + }
|
| +
|
| + 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-1)/duration*(t - t0))
|
| - var f = (length - 1) / (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];
|
| - }
|
| +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-1)/duration*(t - t0))
|
| + var f = (length - 1) / (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;
|
| + return array;
|
| }
|
|
|
| -// Create a sine wave of the given frequency and amplitude. The sine wave is offset by half the
|
| -// amplitude so that result is always positive.
|
| -function createSineWaveArray(durationSeconds, freqHz, amplitude, sampleRate)
|
| -{
|
| - var length = timeToSampleFrame(durationSeconds, sampleRate);
|
| - var signal = new Float32Array(length);
|
| - var omega = 2 * Math.PI * freqHz / sampleRate;
|
| - var halfAmplitude = amplitude / 2;
|
| -
|
| - for (var k = 0; k < length; ++k) {
|
| - signal[k] = halfAmplitude + halfAmplitude * Math.sin(omega * k);
|
| - }
|
| +// Create a sine wave of the given frequency and amplitude. The sine wave is
|
| +// offset by half the amplitude so that result is always positive.
|
| +function createSineWaveArray(durationSeconds, freqHz, amplitude, sampleRate) {
|
| + var length = timeToSampleFrame(durationSeconds, sampleRate);
|
| + var signal = new Float32Array(length);
|
| + var omega = 2 * Math.PI * freqHz / sampleRate;
|
| + var halfAmplitude = amplitude / 2;
|
|
|
| - return signal;
|
| + for (var k = 0; k < length; ++k) {
|
| + signal[k] = halfAmplitude + halfAmplitude * Math.sin(omega * k);
|
| + }
|
| +
|
| + return signal;
|
| }
|
|
|
| -// Return the difference between the starting value and the ending value for time interval
|
| -// |timeIntervalIndex|. We alternate between an end value that is above or below the starting
|
| -// value.
|
| -function endValueDelta(timeIntervalIndex)
|
| -{
|
| - if (timeIntervalIndex & 1) {
|
| - return -startEndValueChange;
|
| - } else {
|
| - return startEndValueChange;
|
| - }
|
| +// Return the difference between the starting value and the ending value for
|
| +// time interval |timeIntervalIndex|. We alternate between an end value that is
|
| +// above or below the starting value.
|
| +function endValueDelta(timeIntervalIndex) {
|
| + if (timeIntervalIndex & 1) {
|
| + return -startEndValueChange;
|
| + } else {
|
| + return startEndValueChange;
|
| + }
|
| }
|
|
|
| // Relative error metric
|
| -function relativeErrorMetric(actual, expected)
|
| -{
|
| - return (actual - expected) / Math.abs(expected);
|
| +function relativeErrorMetric(actual, expected) {
|
| + return (actual - expected) / Math.abs(expected);
|
| }
|
|
|
| // Difference metric
|
| -function differenceErrorMetric(actual, expected)
|
| -{
|
| - return actual - expected;
|
| +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.
|
| -function valueUpdate(timeIntervalIndex)
|
| -{
|
| - return -startingValueDelta;
|
| +// 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.
|
| +function valueUpdate(timeIntervalIndex) {
|
| + return -startingValueDelta;
|
| }
|
|
|
| // Compare a section of the rendered data against our expected signal.
|
| -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);
|
| -
|
| - var n = expected.length;
|
| - var maxError = -1;
|
| - var maxErrorIndex = -1;
|
| -
|
| - for (var k = 0; k < n; ++k) {
|
| - // Make sure we don't pass these tests because a NaN has been generated in either the
|
| - // rendered data or the reference data.
|
| - if (!isValidNumber(rendered[startSample + k])) {
|
| - maxError = Infinity;
|
| - maxErrorIndex = startSample + k;
|
| - testFailed("NaN or infinity for rendered data at " + maxErrorIndex);
|
| - break;
|
| - }
|
| - if (!isValidNumber(expected[k])) {
|
| - maxError = Infinity;
|
| - maxErrorIndex = startSample + k;
|
| - testFailed("Nan or infinity for reference data at " + maxErrorIndex);
|
| - break;
|
| - }
|
| - var error = Math.abs(errorMetric(rendered[startSample + k], expected[k]));
|
| - if (error > maxError) {
|
| - maxError = error;
|
| - maxErrorIndex = k;
|
| - }
|
| +function comparePartialSignals(
|
| + should, rendered, expectedFunction, startTime, endTime, valueInfo,
|
| + sampleRate, errorMetric) {
|
| + var startSample = timeToSampleFrame(startTime, sampleRate);
|
| + var expected = expectedFunction(
|
| + startTime, endTime, valueInfo.startValue, valueInfo.endValue, sampleRate,
|
| + timeConstant);
|
| +
|
| + var n = expected.length;
|
| + var maxError = -1;
|
| + var maxErrorIndex = -1;
|
| +
|
| + for (var k = 0; k < n; ++k) {
|
| + // Make sure we don't pass these tests because a NaN has been generated in
|
| + // either the
|
| + // rendered data or the reference data.
|
| + if (!isValidNumber(rendered[startSample + k])) {
|
| + maxError = Infinity;
|
| + maxErrorIndex = startSample + k;
|
| + should(
|
| + isValidNumber(rendered[startSample + k]),
|
| + 'NaN or infinity for rendered data at ' + maxErrorIndex)
|
| + .beTrue();
|
| + break;
|
| + }
|
| + if (!isValidNumber(expected[k])) {
|
| + maxError = Infinity;
|
| + maxErrorIndex = startSample + k;
|
| + should(
|
| + isValidNumber(expected[k]),
|
| + 'NaN or infinity for rendered data at ' + maxErrorIndex)
|
| + .beTrue();
|
| + break;
|
| }
|
| + var error = Math.abs(errorMetric(rendered[startSample + k], expected[k]));
|
| + if (error > maxError) {
|
| + maxError = error;
|
| + maxErrorIndex = k;
|
| + }
|
| + }
|
|
|
| - return {maxError : maxError, index : maxErrorIndex, expected: expected};
|
| + return {maxError: maxError, index: maxErrorIndex, expected: expected};
|
| }
|
|
|
| -// Find the discontinuities in the data and compare the locations of the discontinuities with the
|
| -// times that define the time intervals. There is a discontinuity if the difference between
|
| -// successive samples exceeds the threshold.
|
| -function verifyDiscontinuities(values, times, threshold)
|
| -{
|
| - var n = values.length;
|
| - var success = true;
|
| - var badLocations = 0;
|
| - var breaks = [];
|
| -
|
| - // Find discontinuities.
|
| - for (var k = 1; k < n; ++k) {
|
| - if (Math.abs(values[k] - values[k - 1]) > threshold) {
|
| - breaks.push(k);
|
| - }
|
| - }
|
| -
|
| - var testCount;
|
| -
|
| - // If there are numberOfTests intervals, there are only numberOfTests - 1 internal interval
|
| - // boundaries. Hence the maximum number of discontinuties we expect to find is numberOfTests -
|
| - // 1. If we find more than that, we have no reference to compare against. We also assume that
|
| - // the actual discontinuities are close to the expected ones.
|
| - //
|
| - // This is just a sanity check when something goes really wrong. For example, if the threshold
|
| - // is too low, every sample frame looks like a discontinuity.
|
| - if (breaks.length >= numberOfTests) {
|
| - testCount = numberOfTests - 1;
|
| - testFailed("Found more discontinuities (" + breaks.length + ") than expected. Only comparing first " + testCount + "discontinuities.");
|
| - success = false;
|
| - } else {
|
| - testCount = breaks.length;
|
| +// Find the discontinuities in the data and compare the locations of the
|
| +// discontinuities with the times that define the time intervals. There is a
|
| +// discontinuity if the difference between successive samples exceeds the
|
| +// threshold.
|
| +function verifyDiscontinuities(should, values, times, threshold) {
|
| + var n = values.length;
|
| + var success = true;
|
| + var badLocations = 0;
|
| + var breaks = [];
|
| +
|
| + // Find discontinuities.
|
| + for (var k = 1; k < n; ++k) {
|
| + if (Math.abs(values[k] - values[k - 1]) > threshold) {
|
| + breaks.push(k);
|
| }
|
| -
|
| - // Compare the location of each discontinuity with the end time of each interval. (There is no
|
| - // discontinuity at the start of the signal.)
|
| - for (var k = 0; k < testCount; ++k) {
|
| - var expectedSampleFrame = timeToSampleFrame(times[k + 1], sampleRate);
|
| - if (breaks[k] != expectedSampleFrame) {
|
| - success = false;
|
| - ++badLocations;
|
| - testFailed("Expected discontinuity at " + expectedSampleFrame + " but got " + breaks[k]);
|
| - }
|
| + }
|
| +
|
| + var testCount;
|
| +
|
| + // If there are numberOfTests intervals, there are only numberOfTests - 1
|
| + // internal interval boundaries. Hence the maximum number of discontinuties we
|
| + // expect to find is numberOfTests - 1. If we find more than that, we have no
|
| + // reference to compare against. We also assume that the actual
|
| + // discontinuities are close to the expected ones.
|
| + //
|
| + // This is just a sanity check when something goes really wrong. For example,
|
| + // if the threshold is too low, every sample frame looks like a discontinuity.
|
| + if (breaks.length >= numberOfTests) {
|
| + testCount = numberOfTests - 1;
|
| + should(breaks.length, 'Number of discontinuities')
|
| + .beLessThan(numberOfTests);
|
| + success = false;
|
| + } else {
|
| + testCount = breaks.length;
|
| + }
|
| +
|
| + // Compare the location of each discontinuity with the end time of each
|
| + // interval. (There is no discontinuity at the start of the signal.)
|
| + for (var k = 0; k < testCount; ++k) {
|
| + var expectedSampleFrame = timeToSampleFrame(times[k + 1], sampleRate);
|
| + if (breaks[k] != expectedSampleFrame) {
|
| + success = false;
|
| + ++badLocations;
|
| + should(breaks[k], 'Discontinuity at index')
|
| + .beEqualTo(expectedSampleFrame);
|
| }
|
| -
|
| - if (badLocations) {
|
| - testFailed(badLocations + " discontinuities at incorrect locations");
|
| - success = false;
|
| - } else {
|
| - if (breaks.length == numberOfTests - 1) {
|
| - testPassed("All " + numberOfTests + " tests started and ended at the correct time.");
|
| - } else {
|
| - testFailed("Found " + breaks.length + " discontinuities but expected " + (numberOfTests - 1));
|
| - success = false;
|
| - }
|
| - }
|
| -
|
| - return success;
|
| + }
|
| +
|
| + if (badLocations) {
|
| + should(badLocations, 'Number of discontinuites at incorrect locations')
|
| + .beEqualTo(0);
|
| + success = false;
|
| + } else {
|
| + should(
|
| + breaks.length + 1,
|
| + 'Number of tests started and ended at the correct time')
|
| + .beEqualTo(numberOfTests);
|
| + }
|
| +
|
| + return success;
|
| }
|
|
|
| // Compare the rendered data with the expected data.
|
| //
|
| // testName - string describing the test
|
| //
|
| -// maxError - maximum allowed difference between the rendered data and the expected data
|
| +// maxError - maximum allowed difference between the rendered data and the
|
| +// expected data
|
| //
|
| // rendererdData - array containing the rendered (actual) data
|
| //
|
| // expectedFunction - function to compute the expected data
|
| //
|
| -// timeValueInfo - array containing information about the start and end times and the start and end
|
| -// values of each interval.
|
| +// timeValueInfo - array containing information about the start and end times
|
| +// and the start and end values of each interval.
|
| //
|
| // breakThreshold - threshold to use for determining discontinuities.
|
| -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, errorMetric);
|
| -
|
| - expectedSignal = expectedSignal.concat(Array.prototype.slice.call(result.expected));
|
| -
|
| - if (result.maxError > maxError) {
|
| - 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;
|
| - }
|
| - }
|
| -
|
| - if (failedTestCount) {
|
| - testFailed(failedTestCount + " tests failed out of " + n);
|
| - success = false;
|
| - } else {
|
| - testPassed("All " + n + " tests passed within an acceptable relative tolerance of " + maxError + ".");
|
| - }
|
| -
|
| - if (success) {
|
| - testPassed("AudioParam " + testName + " test passed.");
|
| - } else {
|
| - testFailed("AudioParam " + testName + " test failed.");
|
| - }
|
| +function compareSignals(
|
| + should, 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(should, renderedData, times, breakThreshold);
|
| +
|
| + for (var k = 0; k < n; ++k) {
|
| + var result = comparePartialSignals(
|
| + should, renderedData, expectedFunction, times[k], times[k + 1],
|
| + values[k], sampleRate, errorMetric);
|
| +
|
| + expectedSignal =
|
| + expectedSignal.concat(Array.prototype.slice.call(result.expected));
|
| +
|
| + should(
|
| + result.maxError,
|
| + 'Max error for test ' + k + ' at offset ' +
|
| + (result.index + timeToSampleFrame(times[k], sampleRate)))
|
| + .beLessThanOrEqualTo(maxError);
|
| + }
|
| +
|
| + should(
|
| + failedTestCount,
|
| + 'Number of failed tests with an acceptable relative tolerance of ' +
|
| + maxError)
|
| + .beEqualTo(0);
|
| }
|
|
|
| // Create a function to test the rendered data with the reference data.
|
| @@ -373,30 +383,33 @@ function compareSignals(testName, maxError, renderedData, expectedFunction, time
|
| //
|
| // error - max allowed error between rendered data and the reference data.
|
| //
|
| -// referenceFunction - function that generates the reference data to be compared with the rendered
|
| -// data.
|
| +// referenceFunction - function that generates the reference data to be compared
|
| +// with the rendered data.
|
| //
|
| -// jumpThreshold - optional parameter that specifies the threshold to use for detecting
|
| -// discontinuities. If not specified, defaults to discontinuityThreshold.
|
| +// jumpThreshold - optional parameter that specifies the threshold to use for
|
| +// detecting discontinuities. If not specified, defaults to
|
| +// discontinuityThreshold.
|
| //
|
| -function checkResultFunction(testName, error, referenceFunction, jumpThreshold, errorMetric)
|
| -{
|
| - return function(event) {
|
| - var buffer = event.renderedBuffer;
|
| - renderedData = buffer.getChannelData(0);
|
| -
|
| - var threshold;
|
| -
|
| - if (!jumpThreshold) {
|
| - threshold = discontinuityThreshold;
|
| - } else {
|
| - threshold = jumpThreshold;
|
| - }
|
| -
|
| - compareSignals(testName, error, renderedData, referenceFunction, timeValueInfo, threshold, errorMetric);
|
| -
|
| - finishJSTest();
|
| +function checkResultFunction(
|
| + task, should, testName, error, referenceFunction, jumpThreshold,
|
| + errorMetric) {
|
| + return function(event) {
|
| + var buffer = event.renderedBuffer;
|
| + renderedData = buffer.getChannelData(0);
|
| +
|
| + var threshold;
|
| +
|
| + if (!jumpThreshold) {
|
| + threshold = discontinuityThreshold;
|
| + } else {
|
| + threshold = jumpThreshold;
|
| }
|
| +
|
| + compareSignals(
|
| + should, testName, error, renderedData, referenceFunction, timeValueInfo,
|
| + threshold, errorMetric);
|
| + task.done();
|
| + }
|
| }
|
|
|
| // Run all the automation tests.
|
| @@ -405,38 +418,40 @@ function checkResultFunction(testName, error, referenceFunction, jumpThreshold,
|
| //
|
| // initialValue - The initial value of the first time interval.
|
| //
|
| -// setValueFunction - function that sets the specified value at the start of a time interval.
|
| +// setValueFunction - function that sets the specified value at the start of a
|
| +// time interval.
|
| //
|
| -// automationFunction - function that sets the end value for the time interval. It specifies how
|
| -// the value approaches the end value.
|
| +// automationFunction - function that sets the end value for the time interval.
|
| +// It specifies how the value approaches the end value.
|
| //
|
| -// An object is returned containing an array of start times for each time interval, and an array
|
| -// giving the start and end values for the interval.
|
| -function doAutomation(numberOfTests, initialValue, setValueFunction, automationFunction)
|
| -{
|
| - var timeInfo = [0];
|
| - var valueInfo = [];
|
| - var value = initialValue;
|
| -
|
| - for (var k = 0; k < numberOfTests; ++k) {
|
| - var startTime = k * timeInterval;
|
| - var endTime = (k + 1) * timeInterval;
|
| - var endValue = value + endValueDelta(k);
|
| -
|
| - // Set the value at the start of the time interval.
|
| - setValueFunction(value, startTime);
|
| -
|
| - // Specify the end or target value, and how we should approach it.
|
| - automationFunction(endValue, startTime, endTime);
|
| -
|
| - // Keep track of the start times, and the start and end values for each time interval.
|
| - timeInfo.push(endTime);
|
| - valueInfo.push({startValue: value, endValue : endValue});
|
| -
|
| - value += valueUpdate(k);
|
| - }
|
| -
|
| - return {times : timeInfo, values : valueInfo};
|
| +// An object is returned containing an array of start times for each time
|
| +// interval, and an array giving the start and end values for the interval.
|
| +function doAutomation(
|
| + numberOfTests, initialValue, setValueFunction, automationFunction) {
|
| + var timeInfo = [0];
|
| + var valueInfo = [];
|
| + var value = initialValue;
|
| +
|
| + for (var k = 0; k < numberOfTests; ++k) {
|
| + var startTime = k * timeInterval;
|
| + var endTime = (k + 1) * timeInterval;
|
| + var endValue = value + endValueDelta(k);
|
| +
|
| + // Set the value at the start of the time interval.
|
| + setValueFunction(value, startTime);
|
| +
|
| + // Specify the end or target value, and how we should approach it.
|
| + automationFunction(endValue, startTime, endTime);
|
| +
|
| + // Keep track of the start times, and the start and end values for each time
|
| + // interval.
|
| + timeInfo.push(endTime);
|
| + valueInfo.push({startValue: value, endValue: endValue});
|
| +
|
| + value += valueUpdate(k);
|
| + }
|
| +
|
| + return {times: timeInfo, values: valueInfo};
|
| }
|
|
|
| // Create the audio graph for the test and then run the test.
|
| @@ -445,61 +460,56 @@ function doAutomation(numberOfTests, initialValue, setValueFunction, automationF
|
| //
|
| // initialValue - the initial value of the gain at time 0.
|
| //
|
| -// setValueFunction - function to set the value at the beginning of each time interval.
|
| +// setValueFunction - function to set the value at the beginning of each time
|
| +// interval.
|
| //
|
| // automationFunction - the AudioParamTimeline automation function
|
| //
|
| // testName - string indicating the test that is being run.
|
| //
|
| -// maxError - maximum allowed error between the rendered data and the reference data
|
| +// maxError - maximum allowed error between the rendered data and the reference
|
| +// data
|
| //
|
| -// referenceFunction - function that generates the reference data to be compared against the
|
| -// rendered data.
|
| +// referenceFunction - function that generates the reference data to be compared
|
| +// against the rendered data.
|
| //
|
| -// jumpThreshold - optional parameter that specifies the threshold to use for detecting
|
| -// discontinuities. If not specified, defaults to discontinuityThreshold.
|
| +// 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, errorMetric)
|
| -{
|
| - if (window.testRunner) {
|
| - testRunner.dumpAsText();
|
| - testRunner.waitUntilDone();
|
| - }
|
| -
|
| - window.jsTestIsAsync = true;
|
| -
|
| - // Create offline audio context.
|
| - context = new OfflineAudioContext(2, renderLength(numberOfTests), sampleRate);
|
| - 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
|
| - // .gain attribute and observe the resulting values.
|
| -
|
| - gainNode = context.createGain();
|
| -
|
| - var bufferSource = context.createBufferSource();
|
| - bufferSource.buffer = constantBuffer;
|
| - bufferSource.connect(gainNode);
|
| - gainNode.connect(context.destination);
|
| -
|
| - // Set up default values for the parameters that control how the automation test values progress
|
| - // for each time interval.
|
| - startingValueDelta = initialValue / numberOfTests;
|
| - startEndValueChange = startingValueDelta / 2;
|
| - discontinuityThreshold = startEndValueChange / 2;
|
| -
|
| - // Run the automation tests.
|
| - timeValueInfo = doAutomation(numberOfTests,
|
| - initialValue,
|
| - setValueFunction,
|
| - automationFunction);
|
| - bufferSource.start(0);
|
| -
|
| - context.oncomplete = checkResultFunction(testName,
|
| - maxError,
|
| - referenceFunction,
|
| - jumpThreshold,
|
| - errorMetric || relativeErrorMetric);
|
| - context.startRendering();
|
| +function createAudioGraphAndTest(
|
| + task, should, numberOfTests, initialValue, setValueFunction,
|
| + automationFunction, testName, maxError, referenceFunction, jumpThreshold,
|
| + errorMetric) {
|
| + // Create offline audio context.
|
| + context = new OfflineAudioContext(2, renderLength(numberOfTests), sampleRate);
|
| + 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 .gain attribute and observe the resulting values.
|
| +
|
| + gainNode = context.createGain();
|
| +
|
| + var bufferSource = context.createBufferSource();
|
| + bufferSource.buffer = constantBuffer;
|
| + bufferSource.connect(gainNode);
|
| + gainNode.connect(context.destination);
|
| +
|
| + // Set up default values for the parameters that control how the automation
|
| + // test values progress for each time interval.
|
| + startingValueDelta = initialValue / numberOfTests;
|
| + startEndValueChange = startingValueDelta / 2;
|
| + discontinuityThreshold = startEndValueChange / 2;
|
| +
|
| + // Run the automation tests.
|
| + timeValueInfo = doAutomation(
|
| + numberOfTests, initialValue, setValueFunction, automationFunction);
|
| + bufferSource.start(0);
|
| +
|
| + context.oncomplete = checkResultFunction(
|
| + task, should, testName, maxError, referenceFunction, jumpThreshold,
|
| + errorMetric || relativeErrorMetric);
|
| + context.startRendering();
|
| }
|
|
|