blob: ea304a8392931a81ff471646c33dd20969db9c83 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>
Test Processing Of AudioParams of Disconnected AudioNodes
</title>
<script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../resources/audit.js"></script>
</head>
<body>
<script id="layout-test-code">
// Arbitrary sample rate.
let sampleRate = 8000;
// Arbitrary number of frames for the test, except it must be greater than
// |automationEndFrame|.
let renderFrames = 1024;
// The linear ramp automation ends at this frame. Arbitrary, except it
// must be strictly less than the render length.
let automationEndFrame = 128;
let audit = Audit.createTaskRunner();
// There should be a test for every single node which has an AudioParam.
// Source nodes are not included in this because the AudioParams for the
// source nodes only process when the node has been started.
audit.define('BiquadFilterNode', async (task, should) => {
let nodeName = 'BiquadFilterNode'
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'Q',
initialValue: 2,
rampFinalValue: 5
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'detune',
initialValue: 1,
rampFinalValue: 0.5
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'frequency',
initialValue: 1000,
rampFinalValue: 100
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'gain',
initialValue: -3,
rampFinalValue: 3
});
task.done();
});
audit.define('DelayNode', (task, should) => {
testParamAutomation(should, {
nodeName: 'DelayNode',
paramName: 'delayTime',
initialValue: 0.25,
rampFinalValue: 0.5
}).then(() => task.done());
});
audit.define('DynamicsCompressorNode', async (task, should) => {
let nodeName = 'DynamicsCompressorNode';
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'attack',
initialValue: 0.1,
rampFinalValue: 0.5
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'knee',
initialValue: 0,
rampFinalValue: 25
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'ratio',
initialValue: 1,
rampFinalValue: 15
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'release',
initialValue: 0,
rampFinalValue: 0.75
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'threshold',
initialValue: -50,
rampFinalValue: -10
});
task.done();
});
audit.define('GainNode', (task, should) => {
testParamAutomation(should, {
nodeName: 'GainNode',
paramName: 'gain',
initialValue: 1,
rampFinalValue: 0.5
}).then(() => task.done());
});
audit.define('PannerNode', async (task, should) => {
let nodeName = 'PannerNode';
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'positionX',
initialValue: 0.1,
rampFinalValue: 0.5
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'positionY',
initialValue: 2,
rampFinalValue: 30
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'positionZ',
initialValue: 1,
rampFinalValue: 15
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'orientationX',
initialValue: 0.1,
rampFinalValue: 0.5
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'orientationY',
initialValue: 2,
rampFinalValue: 30
});
await testParamAutomation(should, {
nodeName: nodeName,
paramName: 'orientationZ',
initialValue: 1,
rampFinalValue: 15
});
task.done();
});
audit.define('StereoPannerNode', (task, should) => {
testParamAutomation(should, {
nodeName: 'StereoPannerNode',
paramName: 'pan',
initialValue: 1,
rampFinalValue: 0.5
}).then(() => task.done());
});
audit.define('AudioListener', async (task, should) => {
await testAudioListener(should, {
paramName: 'positionX',
initialValue: 1,
rampFinalValue: 100
});
await testAudioListener(should, {
paramName: 'positionY',
initialValue: 1,
rampFinalValue: 200
});
await testAudioListener(should, {
paramName: 'positionZ',
initialValue: 1,
rampFinalValue: 300
});
await testAudioListener(should, {
paramName: 'forwardX',
initialValue: 1,
rampFinalValue: -100
});
await testAudioListener(should, {
paramName: 'forwardY',
initialValue: 1,
rampFinalValue: -200
});
await testAudioListener(should, {
paramName: 'forwardZ',
initialValue: 1,
rampFinalValue: -300
});
await testAudioListener(should, {
paramName: 'upX',
initialValue: 1,
rampFinalValue: 99
});
await testAudioListener(should, {
paramName: 'upY',
initialValue: 1,
rampFinalValue: 42
});
await testAudioListener(should, {
paramName: 'upZ',
initialValue: 1,
rampFinalValue: 137
});
task.done();
});
// Run test of automation processing. |options| is a dictionary that
// describes the node to test, the AudioParams to be tested and the values
// for the AudioParam. The members of the dictionary are:
//
// nodeName - name of the node (constructor name)
// paramName - name of the AudioParam to be tested
// initialValue - starting value for linear ramp
// rampFinalValue - finale value for linear ramp
//
// The test is considered to have succeeded if the |.value| of the
// AudioParam is the final value.
//
// A simple graph is created containing the node to be tested, connected
// to the destination. A linear ramp automation is scheduled for the
// specified AudioParam, starting and ending at the values given.
//
// Processing is started and after some number of frames, the |.value| of
// the AudioParam is obtained and compared against the final value. These
// should match exactly.
function testParamAutomation(should, options) {
let context = new OfflineAudioContext(1, renderFrames, sampleRate);
// Create the node to be tested
let node = new window[options.nodeName](context);
node.connect(context.destination);
// A linear ramp starting at frame 0 to frame |automationEndFrame| is
// used for the test. This value is fairly arbitrary, but it should be
// less than the total render frames.
node[options.paramName].setValueAtTime(options.initialValue, 0);
node[options.paramName].linearRampToValueAtTime(
options.rampFinalValue, automationEndFrame / context.sampleRate);
return context.startRendering().then(function(resultBuffer) {
// Sanity check: the given ramp final value must not be the default
// value, otherwise we can't easily tell if the automation was
// actually run.
should(
options.rampFinalValue,
options.nodeName + '.' + options.paramName + ' ramp final value')
.notBeEqualTo(node[options.paramName].defaultValue);
// The actual AudioParam value should be the rampe final value.
should(
node[options.paramName].value,
options.nodeName + '.' + options.paramName + '.value')
.beEqualTo(options.rampFinalValue);
});
}
function testAudioListener(should, options) {
let context = new OfflineAudioContext(1, renderFrames, sampleRate);
// Create the node to be tested
let node = new PannerNode(context);
node.connect(context.destination);
// A linear ramp starting at frame 0 to frame |automationEndFrame| is
// used for the test. This value is fairly arbitrary, but it should be
// less than the total render frames.
context.listener[options.paramName].setValueAtTime(
options.initialValue, 0);
context.listener[options.paramName].linearRampToValueAtTime(
options.rampFinalValue, automationEndFrame / context.sampleRate);
return context.startRendering().then(function(resultBuffer) {
// Sanity check: the given ramp final value must not be the default
// value, otherwise we can't easily tell if the automation was
// actually run.
should(
options.rampFinalValue,
'AudioListener.' + options.paramName + ' ramp final value')
.notBeEqualTo(context.listener[options.paramName].defaultValue);
// The actual AudioParam value should be the rampe final value.
should(
context.listener[options.paramName].value,
'AudioListener.' + options.paramName + '.value')
.beEqualTo(options.rampFinalValue);
});
}
audit.run();
</script>
</body>
</html>