Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!doctype html>
<html>
<head>
<title>Adding Events</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/audio-param.js"></script>
</head>
<body>
<script>
let audit = Audit.createTaskRunner();
// Arbitrary power of two to eliminate round-off in computing time from
// frame.
const sampleRate = 8192;
audit.define(
{
label: 'linearRamp',
description: 'Insert linearRamp after running for some time'
},
(task, should) => {
testInsertion(should, {
method: 'linearRampToValueAtTime',
prefix: 'linearRamp'
}).then(() => task.done());
});
audit.define(
{
label: 'expoRamp',
description: 'Insert expoRamp after running for some time'
},
(task, should) => {
testInsertion(should, {
method: 'exponentialRampToValueAtTime',
prefix: 'expoRamp'
}).then(() => task.done());
});
// Test insertion of an event in the middle of rendering.
//
// options dictionary:
// method - automation method to test
// prefix - string to use for prefixing messages
function testInsertion(should, options) {
let {method, prefix} = options;
// Channel 0 is the output for the test, and channel 1 is the
// reference output.
let context = new OfflineAudioContext(
{numberOfChannels: 2, length: sampleRate, sampleRate: sampleRate});
let merger = new ChannelMergerNode(
context, {numberOfChannels: context.destination.channelCount});
merger.connect(context.destination);
// Initial value and final values of the source node
let initialValue = 1;
let finalValue = 2;
// Set up the node for the automations under test
let src = new ConstantSourceNode(context, {offset: initialValue});
src.connect(merger, 0, 0);
// Set initial event to occur at this time. Keep it in the first
// render quantum.
const initialEventTime = 64 / context.sampleRate;
should(
() => src.offset.setValueAtTime(initialValue, initialEventTime),
`${prefix}: setValueAtTime(${initialValue}, ${initialEventTime})`)
.notThrow();
// Let time pass and then add a new event with time in the future.
let insertAtFrame = 512;
let insertTime = insertAtFrame / context.sampleRate;
let automationEndFrame = 1024 + 64;
let automationEndTime = automationEndFrame / context.sampleRate;
context.suspend(insertTime)
.then(() => {
should(
() => src.offset[method](finalValue, automationEndTime),
`${prefix}: At time ${insertTime} scheduling ${method}(${
finalValue}, ${automationEndTime})`)
.notThrow();
})
.then(() => context.resume());
// Set up graph for the reference result. Automate the source with
// the events scheduled from the beginning. Let the gain node
// simulate the insertion of the event above. This is done by
// setting the gain to 1 at the insertion time.
let srcRef = new ConstantSourceNode(context, {offset: 1});
let g = new GainNode(context, {gain: 0});
srcRef.connect(g).connect(merger, 0, 1);
srcRef.offset.setValueAtTime(initialValue, initialEventTime);
srcRef.offset[method](finalValue, automationEndTime);
// Allow everything through after |insertFrame| frames.
g.gain.setValueAtTime(1, insertTime);
// Go!
src.start();
srcRef.start();
return context.startRendering().then(audioBuffer => {
let actual = audioBuffer.getChannelData(0);
let expected = audioBuffer.getChannelData(1);
// Verify that the output is 1 until we reach
// insertAtFrame. Ignore the expected data because that always
// produces 1.
should(
actual.slice(0, insertAtFrame),
`${prefix}: output[0:${insertAtFrame - 1}]`)
.beConstantValueOf(initialValue);
// Verify ramp is correct by comparing it to the expected
// data.
should(
actual.slice(
insertAtFrame, automationEndFrame - insertAtFrame + 1),
`${prefix}: output[${insertAtFrame}:${
automationEndFrame - insertAtFrame}]`)
.beCloseToArray(
expected.slice(
insertAtFrame, automationEndFrame - insertAtFrame + 1),
{absoluteThreshold: 0, numberOfArrayElements: 0});
// Verify final output has the expected value
should(
actual.slice(automationEndFrame),
`${prefix}: output[${automationEndFrame}:]`)
.beConstantValueOf(finalValue);
})
}
audit.run();
</script>
</body>
</html>