k-rate-constant-source.html (6563B)
1 <!doctype html> 2 <html> 3 <head> 4 <title>Test k-rate AudioParam of ConstantSourceNode</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/audit.js"></script> 9 <script src="automation-rate-testing.js"></script> 10 </head> 11 12 <body> 13 <script> 14 let audit = Audit.createTaskRunner(); 15 16 audit.define('ConstantSource k-rate offset', (task, should) => { 17 // Arbitrary sample rate and duration. 18 let sampleRate = 8000; 19 20 // Only new a few render quanta to verify things are working. 21 let testDuration = 4 * 128 / sampleRate; 22 23 let context = new OfflineAudioContext({ 24 numberOfChannels: 3, 25 sampleRate: sampleRate, 26 length: testDuration * sampleRate 27 }); 28 29 doTest(context, should, { 30 sourceNodeName: 'none', 31 verifyPieceWiseConstant: true, 32 nodeName: 'ConstantSourceNode', 33 prefix: 'k-rate offset', 34 rateSettings: [{name: 'offset', value: 'k-rate'}], 35 automations: [{ 36 name: 'offset', 37 methods: [ 38 {name: 'setValueAtTime', options: [0, 0]}, { 39 name: 'linearRampToValueAtTime', 40 options: [10, testDuration] 41 } 42 ] 43 }] 44 }).then(() => task.done()); 45 }); 46 47 // Parameters for the For the following tests. 48 49 // Must be power of two to eliminate round-off 50 const sampleRate8k = 8192; 51 52 // Arbitrary duration that doesn't need to be too long to verify k-rate 53 // automations. Probably should be at least a few render quanta. 54 const testDuration = 8 * RENDER_QUANTUM_FRAMES / sampleRate8k; 55 56 // Basic test that k-rate ConstantSourceNode.offset is k-rate. This is 57 // the basis for all of the following tests, so make sure it's right. 58 audit.define( 59 { 60 label: 'ConstantSourceNode.offset k-rate automation', 61 description: 62 'Explicitly test ConstantSourceNode.offset k-rate automation is k-rate' 63 }, 64 (task, should) => { 65 let context = new OfflineAudioContext({ 66 numberOfChannels: 2, 67 sampleRate: sampleRate8k, 68 length: testDuration * sampleRate8k 69 }); 70 let merger = new ChannelMergerNode( 71 context, {numberOfInputs: context.destination.channelCount}); 72 merger.connect(context.destination); 73 74 // k-rate ConstantSource.offset using a linear ramp starting at 0 75 // and incrementing by 1 for each frame. 76 let src = new ConstantSourceNode(context, {offset: 0}); 77 src.offset.automationRate = 'k-rate'; 78 79 src.offset.setValueAtTime(0, 0); 80 src.offset.linearRampToValueAtTime(context.length, testDuration); 81 82 src.connect(merger, 0, 0); 83 84 src.start(); 85 86 // a-rate ConstantSource using the same ramp as above. 87 let refSrc = new ConstantSourceNode(context, {offset: 0}); 88 89 refSrc.offset.setValueAtTime(0, 0); 90 refSrc.offset.linearRampToValueAtTime(context.length, testDuration); 91 92 refSrc.connect(merger, 0, 1); 93 94 refSrc.start(); 95 96 context.startRendering() 97 .then(buffer => { 98 let actual = buffer.getChannelData(0); 99 let expected = buffer.getChannelData(1); 100 101 for (let k = 0; k < actual.length; 102 k += RENDER_QUANTUM_FRAMES) { 103 // Verify that the k-rate output is constant over the render 104 // and that it matches the value of the a-rate value at the 105 // beginning of the render. 106 should( 107 actual.slice(k, k + RENDER_QUANTUM_FRAMES), 108 `k-rate ConstantSource.offset: output[${k}:${ 109 k + RENDER_QUANTUM_FRAMES}]`) 110 .beConstantValueOf(expected[k]); 111 } 112 }) 113 .then(() => task.done()); 114 }); 115 116 // This test verifies that a k-rate input to the ConstantSourceNode.offset 117 // works just as if we set the AudioParam to be k-rate. This is the basis 118 // of the following tests, so make sure it works. 119 audit.define( 120 { 121 label: 'ConstantSource.offset', 122 description: 'Verify k-rate automation matches k-rate input' 123 }, 124 (task, should) => { 125 let context = new OfflineAudioContext({ 126 numberOfChannels: 2, 127 sampleRate: sampleRate8k, 128 length: testDuration * sampleRate8k 129 }); 130 131 let merger = new ChannelMergerNode( 132 context, {numberOfInputs: context.destination.channelCount}); 133 merger.connect(context.destination); 134 135 let tstSrc = new ConstantSourceNode(context); 136 let tstMod = new ConstantSourceNode(context); 137 tstSrc.offset.automationRate = 'k-rate'; 138 tstMod.offset.linearRampToValueAtTime(context.length, testDuration); 139 140 tstMod.connect(tstSrc.offset) 141 tstSrc.connect(merger, 0, 0); 142 143 let refSrc = new ConstantSourceNode(context); 144 let refMod = new ConstantSourceNode(context); 145 refMod.offset.linearRampToValueAtTime(context.length, testDuration); 146 refMod.offset.automationRate = 'k-rate'; 147 148 refMod.connect(refSrc.offset); 149 refSrc.connect(merger, 0, 1); 150 151 tstSrc.start(); 152 tstMod.start(); 153 refSrc.start(); 154 refMod.start(); 155 156 context.startRendering() 157 .then(buffer => { 158 let actual = buffer.getChannelData(0); 159 let expected = buffer.getChannelData(1); 160 161 for (let k = 0; k < context.length; 162 k += RENDER_QUANTUM_FRAMES) { 163 should( 164 actual.slice(k, k + RENDER_QUANTUM_FRAMES), 165 `ConstantSource.offset k-rate input: output[${k}:${ 166 k + RENDER_QUANTUM_FRAMES}]`) 167 .beConstantValueOf(expected[k]); 168 } 169 }) 170 .then(() => task.done()); 171 }); 172 173 audit.run(); 174 </script> 175 </body> 176 </html>