@@ -241,9 +241,12 @@ impl AudioProcessor for ScriptProcessorRenderer {
241241 // move next output buffer into current output buffer
242242 std:: mem:: swap ( & mut self . output_buffer , & mut self . next_output_buffer ) ;
243243
244- // fill next output buffer with silence
244+ // fill next output buffer with silence (with the right channel count)
245+ let mut silent_quantum = silence;
246+ silent_quantum. set_number_of_channels ( self . number_of_output_channels ) ;
245247 self . next_output_buffer . clear ( ) ;
246- self . next_output_buffer . resize ( number_of_quanta, silence) ;
248+ self . next_output_buffer
249+ . resize ( number_of_quanta, silent_quantum) ;
247250 }
248251
249252 false // node is kept alive as long as the handle in the event loop still exists
@@ -268,6 +271,7 @@ impl AudioProcessor for ScriptProcessorRenderer {
268271mod tests {
269272 use super :: * ;
270273 use crate :: context:: OfflineAudioContext ;
274+ use crate :: node:: scheduled_source:: AudioScheduledSourceNode ;
271275 use float_eq:: assert_float_eq;
272276
273277 #[ test]
@@ -322,4 +326,64 @@ mod tests {
322326 abs_all <= 0.
323327 ) ;
324328 }
329+
330+ #[ test]
331+ fn test_multiple_channels ( ) {
332+ const BUFFER_SIZE : usize = 256 ;
333+
334+ let mut context = OfflineAudioContext :: new ( 2 , BUFFER_SIZE * 3 , 48000. ) ;
335+
336+ // 2 input channels, 2 output channels
337+ let node = context. create_script_processor ( BUFFER_SIZE , 2 , 2 ) ;
338+ node. connect ( & context. destination ( ) ) ;
339+ node. set_onaudioprocess ( |e| {
340+ // left output buffer is left input * 2
341+ e. output_buffer
342+ . get_channel_data_mut ( 0 )
343+ . iter_mut ( )
344+ . zip ( e. input_buffer . get_channel_data ( 0 ) )
345+ . for_each ( |( o, i) | * o = * i * 2. ) ;
346+
347+ // right output buffer is right input * 3
348+ e. output_buffer
349+ . get_channel_data_mut ( 1 )
350+ . iter_mut ( )
351+ . zip ( e. input_buffer . get_channel_data ( 1 ) )
352+ . for_each ( |( o, i) | * o = * i * 3. ) ;
353+ } ) ;
354+
355+ // let the input be a mono constant source, it will be upmixed to two channels
356+ let mut src = context. create_constant_source ( ) ;
357+ src. start ( ) ;
358+ src. connect ( & node) ;
359+
360+ let result = context. start_rendering_sync ( ) ;
361+ let channel1 = result. get_channel_data ( 0 ) ;
362+ let channel2 = result. get_channel_data ( 1 ) ;
363+
364+ // first `2 * BUFFER_SIZE` samples should be silent due to buffering
365+ assert_float_eq ! (
366+ channel1[ ..2 * BUFFER_SIZE ] ,
367+ & [ 0. ; 2 * BUFFER_SIZE ] [ ..] ,
368+ abs_all <= 0.
369+ ) ;
370+ assert_float_eq ! (
371+ channel2[ ..2 * BUFFER_SIZE ] ,
372+ & [ 0. ; 2 * BUFFER_SIZE ] [ ..] ,
373+ abs_all <= 0.
374+ ) ;
375+
376+ // rest of the samples should be 2. for left buffer
377+ assert_float_eq ! (
378+ channel1[ 2 * BUFFER_SIZE ..] ,
379+ & [ 2. ; BUFFER_SIZE ] [ ..] ,
380+ abs_all <= 0.
381+ ) ;
382+ // rest of the samples should be 3. for right buffer
383+ assert_float_eq ! (
384+ channel2[ 2 * BUFFER_SIZE ..] ,
385+ & [ 3. ; BUFFER_SIZE ] [ ..] ,
386+ abs_all <= 0.
387+ ) ;
388+ }
325389}
0 commit comments