Skip to content

Commit cb0305a

Browse files
authored
Merge pull request #414 from orottier/bugfix/worklet-channels
Fix worklet output channel iterator #413
2 parents 3a7687d + ddeefbd commit cb0305a

File tree

1 file changed

+111
-9
lines changed

1 file changed

+111
-9
lines changed

src/worklet.rs

Lines changed: 111 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,15 @@ impl AudioProcessor for AudioWorkletRenderer {
323323

324324
// Create an iterator for the output channel counts without allocating, handling also the
325325
// case where self.output_channel_count is empty.
326-
let output_channel_count = self
327-
.output_channel_count
328-
.iter()
329-
.copied()
330-
.chain(std::iter::once(inputs[0].number_of_channels()));
326+
let single_case = [inputs
327+
.get(0)
328+
.map(|i| i.number_of_channels())
329+
.unwrap_or_default()];
330+
let output_channel_count = if self.output_channel_count.is_empty() {
331+
&single_case[..]
332+
} else {
333+
&self.output_channel_count[..]
334+
};
331335

332336
outputs
333337
.iter_mut()
@@ -342,7 +346,7 @@ impl AudioProcessor for AudioWorkletRenderer {
342346

343347
let mut outputs_flat = &mut self.outputs_flat[..];
344348
for c in output_channel_count {
345-
let (left, right) = outputs_flat.split_at_mut(c);
349+
let (left, right) = outputs_flat.split_at_mut(*c);
346350
// SAFETY - see comments above
347351
let left_static = unsafe { std::mem::transmute(left) };
348352
self.outputs_grouped.push(left_static);
@@ -374,15 +378,113 @@ impl AudioProcessor for AudioWorkletRenderer {
374378
mod tests {
375379
use super::*;
376380
use crate::context::OfflineAudioContext;
381+
use float_eq::assert_float_eq;
382+
383+
struct TestProcessor;
384+
385+
impl AudioWorkletProcessor for TestProcessor {
386+
type ProcessorOptions = ();
387+
388+
fn constructor(_opts: Self::ProcessorOptions) -> Self {
389+
TestProcessor {}
390+
}
391+
392+
fn process<'a, 'b>(
393+
&mut self,
394+
_inputs: &'b [&'a [&'a [f32]]],
395+
_outputs: &'b mut [&'a mut [&'a mut [f32]]],
396+
_params: AudioParamValues<'b>,
397+
_scope: &'b RenderScope,
398+
) -> bool {
399+
true
400+
}
401+
}
402+
403+
#[test]
404+
fn test_worklet_render() {
405+
let mut context = OfflineAudioContext::new(1, 128, 48000.);
406+
let options = AudioWorkletNodeOptions::default();
407+
let worklet = AudioWorkletNode::new::<TestProcessor>(&context, options);
408+
worklet.connect(&context.destination());
409+
let buffer = context.start_rendering_sync();
410+
assert_float_eq!(
411+
buffer.get_channel_data(0)[..],
412+
&[0.; 128][..],
413+
abs_all <= 0.
414+
);
415+
}
416+
417+
#[test]
418+
fn test_worklet_inputs_outputs() {
419+
let matrix = [0, 1, 2];
420+
let mut context = OfflineAudioContext::new(1, 128, 48000.);
421+
for inputs in matrix {
422+
for outputs in matrix {
423+
if inputs == 0 && outputs == 0 {
424+
continue; // this case is not allowed
425+
}
426+
let options = AudioWorkletNodeOptions {
427+
number_of_inputs: inputs,
428+
number_of_outputs: outputs,
429+
..AudioWorkletNodeOptions::default()
430+
};
431+
let worklet = AudioWorkletNode::new::<TestProcessor>(&context, options);
432+
433+
if outputs > 0 {
434+
worklet.connect(&context.destination());
435+
}
436+
}
437+
}
438+
let buffer = context.start_rendering_sync();
439+
assert_float_eq!(
440+
buffer.get_channel_data(0)[..],
441+
&[0.; 128][..],
442+
abs_all <= 0.
443+
);
444+
}
445+
446+
#[test]
447+
fn test_worklet_output_channel_count() {
448+
let mut context = OfflineAudioContext::new(1, 128, 48000.);
449+
450+
let options1 = AudioWorkletNodeOptions {
451+
output_channel_count: vec![],
452+
..AudioWorkletNodeOptions::default()
453+
};
454+
let worklet1 = AudioWorkletNode::new::<TestProcessor>(&context, options1);
455+
worklet1.connect(&context.destination());
456+
457+
let options2 = AudioWorkletNodeOptions {
458+
output_channel_count: vec![1],
459+
..AudioWorkletNodeOptions::default()
460+
};
461+
let worklet2 = AudioWorkletNode::new::<TestProcessor>(&context, options2);
462+
worklet2.connect(&context.destination());
463+
464+
let options3 = AudioWorkletNodeOptions {
465+
number_of_outputs: 2,
466+
output_channel_count: vec![1, 2],
467+
..AudioWorkletNodeOptions::default()
468+
};
469+
let worklet3 = AudioWorkletNode::new::<TestProcessor>(&context, options3);
470+
worklet3.connect(&context.destination());
471+
472+
let buffer = context.start_rendering_sync();
473+
assert_float_eq!(
474+
buffer.get_channel_data(0)[..],
475+
&[0.; 128][..],
476+
abs_all <= 0.
477+
);
478+
}
377479

378480
#[test]
379481
fn send_bound() {
380482
#[derive(Default)]
381-
struct MyProcessor {
483+
struct RcProcessor {
382484
_rc: std::rc::Rc<()>, // not send
383485
}
384486

385-
impl AudioWorkletProcessor for MyProcessor {
487+
impl AudioWorkletProcessor for RcProcessor {
386488
type ProcessorOptions = ();
387489

388490
fn constructor(_opts: Self::ProcessorOptions) -> Self {
@@ -402,6 +504,6 @@ mod tests {
402504

403505
let context = OfflineAudioContext::new(1, 128, 48000.);
404506
let options = AudioWorkletNodeOptions::default();
405-
let _worklet = AudioWorkletNode::new::<MyProcessor>(&context, options);
507+
let _worklet = AudioWorkletNode::new::<RcProcessor>(&context, options);
406508
}
407509
}

0 commit comments

Comments
 (0)