blob: 730f03e5619577abf98c30b5566cddeeccf31551 [file] [log] [blame]
<!doctype html>
<html>
<head>
<title>k-rate AudioParams with Inputs</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();
// Must be power of two to eliminate round-off
const sampleRate = 8192;
// Arbitrary duration that doesn't need to be too long to verify k-rate
// automations. Probably should be at least a few render quanta.
const testDuration = 8 * RENDER_QUANTUM_FRAMES / sampleRate;
// Test k-rate GainNode.gain is k-rate
audit.define(
{label: 'Gain', description: 'k-rate GainNode.gain'},
(task, should) => {
let context = new OfflineAudioContext({
numberOfChannels: 2,
sampleRate: sampleRate,
length: testDuration * sampleRate
});
let merger = new ChannelMergerNode(
context, {numberOfInputs: context.destination.channelCount});
merger.connect(context.destination);
let src = new ConstantSourceNode(context);
createTestSubGraph(context, src, merger, 'GainNode', 'gain');
src.start();
context.startRendering()
.then(buffer => {
let actual = buffer.getChannelData(0);
let expected = buffer.getChannelData(1);
for (let k = 0; k < actual.length;
k += RENDER_QUANTUM_FRAMES) {
should(
actual.slice(k, k + RENDER_QUANTUM_FRAMES),
`gain[${k}:${k + RENDER_QUANTUM_FRAMES}]`)
.beConstantValueOf(expected[k]);
}
})
.then(() => task.done());
});
// Test k-rate StereoPannerNode.pan is k-rate
audit.define(
{label: 'StereoPanner', description: 'k-rate StereoPannerNode.pan'},
(task, should) => {
let context = new OfflineAudioContext({
numberOfChannels: 2,
sampleRate: sampleRate,
length: testDuration * sampleRate
});
let merger = new ChannelMergerNode(
context, {numberOfInputs: context.destination.channelCount});
merger.connect(context.destination);
let src = new ConstantSourceNode(context);
createTestSubGraph(
context, src, merger, 'StereoPannerNode', 'pan', {
testModSetup: node => {
node.offset.setValueAtTime(-1, 0);
node.offset.linearRampToValueAtTime(1, testDuration);
}
});
src.start();
context.startRendering()
.then(buffer => {
let actual = buffer.getChannelData(0);
let expected = buffer.getChannelData(1);
for (let k = 0; k < actual.length; k += 128) {
should(actual.slice(k, k + 128), `pan[${k}:${k + 128}]`)
.beConstantValueOf(expected[k]);
}
})
.then(() => task.done());
});
audit.run();
function createTestSubGraph(
context, src, merger, nodeName, paramName, options) {
// The test node which has its AudioParam set up for k-rate autmoations.
let tstNode = new window[nodeName](context);
if (options && options.setups) {
options.setups(tstNode);
}
tstNode[paramName].automationRate = 'k-rate';
// Modulating signal for the test node. Just a linear ramp. This is
// connected to the AudioParam of the tstNode.
let tstMod = new ConstantSourceNode(context);
if (options && options.testModSetup) {
options.testModSetup(tstMod);
} else {
tstMod.offset.linearRampToValueAtTime(context.length, testDuration);
}
tstMod.connect(tstNode[paramName]);
src.connect(tstNode).connect(merger, 0, 0);
// The ref node is the same type of node as the test node, but uses
// a-rate automation. However, the modulating signal is k-rate. This
// causes the input to the audio param to be constant over a render,
// which is basically the same as making the audio param be k-rate.
let refNode = new window[nodeName](context);
let refMod = new ConstantSourceNode(context);
refMod.offset.automationRate = 'k-rate';
if (options && options.testModSetup) {
options.testModSetup(refMod);
} else {
refMod.offset.linearRampToValueAtTime(context.length, testDuration);
}
refMod.connect(refNode[paramName]);
src.connect(refNode).connect(merger, 0, 1);
tstMod.start();
refMod.start();
}
</script>
</body>
</html>