183 lines
7.1 KiB
HTML
183 lines
7.1 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>
|
|
Updating of Value Attribute from Timeline
|
|
</title>
|
|
<script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script>
|
|
<script src="../../resources/testharnessreport.js"></script>
|
|
<script src="../resources/audit-util.js"></script>
|
|
<script src="../resources/audit.js"></script>
|
|
<script src="../resources/audio-param.js"></script>
|
|
</head>
|
|
<body>
|
|
<script id="layout-test-code">
|
|
// This should be a power of two so that all time computations have no
|
|
// round-off errors.
|
|
let sampleRate = 32768;
|
|
let renderQuantumSize = 128;
|
|
// How many tests to run.
|
|
let renderLoops = 20;
|
|
let renderFrames = renderLoops * renderQuantumSize;
|
|
let renderDuration = renderFrames / sampleRate;
|
|
|
|
let audit = Audit.createTaskRunner();
|
|
|
|
audit.define('linear', (task, should) => {
|
|
// Test the value attribute from a linearRamp event
|
|
runTest(should, function(g, v0, t0, v1, t1) {
|
|
g.gain.linearRampToValueAtTime(v1, t1);
|
|
return {
|
|
expectedValue: function(testTime) {
|
|
return audioParamLinearRamp(testTime, v0, t0, v1, t1);
|
|
},
|
|
message: 'linearRamp(' + v1 + ', ' + t1 + ')',
|
|
errorThreshold: 1.1650e-6
|
|
};
|
|
}).then(() => task.done());
|
|
});
|
|
|
|
audit.define('exponential', (task, should) => {
|
|
// Test the value attribute from an exponentialRamp event
|
|
runTest(should, function(g, v0, t0, v1, t1) {
|
|
g.gain.exponentialRampToValueAtTime(v1, t1);
|
|
return {
|
|
expectedValue: function(testTime) {
|
|
return audioParamExponentialRamp(testTime, v0, t0, v1, t1);
|
|
},
|
|
message: 'exponentialRamp(' + v1 + ', ' + t1 + ')',
|
|
errorThreshold: 7.4601e-7
|
|
};
|
|
}).then(() => task.done());
|
|
});
|
|
|
|
audit.define('setTarget', (task, should) => {
|
|
// Test the value attribute from a setTargetAtTime event
|
|
runTest(should, function(g, v0, t0, v1, t1) {
|
|
let timeConstant = 0.1;
|
|
let vFinal = 0;
|
|
g.gain.setTargetAtTime(vFinal, t0, timeConstant);
|
|
return {
|
|
expectedValue: function(testTime) {
|
|
return audioParamSetTarget(
|
|
testTime, v0, t0, vFinal, timeConstant);
|
|
},
|
|
message: 'setTargetAtTime(' + vFinal + ', ' + t0 + ', ' +
|
|
timeConstant + ')',
|
|
errorThreshold: 2.2599e-6
|
|
};
|
|
}).then(() => task.done());
|
|
});
|
|
|
|
audit.define('setValueCurve', (task, should) => {
|
|
// Test the value attribute from a setValueCurve event
|
|
runTest(should, function(g, v0, t0, v1, t1) {
|
|
let curve = [1, 1.5, 4];
|
|
let duration = t1 - t0;
|
|
g.gain.setValueCurveAtTime(Float32Array.from(curve), t0, duration);
|
|
return {
|
|
expectedValue: function(testTime) {
|
|
return audioParamSetValueCurve(testTime, curve, t0, duration);
|
|
},
|
|
message: 'setValueCurveAtTime([' + curve + '], ' + t0 + ', ' +
|
|
duration + ')',
|
|
errorThreshold: 7.9577e-8
|
|
};
|
|
}).then(() => task.done());
|
|
});
|
|
|
|
audit.run();
|
|
|
|
// Test that the .value getter has the correct value when a timeline is
|
|
// running. The |testFunction| is the underlying test to be run.
|
|
function runTest(should, testFunction) {
|
|
// Create a simple graph consisting of a constant source and a gain node
|
|
// where the automations are run. A setValueAtTime event starts things
|
|
// off.
|
|
let context = new OfflineAudioContext(1, renderFrames, sampleRate);
|
|
let source = context.createBufferSource();
|
|
source.buffer = createConstantBuffer(context, 1, 1);
|
|
source.loop = true;
|
|
let gain = context.createGain();
|
|
|
|
source.connect(gain);
|
|
gain.connect(context.destination);
|
|
|
|
// Start the timeline with setValueAtTime(v0, t0).
|
|
let v0 = 0.25;
|
|
let t0 = 0;
|
|
// End value and time, for those that need it. The end time is less
|
|
// than the rendering duration so we can test that the final values of
|
|
// the automation (if any) are also correct.
|
|
let v1 = 100;
|
|
let t1 = renderDuration - 5 * renderQuantumSize / sampleRate;
|
|
|
|
gain.gain.setValueAtTime(v0, t0);
|
|
|
|
// Run the desired automation test. The test function returns a
|
|
// dictionary consisting of the following properties:
|
|
//
|
|
// |message| an informative message about the automation being
|
|
// tested. |errorThreshold| error threshold to determine if the test
|
|
// passes or not. |expectedValue| a function that compute the expected
|
|
// value at time |t|.
|
|
let test = testFunction(gain, v0, t0, v1, t1);
|
|
|
|
// Print an informative message about the test being run.
|
|
// testPassed("Initialize " + test.message + " with setValueAtTime(" +
|
|
// v0 + ", " + t0 + ").");
|
|
should(true, 'Initialize')
|
|
.message(
|
|
test.message + ' with setValueAtTime(' + v0 + ', ' + t0 + ')',
|
|
'');
|
|
|
|
let success = true;
|
|
|
|
// Max relative error found for this test. This is printed if the test
|
|
// fails so that setting the thresholds is easier.
|
|
let maxError = 0;
|
|
|
|
// For every rendering quantum (except the first), suspend the context
|
|
// so the we can inspect the value attribute and compare it with the
|
|
// expected value.
|
|
for (let k = 1; k < renderLoops; ++k) {
|
|
let time = k * renderQuantumSize / sampleRate;
|
|
context.suspend(time)
|
|
.then(function() {
|
|
// The context is supsended at time |time|, which is just before
|
|
// the rendering quantum starts. Thus, the value of the
|
|
// attribute is actually 1 frame before the current context
|
|
// time.
|
|
let sampleTime = context.currentTime - 1 / sampleRate;
|
|
|
|
// Compute the max relative error
|
|
let expected = test.expectedValue(sampleTime);
|
|
let relError =
|
|
Math.abs(expected - gain.gain.value) / Math.abs(expected);
|
|
maxError = Math.max(relError, maxError);
|
|
|
|
success =
|
|
should(
|
|
gain.gain.value,
|
|
test.message + ' at frame ' + (sampleRate * sampleTime))
|
|
.beCloseTo(
|
|
expected, {threshold: test.errorThreshold || 0});
|
|
})
|
|
.then(context.resume.bind(context));
|
|
}
|
|
|
|
source.start();
|
|
|
|
return context.startRendering().then(function(resultBuffer) {
|
|
// Just print a final pass (or fail) message.
|
|
should(success, 'Gain .value attribute for ' + test.message)
|
|
.message(
|
|
'correctly updated during automation',
|
|
'not correctly updated during automation; max error = ' +
|
|
maxError);
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|