adding-events.html (5350B)
1 <!doctype html> 2 <html> 3 <head> 4 <title>Adding Events</title> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/webaudio/resources/audit-util.js"></script> 8 <script src="/webaudio/resources/audio-param.js"></script> 9 </head> 10 11 <body> 12 <script> 13 14 // Arbitrary power of two to eliminate round-off in computing time from frame. 15 const sampleRate = 8192; 16 17 // Test insertion of an event in the middle of rendering. 18 // 19 // options dictionary: 20 // method - automation method to test 21 // prefix - string to use for prefixing messages 22 async function testInsertion(options) { 23 const {method, prefix} = options; 24 25 // Channel 0 is the output for the test, and channel 1 is the 26 // reference output. 27 const context = new OfflineAudioContext({ 28 numberOfChannels: 2, 29 length: sampleRate, 30 sampleRate: sampleRate 31 }); 32 33 const merger = new ChannelMergerNode( 34 context, {numberOfChannels: context.destination.channelCount}); 35 merger.connect(context.destination); 36 37 // Initial value and final values of the source node 38 const initialValue = 1; 39 const finalValue = 2; 40 41 // Set up the node for the automations under test 42 const src = new ConstantSourceNode(context, { offset: initialValue }); 43 src.connect(merger, 0, 0); 44 45 // Set initial event to occur at this time. Keep it in the first 46 // render quantum. 47 const initialEventTime = 64 / context.sampleRate; 48 // Any exception will naturally fail the test. 49 src.offset.setValueAtTime(initialValue, initialEventTime); 50 51 // Let time pass and then add a new event with time in the future. 52 const insertAtFrame = 512; 53 const insertTime = insertAtFrame / context.sampleRate; 54 const automationEndFrame = 1024 + 64; 55 const automationEndTime = automationEndFrame / context.sampleRate; 56 57 // Schedule the insertion while rendering is in progress. 58 context.suspend(insertTime).then(() => { 59 src.offset[method](finalValue, automationEndTime); 60 context.resume(); 61 }); 62 63 // Set up graph for the reference result. Automate the source with 64 // the events scheduled from the beginning. Let the gain node 65 // simulate the insertion of the event above. This is done by 66 // setting the gain to 1 at the insertion time. 67 const srcRef = new ConstantSourceNode(context, {offset: 1}); 68 const g = new GainNode(context, {gain: 0}); 69 srcRef.connect(g).connect(merger, 0, 1); 70 srcRef.offset.setValueAtTime(initialValue, initialEventTime); 71 srcRef.offset[method](finalValue, automationEndTime); 72 73 // Allow everything through after |insertAtFrame| frames. 74 g.gain.setValueAtTime(1, insertTime); 75 76 // Go! 77 src.start(); 78 srcRef.start(); 79 80 const audioBuffer = await context.startRendering(); 81 82 const actual = audioBuffer.getChannelData(0); 83 const expected = audioBuffer.getChannelData(1); 84 85 // Verify that the output is 1 until we reach 86 // insertAtFrame. Ignore the expected data because that always 87 // produces 1. 88 { 89 const actualBeforeInsert = actual.slice(0, insertAtFrame); 90 const expectedBeforeInsert = new Float32Array(insertAtFrame); 91 expectedBeforeInsert.fill(initialValue); 92 assert_array_equal_within_eps( 93 actualBeforeInsert, 94 expectedBeforeInsert, 95 0, 96 `${prefix}: output[0:${insertAtFrame - 1}]`); 97 } 98 99 // Verify ramp is correct by comparing it to the expected 100 { 101 const rampStart = insertAtFrame; 102 const rampEndInclusive = automationEndFrame; 103 const rampEndExclusive = rampEndInclusive + 1; 104 105 const actualRamp = actual.slice(rampStart, rampEndExclusive); 106 const expectedRamp = expected.slice(rampStart, rampEndExclusive); 107 108 assert_array_equal_within_eps( 109 actualRamp, 110 expectedRamp, 111 {absoluteThreshold: 0}, 112 `${prefix}: output[${rampStart}:${rampEndInclusive}]`); 113 } 114 115 // Verify final output has the expected value 116 { 117 const tailStart = automationEndFrame + 1; 118 const actualTail = actual.slice(tailStart); 119 const refTail = new Float32Array(actualTail.length); 120 refTail.fill(finalValue); 121 122 assert_array_equal_within_eps( 123 actualTail, 124 refTail, 125 0, 126 `${prefix}: output[${tailStart}:]`); 127 } 128 } 129 130 // Define tests (replacing audit.define/audit.run with promise_test) 131 promise_test(async () => { 132 await testInsertion({ 133 method: 'linearRampToValueAtTime', 134 prefix: 'linearRamp' 135 }); 136 }, 'linearRamp: Insert linearRamp after running for some time'); 137 138 promise_test(async () => { 139 await testInsertion({ 140 method: 'exponentialRampToValueAtTime', 141 prefix: 'exponentialRamp' 142 }); 143 }, 'exponentialRamp: Insert exponentialRamp after running for some time'); 144 </script> 145 </body> 146 </html>