mirror of
https://github.com/servo/servo.git
synced 2025-09-01 02:28:21 +01:00
Update web-platform-tests to revision 5084587f6b05bf99ad09e7844be66dcc61070cdf
This commit is contained in:
parent
6d42d2f1e8
commit
7d1071a6a4
408 changed files with 8968 additions and 2608 deletions
|
@ -0,0 +1,117 @@
|
|||
// Test k-rate vs a-rate AudioParams.
|
||||
//
|
||||
// |options| describes how the testing of the AudioParam should be done:
|
||||
//
|
||||
// nodeName: name of the AudioNode to be tested
|
||||
// nodeOptions: options to be used in the AudioNode constructor
|
||||
//
|
||||
// prefix: Prefix for all output messages (to make them unique for
|
||||
// testharness)
|
||||
//
|
||||
// rateSettings: A vector of dictionaries specifying how to set the automation
|
||||
// rate(s):
|
||||
// name: Name of the AudioParam
|
||||
// value: The automation rate for the AudioParam given by |name|.
|
||||
//
|
||||
// automations: A vector of dictionaries specifying how to automate each
|
||||
// AudioParam:
|
||||
// name: Name of the AudioParam
|
||||
//
|
||||
// methods: A vector of dictionaries specifying the automation methods to
|
||||
// be used for testing:
|
||||
// name: Automation method to call
|
||||
// options: Arguments for the automation method
|
||||
//
|
||||
// Testing is somewhat rudimentary. We create two nodes of the same type. One
|
||||
// node uses the default automation rates for each AudioParam (expecting them to
|
||||
// be a-rate). The second node sets the automation rate of AudioParams to
|
||||
// "k-rate". The set is speciified by |options.rateSettings|.
|
||||
//
|
||||
// For both of these nodes, the same set of automation methods (given by
|
||||
// |options.automations|) is applied. A simple oscillator is connected to each
|
||||
// node which in turn are connected to different channels of an offline context.
|
||||
// Channel 0 is the k-rate node output; channel 1, the a-rate output; and
|
||||
// channel 3, the difference between the outputs.
|
||||
//
|
||||
// Success is declared if the difference signal is not exactly zero. This means
|
||||
// the the automations did different things, as expected.
|
||||
//
|
||||
// The promise from |startRendering| is returned.
|
||||
function doTest(context, should, options) {
|
||||
let merger = new ChannelMergerNode(
|
||||
context, {numberOfInputs: context.destination.numberOfChannels});
|
||||
merger.connect(context.destination);
|
||||
|
||||
let src = new OscillatorNode(context);
|
||||
let kRateNode = new window[options.nodeName](context, options.nodeOptions);
|
||||
let aRateNode = new window[options.nodeName](context, options.nodeOptions);
|
||||
let inverter = new GainNode(context, {gain: -1});
|
||||
|
||||
// Set kRateNode filter to use k-rate params.
|
||||
options.rateSettings.forEach(setting => {
|
||||
kRateNode[setting.name].automationRate = setting.value;
|
||||
// Mostly for documentation in the output. These should always
|
||||
// pass.
|
||||
should(
|
||||
kRateNode[setting.name].automationRate,
|
||||
`${options.prefix}: Setting ${
|
||||
setting.name
|
||||
}.automationRate to "${setting.value}"`)
|
||||
.beEqualTo(setting.value);
|
||||
});
|
||||
|
||||
// Run through all automations for each node separately. (Mostly to keep
|
||||
// output of automations together.)
|
||||
options.automations.forEach(param => {
|
||||
param.methods.forEach(method => {
|
||||
// Most for documentation in the output. These should never throw.
|
||||
let message = `${param.name}.${method.name}(${method.options})`
|
||||
should(() => {
|
||||
kRateNode[param.name][method.name](...method.options);
|
||||
}, options.prefix + ': k-rate node: ' + message).notThrow();
|
||||
});
|
||||
});
|
||||
options.automations.forEach(param => {
|
||||
param.methods.forEach(method => {
|
||||
// Most for documentation in the output. These should never throw.
|
||||
let message = `${param.name}.${method.name}(${method.options})`
|
||||
should(() => {
|
||||
aRateNode[param.name][method.name](...method.options);
|
||||
}, options.prefix + ': a-rate node:' + message).notThrow();
|
||||
});
|
||||
});
|
||||
|
||||
// The k-rate result is channel 0, and the a-rate result is channel 1.
|
||||
src.connect(kRateNode).connect(merger, 0, 0);
|
||||
src.connect(aRateNode).connect(merger, 0, 1);
|
||||
|
||||
// Compute the difference between the a-rate and k-rate results and send
|
||||
// that to channel 2.
|
||||
kRateNode.connect(merger, 0, 2);
|
||||
aRateNode.connect(inverter).connect(merger, 0, 2);
|
||||
|
||||
src.start();
|
||||
return context.startRendering().then(renderedBuffer => {
|
||||
let kRateOutput = renderedBuffer.getChannelData(0);
|
||||
let aRateOutput = renderedBuffer.getChannelData(1);
|
||||
let diff = renderedBuffer.getChannelData(2);
|
||||
|
||||
// Some informative messages to print out values of the k-rate and
|
||||
// a-rate outputs. These should always pass.
|
||||
should(
|
||||
kRateOutput, `${options.prefix}: Output of k-rate ${options.nodeName}`)
|
||||
.beEqualToArray(kRateOutput);
|
||||
should(
|
||||
aRateOutput, `${options.prefix}: Output of a-rate ${options.nodeName}`)
|
||||
.beEqualToArray(aRateOutput);
|
||||
|
||||
// The real test. If k-rate AudioParam is working correctly, the
|
||||
// k-rate result MUST differ from the a-rate result.
|
||||
should(
|
||||
diff,
|
||||
`${
|
||||
options.prefix
|
||||
}: Difference between a-rate and k-rate ${options.nodeName}`)
|
||||
.notBeConstantValueOf(0);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>AudioParam.automationRate tests</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>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
// For each node that has an AudioParam, verify that the default
|
||||
// |automationRate| has the expected value and that we can change it or
|
||||
// throw an error if it can't be changed.
|
||||
|
||||
// Any valid sample rate is fine; we don't actually render anything in the
|
||||
// tests.
|
||||
let sampleRate = 8000;
|
||||
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
// Array of tests. Each test is a dictonary consisting of the name of the
|
||||
// node and an array specifying the AudioParam's of the node. This array
|
||||
// in turn gives the name of the AudioParam, the default value for the
|
||||
// |automationRate|, and whether it is fixed (isFixed).
|
||||
const tests = [
|
||||
{
|
||||
nodeName: 'AudioBufferSourceNode',
|
||||
audioParams: [
|
||||
{name: 'detune', defaultRate: 'k-rate', isFixed: true},
|
||||
{name: 'playbackRate', defaultRate: 'k-rate', isFixed: true}
|
||||
]
|
||||
},
|
||||
{
|
||||
nodeName: 'BiquadFilterNode',
|
||||
audioParams: [
|
||||
{name: 'frequency', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'detune', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'Q', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'gain', defaultRate: 'a-rate', isFixed: false},
|
||||
]
|
||||
},
|
||||
{
|
||||
nodeName: 'ConstantSourceNode',
|
||||
audioParams: [{name: 'offset', defaultRate: 'a-rate', isFixed: false}]
|
||||
},
|
||||
{
|
||||
nodeName: 'DelayNode',
|
||||
audioParams:
|
||||
[{name: 'delayTime', defaultRate: 'a-rate', isFixed: false}]
|
||||
},
|
||||
{
|
||||
nodeName: 'DynamicsCompressorNode',
|
||||
audioParams: [
|
||||
{name: 'threshold', defaultRate: 'k-rate', isFixed: true},
|
||||
{name: 'knee', defaultRate: 'k-rate', isFixed: true},
|
||||
{name: 'ratio', defaultRate: 'k-rate', isFixed: true},
|
||||
{name: 'attack', defaultRate: 'k-rate', isFixed: true},
|
||||
{name: 'release', defaultRate: 'k-rate', isFixed: true}
|
||||
]
|
||||
},
|
||||
{
|
||||
nodeName: 'GainNode',
|
||||
audioParams: [{name: 'gain', defaultRate: 'a-rate', isFixed: false}]
|
||||
},
|
||||
{
|
||||
nodeName: 'OscillatorNode',
|
||||
audioParams: [
|
||||
{name: 'frequency', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'detune', defaultRate: 'a-rate', isFixed: false}
|
||||
]
|
||||
},
|
||||
{
|
||||
nodeName: 'PannerNode',
|
||||
audioParams: [
|
||||
{name: 'positionX', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'positionY', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'positionZ', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'orientationX', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'orientationY', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'orientationZ', defaultRate: 'a-rate', isFixed: false},
|
||||
]
|
||||
},
|
||||
{
|
||||
nodeName: 'StereoPannerNode',
|
||||
audioParams: [{name: 'pan', defaultRate: 'a-rate', isFixed: false}]
|
||||
},
|
||||
];
|
||||
|
||||
tests.forEach(test => {
|
||||
// Define a separate test for each test entry.
|
||||
audit.define(test.nodeName, (task, should) => {
|
||||
let context = new OfflineAudioContext(
|
||||
{length: sampleRate, sampleRate: sampleRate});
|
||||
// Construct the node and test each AudioParam of the node.
|
||||
let node = new window[test.nodeName](context);
|
||||
test.audioParams.forEach(param => {
|
||||
testAudioParam(
|
||||
should, {nodeName: test.nodeName, node: node, param: param});
|
||||
});
|
||||
|
||||
task.done();
|
||||
});
|
||||
});
|
||||
|
||||
// AudioListener needs it's own special test since it's not a node.
|
||||
audit.define('AudioListener', (task, should) => {
|
||||
let context = new OfflineAudioContext(
|
||||
{length: sampleRate, sampleRate: sampleRate});
|
||||
|
||||
[{name: 'positionX', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'positionY', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'positionZ', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'forwardX', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'forwardY', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'forwardZ', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'upX', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'upY', defaultRate: 'a-rate', isFixed: false},
|
||||
{name: 'upZ', defaultRate: 'a-rate', isFixed: false},
|
||||
].forEach(param => {
|
||||
testAudioParam(should, {
|
||||
nodeName: 'AudioListener',
|
||||
node: context.listener,
|
||||
param: param
|
||||
});
|
||||
});
|
||||
task.done();
|
||||
});
|
||||
|
||||
audit.run();
|
||||
|
||||
function testAudioParam(should, options) {
|
||||
let param = options.param;
|
||||
let audioParam = options.node[param.name];
|
||||
let defaultRate = param.defaultRate;
|
||||
|
||||
// Verify that the default value is correct.
|
||||
should(
|
||||
audioParam.automationRate,
|
||||
`Default ${options.nodeName}.${param.name}.automationRate`)
|
||||
.beEqualTo(defaultRate);
|
||||
|
||||
// Try setting the rate to a different rate. If the |automationRate|
|
||||
// is fixed, expect an error. Otherwise, expect no error and expect
|
||||
// the value is changed to the new value.
|
||||
let newRate = defaultRate === 'a-rate' ? 'k-rate' : 'a-rate';
|
||||
let setMessage = `Set ${
|
||||
options.nodeName
|
||||
}.${param.name}.automationRate to "${newRate}"`
|
||||
|
||||
if (param.isFixed) {
|
||||
should(() => audioParam.automationRate = newRate, setMessage)
|
||||
.throw('InvalidStateError');
|
||||
}
|
||||
else {
|
||||
should(() => audioParam.automationRate = newRate, setMessage)
|
||||
.notThrow();
|
||||
should(
|
||||
audioParam.automationRate,
|
||||
`${options.nodeName}.${param.name}.automationRate`)
|
||||
.beEqualTo(newRate);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,79 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParam of AudioWorkletNode</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>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
const audit = Audit.createTaskRunner();
|
||||
|
||||
// Use the worklet gain node to test k-rate parameters.
|
||||
const filePath =
|
||||
'../the-audioworklet-interface/processors/gain-processor.js';
|
||||
|
||||
// Context for testing
|
||||
let context;
|
||||
|
||||
audit.define('Create Test Worklet', (task, should) => {
|
||||
|
||||
// Arbitrary sample rate and duration.
|
||||
const sampleRate = 8000;
|
||||
|
||||
// Only new a few render quanta to verify things are working.
|
||||
const testDuration = 4 * 128 / sampleRate;
|
||||
|
||||
context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
should(
|
||||
context.audioWorklet.addModule(filePath),
|
||||
'Construction of AudioWorklet')
|
||||
.beResolved()
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.define('AudioWorklet k-rate AudioParam', (task, should) => {
|
||||
let src = new ConstantSourceNode(context);
|
||||
|
||||
let kRateNode = new AudioWorkletNode(context, 'gain');
|
||||
|
||||
src.connect(kRateNode).connect(context.destination);
|
||||
|
||||
let kRateParam = kRateNode.parameters.get('gain');
|
||||
kRateParam.automationRate = 'k-rate';
|
||||
|
||||
// Automate the gain
|
||||
kRateParam.setValueAtTime(0, 0);
|
||||
kRateParam.linearRampToValueAtTime(
|
||||
10, context.length / context.sampleRate);
|
||||
|
||||
src.start();
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
let output = audioBuffer.getChannelData(0);
|
||||
|
||||
// Verify that the output from the worklet is step-wise
|
||||
// constant.
|
||||
for (let k = 0; k < output.length; k += 128) {
|
||||
should(
|
||||
output.slice(k, k + 128),
|
||||
` k-rate output [${k}: ${k + 127}]`)
|
||||
.beConstantValueOf(output[k]);
|
||||
}
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,111 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParams of BiquadFilterNode</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="automation-rate-testing.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
audit.define(
|
||||
{task: 'BiquadFilter-0', label: 'Biquad k-rate AudioParams (all)'},
|
||||
(task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
let testDuration = 1;
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
doTest(context, should, {
|
||||
nodeName: 'BiquadFilterNode',
|
||||
nodeOptions: {type: 'lowpass'},
|
||||
prefix: 'All k-rate params',
|
||||
// Set all AudioParams to k-rate
|
||||
rateSettings: [
|
||||
{name: 'Q', value: 'k-rate'},
|
||||
{name: 'detune', value: 'k-rate'},
|
||||
{name: 'frequency', value: 'k-rate'},
|
||||
{name: 'gain', value: 'k-rate'},
|
||||
],
|
||||
// Automate just the frequency
|
||||
automations: [{
|
||||
name: 'frequency',
|
||||
methods: [
|
||||
{name: 'setValueAtTime', options: [350, 0]}, {
|
||||
name: 'linearRampToValueAtTime',
|
||||
options: [0, testDuration]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}).then(() => task.done());
|
||||
});
|
||||
|
||||
// Define a test where we verify that a k-rate audio param produces
|
||||
// different results from an a-rate audio param for each of the audio
|
||||
// params of a biquad.
|
||||
//
|
||||
// Each entry gives the name of the AudioParam, an initial value to be
|
||||
// used with setValueAtTime, and a final value to be used with
|
||||
// linearRampToValueAtTime. (See |doTest| for details as well.)
|
||||
|
||||
[{name: 'Q',
|
||||
initial: 1,
|
||||
final: 10
|
||||
},
|
||||
{name: 'detune',
|
||||
initial: 0,
|
||||
final: 1200
|
||||
},
|
||||
{name: 'frequency',
|
||||
initial: 350,
|
||||
final: 0
|
||||
},
|
||||
{name: 'gain',
|
||||
initial: 10,
|
||||
final: 0
|
||||
}].forEach(paramProperty => {
|
||||
audit.define('Biquad k-rate ' + paramProperty.name, (task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
let testDuration = 1;
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
doTest(context, should, {
|
||||
nodeName: 'BiquadFilterNode',
|
||||
nodeOptions: {type: 'peaking', Q: 1, gain: 10},
|
||||
prefix: `k-rate ${paramProperty.name}`,
|
||||
// Just set the frequency to k-rate
|
||||
rateSettings: [
|
||||
{name: paramProperty.name, value: 'k-rate'},
|
||||
],
|
||||
// Automate just the given AudioParam
|
||||
automations: [{
|
||||
name: paramProperty.name,
|
||||
methods: [
|
||||
{name: 'setValueAtTime', options: [paramProperty.initial, 0]}, {
|
||||
name: 'linearRampToValueAtTime',
|
||||
options: [paramProperty.final, testDuration]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}).then(() => task.done());
|
||||
});
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,81 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParam of ConstantSourceNode</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>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
audit.define('ConstantSource k-rate offset', (task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
|
||||
// Only new a few render quanta to verify things are working.
|
||||
let testDuration = 4 * 128 / sampleRate;
|
||||
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
let merger = new ChannelMergerNode(
|
||||
context, {numberOfInputs: context.numberOfChannels});
|
||||
merger.connect(context.destination);
|
||||
let inverter = new GainNode(context, {gain: -1});
|
||||
inverter.connect(merger, 0, 2);
|
||||
|
||||
let kRateNode = new ConstantSourceNode(context);
|
||||
let aRateNode = new ConstantSourceNode(context);
|
||||
|
||||
kRateNode.connect(merger, 0, 0);
|
||||
aRateNode.connect(merger, 0, 1);
|
||||
|
||||
kRateNode.connect(merger, 0, 2);
|
||||
aRateNode.connect(inverter);
|
||||
|
||||
// Set the rate
|
||||
kRateNode.offset.automationRate = 'k-rate';
|
||||
|
||||
// Automate the offset
|
||||
kRateNode.offset.setValueAtTime(0, 0);
|
||||
kRateNode.offset.linearRampToValueAtTime(10, testDuration);
|
||||
|
||||
aRateNode.offset.setValueAtTime(0, 0);
|
||||
aRateNode.offset.linearRampToValueAtTime(10, testDuration);
|
||||
|
||||
kRateNode.start();
|
||||
aRateNode.start();
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
let kRateOut = audioBuffer.getChannelData(0);
|
||||
let aRateOut = audioBuffer.getChannelData(1);
|
||||
let diff = audioBuffer.getChannelData(2);
|
||||
|
||||
// Verify that the outputs are different.
|
||||
should(diff, 'Difference between a-rate and k-rate outputs')
|
||||
.notBeConstantValueOf(0);
|
||||
|
||||
// Verify that the constant source node output is step-wise
|
||||
// constant.
|
||||
for (let k = 0; k < kRateOut.length; k += 128) {
|
||||
should(
|
||||
kRateOut.slice(k, k + 128),
|
||||
`k-rate output [${k}: ${k + 127}]`)
|
||||
.beConstantValueOf(kRateOut[k]);
|
||||
}
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParam of DelayNode</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="automation-rate-testing.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
audit.define('Test k-rate DelayNode', (task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
let testDuration = 1;
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
|
||||
doTest(context, should, {
|
||||
nodeName: 'DelayNode',
|
||||
nodeOptions: null,
|
||||
prefix: 'DelayNode',
|
||||
// Set all AudioParams to k-rate
|
||||
rateSettings: [{name: 'delayTime', value: 'k-rate'}],
|
||||
// Automate just the frequency
|
||||
automations: [{
|
||||
name: 'delayTime',
|
||||
methods: [
|
||||
{name: 'setValueAtTime', options: [0, 0]}, {
|
||||
name: 'linearRampToValueAtTime',
|
||||
options: [.5, testDuration]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}).then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,47 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParam of GainNode</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="automation-rate-testing.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
audit.define('Test k-rate GainNode', (task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
let testDuration = 1;
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
|
||||
doTest(context, should, {
|
||||
nodeName: 'GainNode',
|
||||
nodeOptions: null,
|
||||
prefix: 'GainNode',
|
||||
// Set AudioParam to k-rate
|
||||
rateSettings: [{name: 'gain', value: 'k-rate'}],
|
||||
// Automate
|
||||
automations: [{
|
||||
name: 'gain',
|
||||
methods: [
|
||||
{name: 'setValueAtTime', options: [1, 0]},
|
||||
{name: 'linearRampToValueAtTime', options: [0, testDuration]}
|
||||
]
|
||||
}]
|
||||
}).then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,88 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParams of OscillatorNode</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>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
|
||||
// Only new a few render quanta to verify things are working.
|
||||
let testDuration = 4 * 128 / sampleRate;
|
||||
|
||||
[{name: 'detune', initial: 0, final: 1200}, {
|
||||
name: 'frequency',
|
||||
initial: 440,
|
||||
final: sampleRate / 2
|
||||
}].forEach(paramProperty => {
|
||||
audit.define(
|
||||
'Oscillator k-rate ' + paramProperty.name, (task, should) => {
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
let merger = new ChannelMergerNode(
|
||||
context, {numberOfInputs: context.numberOfChannels});
|
||||
merger.connect(context.destination);
|
||||
let inverter = new GainNode(context, {gain: -1});
|
||||
inverter.connect(merger, 0, 2);
|
||||
|
||||
let kRateNode = new OscillatorNode(context);
|
||||
let aRateNode = new OscillatorNode(context);
|
||||
|
||||
kRateNode.connect(merger, 0, 0);
|
||||
aRateNode.connect(merger, 0, 1);
|
||||
|
||||
kRateNode.connect(merger, 0, 2);
|
||||
aRateNode.connect(inverter);
|
||||
|
||||
// Set the rate
|
||||
kRateNode[paramProperty.name].automationRate = 'k-rate';
|
||||
|
||||
// Automate the offset
|
||||
kRateNode[paramProperty.name].setValueAtTime(
|
||||
paramProperty.initial, 0);
|
||||
kRateNode[paramProperty.name].linearRampToValueAtTime(
|
||||
paramProperty.final, testDuration);
|
||||
|
||||
aRateNode[paramProperty.name].setValueAtTime(
|
||||
paramProperty.initial, 0);
|
||||
aRateNode[paramProperty.name].linearRampToValueAtTime(
|
||||
paramProperty.final, testDuration);
|
||||
|
||||
kRateNode.start();
|
||||
aRateNode.start();
|
||||
|
||||
context.startRendering()
|
||||
.then(audioBuffer => {
|
||||
let kRateOut = audioBuffer.getChannelData(0);
|
||||
let aRateOut = audioBuffer.getChannelData(1);
|
||||
let diff = audioBuffer.getChannelData(2);
|
||||
|
||||
// Verify that the outputs are different.
|
||||
should(
|
||||
diff,
|
||||
'k-rate ' + paramProperty.name +
|
||||
': Difference between a-rate and k-rate outputs')
|
||||
.notBeConstantValueOf(0);
|
||||
|
||||
})
|
||||
.then(() => task.done());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,172 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParams of PannerNode</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="automation-rate-testing.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
// Define a test where we verify that a k-rate audio param produces
|
||||
// different results from an a-rate audio param for each of the audio
|
||||
// params of a biquad.
|
||||
//
|
||||
// Each entry gives the name of the AudioParam, an initial value to be
|
||||
// used with setValueAtTime, and a final value to be used with
|
||||
// linearRampToValueAtTime. (See |doTest| for details as well.)
|
||||
|
||||
[{name: 'positionX', initial: 0, final: 1000},
|
||||
{name: 'positionY', initial: 0, final: 1000},
|
||||
{name: 'orientationX', initial: .1, final: 1000},
|
||||
{name: 'orientationY', initial: .1, final: 1000},
|
||||
{name: 'orientationZ', initial: .1, final: 1000},
|
||||
].forEach(paramProperty => {
|
||||
audit.define('Panner k-rate ' + paramProperty.name, (task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
let testDuration = 1;
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
doTest(context, should, {
|
||||
nodeName: 'PannerNode',
|
||||
// Make the source directional so orientation matters, and set some
|
||||
// defaults for the position and orientation so that we're not on an
|
||||
// axis where the azimuth and elevation might be constant when
|
||||
// moving one of the AudioParams.
|
||||
nodeOptions: {
|
||||
distanceModel: 'inverse',
|
||||
coneOuterAngle: 360,
|
||||
coneInnerAngle: 10,
|
||||
positionX: 10,
|
||||
positionY: 10,
|
||||
positionZ: 10,
|
||||
orientationX: 1,
|
||||
orientationY: 1,
|
||||
orientationZ: 1
|
||||
},
|
||||
prefix: `k-rate ${paramProperty.name}`,
|
||||
// Just set the frequency to k-rate
|
||||
rateSettings: [
|
||||
{name: paramProperty.name, value: 'k-rate'},
|
||||
],
|
||||
// Automate just the given AudioParam
|
||||
automations: [{
|
||||
name: paramProperty.name,
|
||||
methods: [
|
||||
{name: 'setValueAtTime', options: [paramProperty.initial, 0]}, {
|
||||
name: 'linearRampToValueAtTime',
|
||||
options: [paramProperty.final, testDuration]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}).then(() => task.done());
|
||||
});
|
||||
});
|
||||
|
||||
// Test k-rate automation of the listener. The intial and final
|
||||
// automation values are pretty arbitrary, except that they should be such
|
||||
// that the panner and listener produces non-constant output.
|
||||
[{name: 'positionX', initial: [1, 0], final: [1000, 1]},
|
||||
{name: 'positionY', initial: [1, 0], final: [1000, 1]},
|
||||
{name: 'positionZ', initial: [1, 0], final: [1000, 1]},
|
||||
{name: 'forwardX', initial: [-1, 0], final: [1, 1]},
|
||||
{name: 'forwardY', initial: [-1, 0], final: [1, 1]},
|
||||
{name: 'forwardZ', initial: [-1, 0], final: [1, 1]},
|
||||
{name: 'upX', initial: [-1, 0], final: [1000, 1]},
|
||||
{name: 'upY', initial: [-1, 0], final: [1000, 1]},
|
||||
{name: 'upZ', initial: [-1, 0], final: [1000, 1]},
|
||||
].forEach(paramProperty => {
|
||||
audit.define(
|
||||
'Listener k-rate ' + paramProperty.name, (task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
let testDuration = 5 * 128 / sampleRate;
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 1,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
doListenerTest(context, should, {
|
||||
param: paramProperty.name,
|
||||
initial: paramProperty.initial,
|
||||
final: paramProperty.final
|
||||
}).then(() => task.done());
|
||||
});
|
||||
});
|
||||
|
||||
audit.run();
|
||||
|
||||
function doListenerTest(context, should, options) {
|
||||
let src = new ConstantSourceNode(context);
|
||||
let panner = new PannerNode(context, {
|
||||
distanceModel: 'inverse',
|
||||
coneOuterAngle: 360,
|
||||
coneInnerAngle: 10,
|
||||
positionX: 10,
|
||||
positionY: 10,
|
||||
positionZ: 10,
|
||||
orientationX: 1,
|
||||
orientationY: 1,
|
||||
orientationZ: 1
|
||||
});
|
||||
|
||||
src.connect(panner).connect(context.destination);
|
||||
|
||||
src.start();
|
||||
|
||||
let listener = context.listener;
|
||||
|
||||
// Set listener properties to "random" values so that motion on one of
|
||||
// the attributes actually changes things relative to the panner
|
||||
// location.
|
||||
listener.positionX.value = -1;
|
||||
listener.positionY.value = 1;
|
||||
listener.positionZ.value = -1;
|
||||
listener.forwardX.value = -1;
|
||||
listener.forwardY.value = 1;
|
||||
listener.forwardZ.value = -1;
|
||||
listener.upX.value = 1;
|
||||
listener.upY.value = 1;
|
||||
listener.upZ.value = 1;
|
||||
|
||||
let audioParam = listener[options.param];
|
||||
audioParam.automationRate = 'k-rate';
|
||||
|
||||
let prefix = `Listener ${options.param}`;
|
||||
should(audioParam.automationRate, prefix + '.automationRate')
|
||||
.beEqualTo('k-rate');
|
||||
should(() => {
|
||||
audioParam.setValueAtTime(...options.initial);
|
||||
}, prefix + `.setValueAtTime(${options.initial})`).notThrow();
|
||||
should(() => {
|
||||
audioParam.linearRampToValueAtTime(...options.final);
|
||||
}, prefix + `.linearRampToValueAtTime(${options.final})`).notThrow();
|
||||
|
||||
return context.startRendering().then(renderedBuffer => {
|
||||
let prefix = `Listener k-rate ${options.param}: `;
|
||||
let output = renderedBuffer.getChannelData(0);
|
||||
// Sanity check that the output isn't constant.
|
||||
should(output, prefix + `Output`).notBeConstantValueOf(output[0]);
|
||||
|
||||
// Verify that the output is constant over each render quantum
|
||||
for (let k = 0; k < output.length; k += 128) {
|
||||
should(
|
||||
output.slice(k, k + 128), prefix + `Output [${k}, ${k + 127}]`)
|
||||
.beConstantValueOf(output[k]);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,48 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test k-rate AudioParam of StereoPannerNode</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="automation-rate-testing.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
let audit = Audit.createTaskRunner();
|
||||
|
||||
audit.define('Test k-rate StereoPannerNode', (task, should) => {
|
||||
// Arbitrary sample rate and duration.
|
||||
let sampleRate = 8000;
|
||||
let testDuration = 1;
|
||||
let context = new OfflineAudioContext({
|
||||
numberOfChannels: 3,
|
||||
sampleRate: sampleRate,
|
||||
length: testDuration * sampleRate
|
||||
});
|
||||
|
||||
doTest(context, should, {
|
||||
nodeName: 'StereoPannerNode',
|
||||
nodeOptions: null,
|
||||
prefix: 'StereoPannerNode',
|
||||
// Set all AudioParams to k-rate.
|
||||
rateSettings: [{name: 'pan', value: 'k-rate'}],
|
||||
// Automate just the frequency.
|
||||
automations: [{
|
||||
name: 'pan',
|
||||
methods: [
|
||||
{name: 'setValueAtTime', options: [0, 0]}, {
|
||||
name: 'linearRampToValueAtTime',
|
||||
options: [.5, testDuration]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}).then(() => task.done());
|
||||
});
|
||||
|
||||
audit.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue