test_delaynode-channel-count-1.html (4581B)
1 <!DOCTYPE html> 2 <title>Test that DelayNode output channelCount matches that of the delayed input</title> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script> 6 // See https://github.com/WebAudio/web-audio-api/issues/25 7 8 // sampleRate is a power of two so that delay times are exact in base-2 9 // floating point arithmetic. 10 const SAMPLE_RATE = 32768; 11 // Arbitrary delay time in frames (but this is assumed a multiple of block 12 // size below): 13 const DELAY_FRAMES = 3 * 128; 14 // Implementations may apply interpolation to input samples, which can spread 15 // the effect of input with larger channel counts over neighbouring blocks. 16 // This test ignores enough neighbouring blocks to ignore the effects of 17 // filter radius of up to this number of frames: 18 const INTERPOLATION_GRACE = 128; 19 // Number of frames of DelayNode output that are known to be stereo: 20 const STEREO_FRAMES = 128; 21 // The delay will be increased at this frame to switch DelayNode output back 22 // to mono. 23 const MONO_OUTPUT_START_FRAME = 24 DELAY_FRAMES + INTERPOLATION_GRACE + STEREO_FRAMES; 25 // Number of frames of output that are known to be mono after the known stereo 26 // and interpolation grace. 27 const MONO_FRAMES = 128; 28 // Total length allows for interpolation after effects of stereo input are 29 // finished and one block to test return to mono output: 30 const TOTAL_LENGTH = 31 MONO_OUTPUT_START_FRAME + INTERPOLATION_GRACE + MONO_FRAMES; 32 // maxDelayTime, is a multiple of block size, because the Gecko implementation 33 // once had a bug with delayTime = maxDelayTime in this situation: 34 const MAX_DELAY_FRAMES = TOTAL_LENGTH + INTERPOLATION_GRACE; 35 36 promise_test(() => { 37 let context = new OfflineAudioContext({numberOfChannels: 1, 38 length: TOTAL_LENGTH, 39 sampleRate: SAMPLE_RATE}); 40 41 // Only channel 1 of the splitter is connected to the destination. 42 let splitter = new ChannelSplitterNode(context, {numberOfOutputs: 2}); 43 splitter.connect(context.destination, 1); 44 45 // A gain node has channelCountMode "max" and channelInterpretation 46 // "speakers", and so will up-mix a mono input when there is stereo input. 47 let gain = new GainNode(context); 48 gain.connect(splitter); 49 50 // The delay node initially outputs a single channel of silence, when it 51 // does not have enough signal in its history to output what it has 52 // previously received. After the delay period, it will then output the 53 // stereo signal it received. 54 let delay = 55 new DelayNode(context, 56 {maxDelayTime: MAX_DELAY_FRAMES / context.sampleRate, 57 delayTime: DELAY_FRAMES / context.sampleRate}); 58 // Schedule an increase in the delay to return to mono silent output from 59 // the unfilled portion of the DelayNode's buffer. 60 delay.delayTime.setValueAtTime(MAX_DELAY_FRAMES / context.sampleRate, 61 MONO_OUTPUT_START_FRAME / context.sampleRate); 62 delay.connect(gain); 63 64 let stereoMerger = new ChannelMergerNode(context, {numberOfInputs: 2}); 65 stereoMerger.connect(delay); 66 67 let leftOffset = 0.125; 68 let rightOffset = 0.5; 69 let leftSource = new ConstantSourceNode(context, {offset: leftOffset}); 70 let rightSource = new ConstantSourceNode(context, {offset: rightOffset}); 71 leftSource.start(); 72 rightSource.start(); 73 leftSource.connect(stereoMerger, 0, 0); 74 rightSource.connect(stereoMerger, 0, 1); 75 // Connect a mono source directly to the gain, so that even stereo silence 76 // will be detected in channel 1 of the gain output because it will cause 77 // the mono source to be up-mixed. 78 let monoOffset = 0.25 79 let monoSource = new ConstantSourceNode(context, {offset: monoOffset}); 80 monoSource.start(); 81 monoSource.connect(gain); 82 83 return context.startRendering(). 84 then((buffer) => { 85 let output = buffer.getChannelData(0); 86 87 function assert_samples_equal(startIndex, length, expected, description) 88 { 89 for (let i = startIndex; i < startIndex + length; ++i) { 90 assert_equals(output[i], expected, description + ` at ${i}`); 91 } 92 } 93 94 assert_samples_equal(0, DELAY_FRAMES - INTERPOLATION_GRACE, 95 0, "Initial mono"); 96 assert_samples_equal(DELAY_FRAMES + INTERPOLATION_GRACE, STEREO_FRAMES, 97 monoOffset + rightOffset, "Stereo"); 98 assert_samples_equal(MONO_OUTPUT_START_FRAME + INTERPOLATION_GRACE, 99 MONO_FRAMES, 100 0, "Final mono"); 101 }); 102 }); 103 104 </script>