bbx_dsp/blocks/effectors/
channel_merger.rs1use std::marker::PhantomData;
4
5use crate::{
6 block::Block, channel::ChannelConfig, context::DspContext, graph::MAX_BLOCK_OUTPUTS, parameter::ModulationOutput,
7 sample::Sample,
8};
9
10pub struct ChannelMergerBlock<S: Sample> {
20 channel_count: usize,
21 _phantom: PhantomData<S>,
22}
23
24impl<S: Sample> ChannelMergerBlock<S> {
25 pub fn new(channels: usize) -> Self {
30 assert!(channels > 0 && channels <= MAX_BLOCK_OUTPUTS);
31 Self {
32 channel_count: channels,
33 _phantom: PhantomData,
34 }
35 }
36
37 pub fn channel_count(&self) -> usize {
39 self.channel_count
40 }
41}
42
43impl<S: Sample> Block<S> for ChannelMergerBlock<S> {
44 fn process(&mut self, inputs: &[&[S]], outputs: &mut [&mut [S]], _modulation_values: &[S], _context: &DspContext) {
45 let num_channels = self.channel_count.min(inputs.len()).min(outputs.len());
46
47 for ch in 0..num_channels {
48 let input = inputs[ch];
49 let output = &mut outputs[ch];
50 let num_samples = input.len().min(output.len());
51
52 output[..num_samples].copy_from_slice(&input[..num_samples]);
53 }
54 }
55
56 #[inline]
57 fn input_count(&self) -> usize {
58 self.channel_count
59 }
60
61 #[inline]
62 fn output_count(&self) -> usize {
63 self.channel_count
64 }
65
66 #[inline]
67 fn modulation_outputs(&self) -> &[ModulationOutput] {
68 &[]
69 }
70
71 #[inline]
72 fn channel_config(&self) -> ChannelConfig {
73 ChannelConfig::Explicit
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::channel::ChannelLayout;
81
82 fn test_context() -> DspContext {
83 DspContext {
84 sample_rate: 44100.0,
85 num_channels: 2,
86 buffer_size: 4,
87 current_sample: 0,
88 channel_layout: ChannelLayout::Stereo,
89 }
90 }
91
92 #[test]
93 fn test_channel_merger_stereo() {
94 let mut merger = ChannelMergerBlock::<f32>::new(2);
95 let context = test_context();
96
97 let left_in = [1.0f32, 2.0, 3.0, 4.0];
98 let right_in = [5.0f32, 6.0, 7.0, 8.0];
99 let mut left_out = [0.0f32; 4];
100 let mut right_out = [0.0f32; 4];
101
102 let inputs: [&[f32]; 2] = [&left_in, &right_in];
103 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
104
105 merger.process(&inputs, &mut outputs, &[], &context);
106
107 assert_eq!(left_out, left_in);
108 assert_eq!(right_out, right_in);
109 }
110
111 #[test]
112 fn test_channel_merger_quad() {
113 let merger = ChannelMergerBlock::<f32>::new(4);
114 assert_eq!(merger.input_count(), 4);
115 assert_eq!(merger.output_count(), 4);
116 assert_eq!(merger.channel_config(), ChannelConfig::Explicit);
117 }
118
119 #[test]
120 #[should_panic]
121 fn test_channel_merger_zero_channels_panics() {
122 let _ = ChannelMergerBlock::<f32>::new(0);
123 }
124
125 #[test]
126 #[should_panic]
127 fn test_channel_merger_too_many_channels_panics() {
128 let _ = ChannelMergerBlock::<f32>::new(17);
129 }
130}