1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
<!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>
|