Skip to content

Commit 3e5b6a4

Browse files
committed
ScriptProcessorNode: fix crash for multi channel output, add test
1 parent 13a1bdd commit 3e5b6a4

File tree

1 file changed

+66
-2
lines changed

1 file changed

+66
-2
lines changed

src/node/script_processor.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
268271
mod 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

Comments
 (0)