Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<html>
<head>
<title>
audioparam-method-chaining.html
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webaudio/resources/audit-util.js"></script>
<script src="/webaudio/resources/audit.js"></script>
<script src="/webaudio/resources/audioparam-testing.js"></script>
</head>
<body>
<script id="layout-test-code">
let sampleRate = 8000;
// Create a dummy array for setValueCurveAtTime method.
let curveArray = new Float32Array([5.0, 6.0]);
// AudioNode dictionary with associated dummy arguments.
let methodDictionary = [
{name: 'setValueAtTime', args: [1.0, 0.0]},
{name: 'linearRampToValueAtTime', args: [2.0, 1.0]},
{name: 'exponentialRampToValueAtTime', args: [3.0, 2.0]},
{name: 'setTargetAtTime', args: [4.0, 2.0, 0.5]},
{name: 'setValueCurveAtTime', args: [curveArray, 5.0, 1.0]},
{name: 'cancelScheduledValues', args: [6.0]}
];
let audit = Audit.createTaskRunner();
// Task: testing entries from the dictionary.
audit.define('from-dictionary', (task, should) => {
let context = new AudioContext();
methodDictionary.forEach(function(method) {
let sourceParam = context.createGain().gain;
should(
sourceParam === sourceParam[method.name](...method.args),
'The return value of ' + sourceParam.constructor.name + '.' +
method.name + '()' +
' matches the source AudioParam')
.beEqualTo(true);
});
task.done();
});
// Task: test method chaining with invalid operation.
audit.define('invalid-operation', (task, should) => {
let context = new OfflineAudioContext(1, sampleRate, sampleRate);
let osc = context.createOscillator();
let amp1 = context.createGain();
let amp2 = context.createGain();
osc.connect(amp1);
osc.connect(amp2);
amp1.connect(context.destination);
amp2.connect(context.destination);
// The first operation fails with an exception, thus the second one
// should not have effect on the parameter value. Instead, it should
// maintain the default value of 1.0.
should(
function() {
amp1.gain.setValueAtTime(0.25, -1.0)
.linearRampToValueAtTime(2.0, 1.0);
},
'Calling setValueAtTime() with a negative end time')
.throw(RangeError);
// The first operation succeeds but the second fails due to zero target
// value for the exponential ramp. Thus only the first should have
// effect on the parameter value, setting the value to 0.5.
should(
function() {
amp2.gain.setValueAtTime(0.5, 0.0).exponentialRampToValueAtTime(
0.0, 1.0);
},
'Calling exponentialRampToValueAtTime() with a zero target value')
.throw(RangeError);
osc.start();
osc.stop(1.0);
context.startRendering()
.then(function(buffer) {
should(amp1.gain.value, 'The gain value of the first gain node')
.beEqualTo(1.0);
should(amp2.gain.value, 'The gain value of the second gain node')
.beEqualTo(0.5);
})
.then(() => task.done());
});
// Task: verify if the method chaining actually works. Create an arbitrary
// envelope and compare the result with the expected one created by JS
// code.
audit.define('verification', (task, should) => {
let context = new OfflineAudioContext(1, sampleRate * 4, sampleRate);
let constantBuffer = createConstantBuffer(context, 1, 1.0);
let source = context.createBufferSource();
source.buffer = constantBuffer;
source.loop = true;
let envelope = context.createGain();
source.connect(envelope);
envelope.connect(context.destination);
envelope.gain.setValueAtTime(0.0, 0.0)
.linearRampToValueAtTime(1.0, 1.0)
.exponentialRampToValueAtTime(0.5, 2.0)
.setTargetAtTime(0.001, 2.0, 0.5);
source.start();
context.startRendering()
.then(function(buffer) {
let expectedEnvelope =
createLinearRampArray(0.0, 1.0, 0.0, 1.0, sampleRate);
expectedEnvelope.push(...createExponentialRampArray(
1.0, 2.0, 1.0, 0.5, sampleRate));
expectedEnvelope.push(...createExponentialApproachArray(
2.0, 4.0, 0.5, 0.001, sampleRate, 0.5));
// There are slight differences between JS implementation of
// AudioParam envelope and the internal implementation. (i.e.
// double/float and rounding up) The error threshold is adjusted
// empirically through the local testing.
should(buffer.getChannelData(0), 'The rendered envelope')
.beCloseToArray(
expectedEnvelope, {absoluteThreshold: 4.0532e-6});
})
.then(() => task.done());
});
audit.run();
</script>
</body>
</html>