1use std::any::Any;
2
3use fft_convolver::FFTConvolver;
4
5use crate::buffer::AudioBuffer;
6use crate::context::{AudioContextRegistration, BaseAudioContext};
7use crate::render::{
8 AudioParamValues, AudioProcessor, AudioRenderQuantum, AudioWorkletGlobalScope,
9};
10use crate::RENDER_QUANTUM_SIZE;
11
12use super::{AudioNode, AudioNodeOptions, ChannelConfig, ChannelCountMode, ChannelInterpretation};
13
14fn normalize_buffer(buffer: &AudioBuffer) -> f32 {
17 let gain_calibration = 0.00125;
18 let gain_calibration_sample_rate = 44100.;
19 let min_power = 0.000125;
20
21 let number_of_channels = buffer.number_of_channels();
23 let length = buffer.length();
24 let sample_rate = buffer.sample_rate();
25
26 let mut power: f32 = buffer
27 .channels()
28 .iter()
29 .map(|c| c.as_slice().iter().map(|&s| s * s).sum::<f32>())
30 .sum();
31
32 power = (power / (number_of_channels * length) as f32).sqrt();
33
34 if !power.is_finite() || power.is_nan() || power < min_power {
36 power = min_power;
37 }
38
39 let mut scale = 1. / power;
40
41 scale *= gain_calibration;
43
44 scale *= gain_calibration_sample_rate / sample_rate;
46
47 if number_of_channels == 4 {
49 scale *= 0.5;
50 }
51
52 scale
53}
54
55#[derive(Clone, Debug)]
61pub struct ConvolverOptions {
62 pub buffer: Option<AudioBuffer>,
64 pub disable_normalization: bool,
66 pub audio_node_options: AudioNodeOptions,
68}
69
70impl Default for ConvolverOptions {
71 fn default() -> Self {
72 Self {
73 buffer: None,
74 disable_normalization: false,
75 audio_node_options: AudioNodeOptions {
76 channel_count: 2,
77 channel_count_mode: ChannelCountMode::ClampedMax,
78 channel_interpretation: ChannelInterpretation::Speakers,
79 },
80 }
81 }
82}
83
84#[track_caller]
92#[inline(always)]
93fn assert_valid_channel_count(count: usize) {
94 assert!(
95 count <= 2,
96 "NotSupportedError - ConvolverNode channel count cannot be greater than two"
97 );
98}
99
100#[track_caller]
108#[inline(always)]
109fn assert_valid_channel_count_mode(mode: ChannelCountMode) {
110 assert_ne!(
111 mode,
112 ChannelCountMode::Max,
113 "NotSupportedError - ConvolverNode channel count mode cannot be set to max"
114 );
115}
116
117#[derive(Debug)]
158pub struct ConvolverNode {
159 registration: AudioContextRegistration,
161 channel_config: ChannelConfig,
163 normalize: bool,
165 buffer: Option<AudioBuffer>,
167}
168
169impl AudioNode for ConvolverNode {
170 fn registration(&self) -> &AudioContextRegistration {
171 &self.registration
172 }
173
174 fn channel_config(&self) -> &ChannelConfig {
175 &self.channel_config
176 }
177
178 fn number_of_inputs(&self) -> usize {
179 1
180 }
181
182 fn number_of_outputs(&self) -> usize {
183 1
184 }
185
186 fn set_channel_count(&self, count: usize) {
188 assert_valid_channel_count(count);
189 self.channel_config.set_count(count, self.registration());
190 }
191
192 fn set_channel_count_mode(&self, mode: ChannelCountMode) {
194 assert_valid_channel_count_mode(mode);
195 self.channel_config
196 .set_count_mode(mode, self.registration());
197 }
198}
199
200impl ConvolverNode {
201 pub fn new<C: BaseAudioContext>(context: &C, options: ConvolverOptions) -> Self {
213 let ConvolverOptions {
214 buffer,
215 disable_normalization,
216 audio_node_options,
217 } = options;
218
219 assert_valid_channel_count(audio_node_options.channel_count);
220 assert_valid_channel_count_mode(audio_node_options.channel_count_mode);
221
222 let mut node = context.base().register(move |registration| {
223 let renderer = ConvolverRenderer {
224 convolvers: None,
225 impulse_length: 0,
226 impulse_number_of_channels: 0,
227 tail_count: 0,
228 };
229
230 let node = Self {
231 registration,
232 channel_config: audio_node_options.into(),
233 normalize: !disable_normalization,
234 buffer: None,
235 };
236
237 (node, Box::new(renderer))
238 });
239
240 if let Some(buffer) = buffer {
242 node.set_buffer(buffer);
243 }
244
245 node
246 }
247
248 pub fn buffer(&self) -> Option<&AudioBuffer> {
250 self.buffer.as_ref()
251 }
252
253 pub fn set_buffer(&mut self, buffer: AudioBuffer) {
260 let sample_rate = buffer.sample_rate();
265 assert_eq!(
266 sample_rate,
267 self.context().sample_rate(),
268 "NotSupportedError - sample rate of the convolution buffer must match the audio context"
269 );
270
271 let number_of_channels = buffer.number_of_channels();
272 assert!(
273 [1, 2, 4].contains(&number_of_channels),
274 "NotSupportedError - the convolution buffer must consist of 1, 2 or 4 channels"
275 );
276
277 let scale = if self.normalize {
279 normalize_buffer(&buffer)
280 } else {
281 1.
282 };
283
284 let mut convolvers = Vec::<FFTConvolver<f32>>::new();
285 let partition_size = RENDER_QUANTUM_SIZE * 8;
287
288 for index in 0..number_of_channels.max(2) {
292 let channel = index.min(number_of_channels - 1);
294
295 let mut scaled_channel = vec![0.; buffer.length()];
296 scaled_channel
297 .iter_mut()
298 .zip(buffer.get_channel_data(channel))
299 .for_each(|(o, i)| *o = *i * scale);
300
301 let mut convolver = FFTConvolver::<f32>::default();
302 convolver
303 .init(partition_size, &scaled_channel)
304 .expect("Unable to initialize convolution engine");
305
306 convolvers.push(convolver);
307 }
308
309 let msg = ConvolverInfosMessage {
310 convolvers: Some(convolvers),
311 impulse_length: buffer.length(),
312 impulse_number_of_channels: number_of_channels,
313 };
314
315 self.registration.post_message(msg);
316 self.buffer = Some(buffer);
317 }
318
319 pub fn normalize(&self) -> bool {
321 self.normalize
322 }
323
324 pub fn set_normalize(&mut self, value: bool) {
326 self.normalize = value;
327 }
328}
329
330struct ConvolverInfosMessage {
331 convolvers: Option<Vec<FFTConvolver<f32>>>,
332 impulse_length: usize,
333 impulse_number_of_channels: usize,
334}
335
336struct ConvolverRenderer {
337 convolvers: Option<Vec<FFTConvolver<f32>>>,
338 impulse_length: usize,
339 impulse_number_of_channels: usize,
340 tail_count: usize,
341}
342
343impl AudioProcessor for ConvolverRenderer {
344 fn process(
345 &mut self,
346 inputs: &[AudioRenderQuantum],
347 outputs: &mut [AudioRenderQuantum],
348 _params: AudioParamValues<'_>,
349 _scope: &AudioWorkletGlobalScope,
350 ) -> bool {
351 let input = &inputs[0];
353 let output = &mut outputs[0];
354
355 if input.is_silent() {
358 if self.tail_count >= self.impulse_length {
359 output.make_silent();
360 return false;
361 }
362
363 self.tail_count += RENDER_QUANTUM_SIZE;
364 } else {
365 self.tail_count = 0;
366 }
367
368 let convolvers = match &mut self.convolvers {
369 None => {
370 *output = input.clone();
372 return !input.is_silent();
373 }
374 Some(convolvers) => convolvers,
375 };
376
377 match (input.number_of_channels(), self.impulse_number_of_channels) {
379 (1, 1) => {
380 output.set_number_of_channels(1);
381
382 let i = &input.channel_data(0)[..];
383 let o = &mut output.channel_data_mut(0)[..];
384 let _ = convolvers[0].process(i, o);
385 }
386 (1, 2) => {
387 output.set_number_of_channels(2);
388
389 let i = &input.channel_data(0)[..];
390
391 let o_left = &mut output.channel_data_mut(0)[..];
392 let _ = convolvers[0].process(i, o_left);
393
394 let o_right = &mut output.channel_data_mut(1)[..];
395 let _ = convolvers[1].process(i, o_right);
396 }
397 (2, 1) => {
398 output.set_number_of_channels(2);
399
400 let i_left = &input.channel_data(0)[..];
401 let o_left = &mut output.channel_data_mut(0)[..];
402 let _ = convolvers[0].process(i_left, o_left);
403
404 let i_right = &input.channel_data(1)[..];
405 let o_right = &mut output.channel_data_mut(1)[..];
406 let _ = convolvers[1].process(i_right, o_right);
407 }
408 (2, 2) => {
409 output.set_number_of_channels(2);
410
411 let i_left = &input.channel_data(0)[..];
412 let o_left = &mut output.channel_data_mut(0)[..];
413 let _ = convolvers[0].process(i_left, o_left);
414
415 let i_right = &input.channel_data(1)[..];
416 let o_right = &mut output.channel_data_mut(1)[..];
417 let _ = convolvers[1].process(i_right, o_right);
418 }
419 (2, 4) => {
420 output.set_number_of_channels(4);
421
422 let i_left = &input.channel_data(0)[..];
423
424 let o_0 = &mut output.channel_data_mut(0)[..];
425 let _ = convolvers[0].process(i_left, o_0);
426 let o_1 = &mut output.channel_data_mut(1)[..];
427 let _ = convolvers[1].process(i_left, o_1);
428
429 let i_right = &input.channel_data(1)[..];
430
431 let o_2 = &mut output.channel_data_mut(2)[..];
432 let _ = convolvers[2].process(i_right, o_2);
433 let o_3 = &mut output.channel_data_mut(3)[..];
434 let _ = convolvers[3].process(i_right, o_3);
435
436 let o_2 = output.channel_data(2).clone();
438 let o_3 = output.channel_data(3).clone();
439
440 output
441 .channel_data_mut(0)
442 .iter_mut()
443 .zip(o_2.iter())
444 .for_each(|(l, sl)| *l += *sl);
445
446 output
447 .channel_data_mut(1)
448 .iter_mut()
449 .zip(o_3.iter())
450 .for_each(|(r, sr)| *r += *sr);
451
452 output.set_number_of_channels(2);
453 }
454 (1, 4) => {
455 output.set_number_of_channels(4);
456
457 let i = &input.channel_data(0)[..];
458
459 let o_0 = &mut output.channel_data_mut(0)[..];
460 let _ = convolvers[0].process(i, o_0);
461 let o_1 = &mut output.channel_data_mut(1)[..];
462 let _ = convolvers[1].process(i, o_1);
463 let o_2 = &mut output.channel_data_mut(2)[..];
464 let _ = convolvers[2].process(i, o_2);
465 let o_3 = &mut output.channel_data_mut(3)[..];
466 let _ = convolvers[3].process(i, o_3);
467
468 let o_2 = output.channel_data(2).clone();
470 let o_3 = output.channel_data(3).clone();
471
472 output
473 .channel_data_mut(0)
474 .iter_mut()
475 .zip(o_2.iter())
476 .for_each(|(l, sl)| *l += *sl);
477
478 output
479 .channel_data_mut(1)
480 .iter_mut()
481 .zip(o_3.iter())
482 .for_each(|(r, sr)| *r += *sr);
483
484 output.set_number_of_channels(2);
485 }
486 _ => unreachable!(),
487 }
488
489 true
490 }
491
492 fn onmessage(&mut self, msg: &mut dyn Any) {
493 if let Some(msg) = msg.downcast_mut::<ConvolverInfosMessage>() {
494 let ConvolverInfosMessage {
495 convolvers,
496 impulse_length,
497 impulse_number_of_channels,
498 } = msg;
499 std::mem::swap(&mut self.convolvers, convolvers);
501 self.impulse_length = *impulse_length;
502 self.impulse_number_of_channels = *impulse_number_of_channels;
503
504 return;
505 }
506
507 log::warn!("ConvolverRenderer: Dropping incoming message {msg:?}");
508 }
509}
510
511#[cfg(test)]
512mod tests {
513 use float_eq::assert_float_eq;
514
515 use crate::context::{BaseAudioContext, OfflineAudioContext};
516 use crate::node::{AudioBufferSourceNode, AudioBufferSourceOptions, AudioScheduledSourceNode};
517
518 use super::*;
519
520 #[test]
521 #[should_panic]
522 fn test_buffer_sample_rate_matches() {
523 let context = OfflineAudioContext::new(1, 128, 44100.);
524
525 let ir = vec![1.];
526 let ir = AudioBuffer::from(vec![ir; 1], 48000.); let options = ConvolverOptions {
528 buffer: Some(ir),
529 ..ConvolverOptions::default()
530 };
531
532 let _ = ConvolverNode::new(&context, options);
533 }
534
535 #[test]
536 #[should_panic]
537 fn test_buffer_must_have_1_2_4_channels() {
538 let context = OfflineAudioContext::new(1, 128, 48000.);
539
540 let ir = vec![1.];
541 let ir = AudioBuffer::from(vec![ir; 3], 48000.); let options = ConvolverOptions {
543 buffer: Some(ir),
544 ..ConvolverOptions::default()
545 };
546
547 let _ = ConvolverNode::new(&context, options);
548 }
549
550 #[test]
551 fn test_constructor_options_buffer() {
552 let sample_rate = 44100.;
553 let mut context = OfflineAudioContext::new(1, 10, sample_rate);
554
555 let ir = vec![1.];
556 let calibration = 0.00125;
557 let channel_data = vec![0., 1., 0., -1., 0.];
558 let expected = [0., calibration, 0., -calibration, 0., 0., 0., 0., 0., 0.];
559
560 let ir = AudioBuffer::from(vec![ir; 1], sample_rate);
562 let options = ConvolverOptions {
563 buffer: Some(ir),
564 ..ConvolverOptions::default()
565 };
566 let conv = ConvolverNode::new(&context, options);
567 conv.connect(&context.destination());
568
569 let buffer = AudioBuffer::from(vec![channel_data; 1], sample_rate);
570 let mut src = context.create_buffer_source();
571 src.connect(&conv);
572 src.set_buffer(buffer);
573 src.start();
574
575 let output = context.start_rendering_sync();
576
577 assert_float_eq!(output.get_channel_data(0), &expected[..], abs_all <= 1E-6);
578 }
579
580 fn test_convolve(signal: &[f32], impulse_resp: Option<Vec<f32>>, length: usize) -> AudioBuffer {
581 let sample_rate = 44100.;
582 let mut context = OfflineAudioContext::new(1, length, sample_rate);
583
584 let input = AudioBuffer::from(vec![signal.to_vec()], sample_rate);
585 let mut src = AudioBufferSourceNode::new(&context, AudioBufferSourceOptions::default());
586 src.set_buffer(input);
587 src.start();
588
589 let mut conv = ConvolverNode::new(&context, ConvolverOptions::default());
590 if let Some(ir) = impulse_resp {
591 conv.set_buffer(AudioBuffer::from(vec![ir.to_vec()], sample_rate));
592 }
593
594 src.connect(&conv);
595 conv.connect(&context.destination());
596
597 context.start_rendering_sync()
598 }
599
600 #[test]
601 fn test_passthrough() {
602 let output = test_convolve(&[0., 1., 0., -1., 0.], None, 10);
603 let expected = [0., 1., 0., -1., 0., 0., 0., 0., 0., 0.];
604 assert_float_eq!(output.get_channel_data(0), &expected[..], abs_all <= 1E-6);
605 }
606
607 #[test]
608 fn test_empty() {
609 let ir = vec![];
610 let output = test_convolve(&[0., 1., 0., -1., 0.], Some(ir), 10);
611 let expected = [0.; 10];
612 assert_float_eq!(output.get_channel_data(0), &expected[..], abs_all <= 1E-6);
613 }
614
615 #[test]
616 fn test_zeroed() {
617 let ir = vec![0., 0., 0., 0., 0., 0.];
618 let output = test_convolve(&[0., 1., 0., -1., 0.], Some(ir), 10);
619 let expected = [0.; 10];
620 assert_float_eq!(output.get_channel_data(0), &expected[..], abs_all <= 1E-6);
621 }
622
623 #[test]
624 fn test_identity() {
625 let ir = vec![1.];
626 let calibration = 0.00125;
627 let output = test_convolve(&[0., 1., 0., -1., 0.], Some(ir), 10);
628 let expected = [0., calibration, 0., -calibration, 0., 0., 0., 0., 0., 0.];
629 assert_float_eq!(output.get_channel_data(0), &expected[..], abs_all <= 1E-6);
630 }
631
632 #[test]
633 fn test_two_id() {
634 let ir = vec![1., 1.];
635 let calibration = 0.00125;
636 let output = test_convolve(&[0., 1., 0., -1., 0.], Some(ir), 10);
637 let expected = [
638 0.,
639 calibration,
640 calibration,
641 -calibration,
642 -calibration,
643 0.,
644 0.,
645 0.,
646 0.,
647 0.,
648 ];
649 assert_float_eq!(output.get_channel_data(0), &expected[..], abs_all <= 1E-6);
650 }
651
652 #[test]
653 fn test_should_have_tail_time() {
654 const IR_LEN: usize = 256;
656 let ir = vec![1.; IR_LEN];
657
658 let input = &[1.];
660
661 let output = test_convolve(input, Some(ir), 512);
663
664 let output = output.channel_data(0).as_slice();
666 assert!(!output[..IR_LEN].iter().any(|v| *v <= 1E-6));
667 assert_float_eq!(&output[IR_LEN..], &[0.; 512 - IR_LEN][..], abs_all <= 1E-6);
668 }
669
670 #[test]
671 fn test_channel_config_1_chan_in_1_chan_ir() {
672 let number_of_channels = 1;
673 let length = 128;
674 let sample_rate = 44100.;
675 let mut context = OfflineAudioContext::new(number_of_channels, length, sample_rate);
676
677 let input = AudioBuffer::from(vec![vec![1.]], sample_rate);
678 let ir = AudioBuffer::from(vec![vec![0., 1.]], sample_rate);
679
680 let mut src = AudioBufferSourceNode::new(
681 &context,
682 AudioBufferSourceOptions {
683 buffer: Some(input),
684 ..AudioBufferSourceOptions::default()
685 },
686 );
687
688 let conv = ConvolverNode::new(
689 &context,
690 ConvolverOptions {
691 buffer: Some(ir),
692 disable_normalization: true,
693 ..ConvolverOptions::default()
694 },
695 );
696
697 src.connect(&conv);
698 conv.connect(&context.destination());
699 src.start();
700
701 let result = context.start_rendering_sync();
702
703 let mut expected = [0.; 128];
704 expected[1] = 1.;
705
706 assert_float_eq!(
707 result.get_channel_data(0)[..],
708 expected[..],
709 abs_all <= 1e-7
710 );
711 }
712
713 #[test]
714 fn test_channel_config_1_chan_in_2_chan_ir() {
715 let number_of_channels = 2;
716 let length = 128;
717 let sample_rate = 44100.;
718 let mut context = OfflineAudioContext::new(number_of_channels, length, sample_rate);
719
720 let input = AudioBuffer::from(vec![vec![1.]], sample_rate);
721 let ir = AudioBuffer::from(vec![vec![0., 1., 0.], vec![0., 0., 1.]], sample_rate);
722
723 let mut src = AudioBufferSourceNode::new(
724 &context,
725 AudioBufferSourceOptions {
726 buffer: Some(input),
727 ..AudioBufferSourceOptions::default()
728 },
729 );
730
731 let conv = ConvolverNode::new(
732 &context,
733 ConvolverOptions {
734 buffer: Some(ir),
735 disable_normalization: true,
736 ..ConvolverOptions::default()
737 },
738 );
739
740 src.connect(&conv);
741 conv.connect(&context.destination());
742 src.start();
743
744 let result = context.start_rendering_sync();
745
746 let mut expected_left = [0.; 128];
747 expected_left[1] = 1.;
748
749 let mut expected_right = [0.; 128];
750 expected_right[2] = 1.;
751
752 assert_eq!(result.number_of_channels(), 2);
753 assert_float_eq!(
754 result.get_channel_data(0)[..],
755 expected_left[..],
756 abs_all <= 1e-7
757 );
758 assert_float_eq!(
759 result.get_channel_data(1)[..],
760 expected_right[..],
761 abs_all <= 1e-7
762 );
763 }
764
765 #[test]
766 fn test_channel_config_2_chan_in_1_chan_ir() {
767 let number_of_channels = 2;
768 let length = 128;
769 let sample_rate = 44100.;
770 let mut context = OfflineAudioContext::new(number_of_channels, length, sample_rate);
771
772 let input = AudioBuffer::from(vec![vec![1., 0.], vec![0., 1.]], sample_rate);
773 let ir = AudioBuffer::from(vec![vec![0., 1.]], sample_rate);
774
775 let mut src = AudioBufferSourceNode::new(
776 &context,
777 AudioBufferSourceOptions {
778 buffer: Some(input),
779 ..AudioBufferSourceOptions::default()
780 },
781 );
782
783 let conv = ConvolverNode::new(
784 &context,
785 ConvolverOptions {
786 buffer: Some(ir),
787 disable_normalization: true,
788 ..ConvolverOptions::default()
789 },
790 );
791
792 src.connect(&conv);
793 conv.connect(&context.destination());
794 src.start();
795
796 let result = context.start_rendering_sync();
797
798 let mut expected_left = [0.; 128];
799 expected_left[1] = 1.;
800
801 let mut expected_right = [0.; 128];
802 expected_right[2] = 1.;
803
804 assert_eq!(result.number_of_channels(), 2);
805 assert_float_eq!(
806 result.get_channel_data(0)[..],
807 expected_left[..],
808 abs_all <= 1e-7
809 );
810 assert_float_eq!(
811 result.get_channel_data(1)[..],
812 expected_right[..],
813 abs_all <= 1e-7
814 );
815 }
816
817 #[test]
818 fn test_channel_config_2_chan_in_2_chan_ir() {
819 let number_of_channels = 2;
820 let length = 128;
821 let sample_rate = 44100.;
822 let mut context = OfflineAudioContext::new(number_of_channels, length, sample_rate);
823
824 let input = AudioBuffer::from(vec![vec![1., 0.], vec![0., 1.]], sample_rate);
825 let ir = AudioBuffer::from(vec![vec![0., 1., 0.], vec![0., 0., 1.]], sample_rate);
826
827 let mut src = AudioBufferSourceNode::new(
828 &context,
829 AudioBufferSourceOptions {
830 buffer: Some(input),
831 ..AudioBufferSourceOptions::default()
832 },
833 );
834
835 let conv = ConvolverNode::new(
836 &context,
837 ConvolverOptions {
838 buffer: Some(ir),
839 disable_normalization: true,
840 ..ConvolverOptions::default()
841 },
842 );
843
844 src.connect(&conv);
845 conv.connect(&context.destination());
846 src.start();
847
848 let result = context.start_rendering_sync();
849
850 let mut expected_left = [0.; 128];
851 expected_left[1] = 1.;
852
853 let mut expected_right = [0.; 128];
854 expected_right[3] = 1.;
855
856 assert_eq!(result.number_of_channels(), 2);
857 assert_float_eq!(
858 result.get_channel_data(0)[..],
859 expected_left[..],
860 abs_all <= 1e-7
861 );
862 assert_float_eq!(
863 result.get_channel_data(1)[..],
864 expected_right[..],
865 abs_all <= 1e-7
866 );
867 }
868
869 #[test]
870 fn test_channel_config_2_chan_in_4_chan_ir() {
871 let number_of_channels = 2;
872 let length = 128;
873 let sample_rate = 44100.;
874 let mut context = OfflineAudioContext::new(number_of_channels, length, sample_rate);
875
876 let input = AudioBuffer::from(vec![vec![1., 0.], vec![0., 1.]], sample_rate);
877 let ir = AudioBuffer::from(
878 vec![
879 vec![0., 1., 0., 0., 0.], vec![0., 0., 1., 0., 0.], vec![0., 0., 0., 1., 0.], vec![0., 0., 0., 0., 1.], ],
884 sample_rate,
885 );
886
887 let mut src = AudioBufferSourceNode::new(
888 &context,
889 AudioBufferSourceOptions {
890 buffer: Some(input),
891 ..AudioBufferSourceOptions::default()
892 },
893 );
894
895 let conv = ConvolverNode::new(
896 &context,
897 ConvolverOptions {
898 buffer: Some(ir),
899 disable_normalization: true,
900 ..ConvolverOptions::default()
901 },
902 );
903
904 src.connect(&conv);
905 conv.connect(&context.destination());
906 src.start();
907
908 let result = context.start_rendering_sync();
909
910 let mut expected_left = [0.; 128];
911 expected_left[1] = 1.;
912 expected_left[4] = 1.;
913
914 let mut expected_right = [0.; 128];
915 expected_right[2] = 1.;
916 expected_right[5] = 1.;
917
918 assert_eq!(result.number_of_channels(), 2);
919 assert_float_eq!(
920 result.get_channel_data(0)[..],
921 expected_left[..],
922 abs_all <= 1e-7
923 );
924 assert_float_eq!(
925 result.get_channel_data(1)[..],
926 expected_right[..],
927 abs_all <= 1e-7
928 );
929 }
930
931 #[test]
932 fn test_channel_config_1_chan_in_4_chan_ir() {
933 let number_of_channels = 2;
934 let length = 128;
935 let sample_rate = 44100.;
936 let mut context = OfflineAudioContext::new(number_of_channels, length, sample_rate);
937
938 let input = AudioBuffer::from(vec![vec![1., 0.]], sample_rate);
939 let ir = AudioBuffer::from(
940 vec![
941 vec![0., 1., 0., 0., 0.], vec![0., 0., 1., 0., 0.], vec![0., 0., 0., 1., 0.], vec![0., 0., 0., 0., 1.], ],
946 sample_rate,
947 );
948
949 let mut src = AudioBufferSourceNode::new(
950 &context,
951 AudioBufferSourceOptions {
952 buffer: Some(input),
953 ..AudioBufferSourceOptions::default()
954 },
955 );
956
957 let conv = ConvolverNode::new(
958 &context,
959 ConvolverOptions {
960 buffer: Some(ir),
961 disable_normalization: true,
962 ..ConvolverOptions::default()
963 },
964 );
965
966 src.connect(&conv);
967 conv.connect(&context.destination());
968 src.start();
969
970 let result = context.start_rendering_sync();
971
972 let mut expected_left = [0.; 128];
973 expected_left[1] = 1.;
974 expected_left[3] = 1.;
975
976 let mut expected_right = [0.; 128];
977 expected_right[2] = 1.;
978 expected_right[4] = 1.;
979
980 assert_eq!(result.number_of_channels(), 2);
981 assert_float_eq!(
982 result.get_channel_data(0)[..],
983 expected_left[..],
984 abs_all <= 1e-7
985 );
986 assert_float_eq!(
987 result.get_channel_data(1)[..],
988 expected_right[..],
989 abs_all <= 1e-7
990 );
991 }
992}