1use std::marker::PhantomData;
4
5use crate::{block::Block, channel::ChannelConfig, context::DspContext, parameter::ModulationOutput, sample::Sample};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9#[repr(u8)]
10pub enum ChannelMode {
11 #[default]
13 Stereo = 0,
14 Left = 1,
16 Right = 2,
18 Swap = 3,
20}
21
22impl From<i32> for ChannelMode {
23 fn from(value: i32) -> Self {
24 match value {
25 0 => Self::Stereo,
26 1 => Self::Left,
27 2 => Self::Right,
28 3 => Self::Swap,
29 _ => Self::Stereo,
30 }
31 }
32}
33
34impl From<f32> for ChannelMode {
35 fn from(value: f32) -> Self {
36 Self::from(value as i32)
37 }
38}
39
40pub struct ChannelRouterBlock<S: Sample> {
44 pub mode: ChannelMode,
46 pub mono: bool,
48 pub invert_left: bool,
50 pub invert_right: bool,
52
53 _phantom: PhantomData<S>,
54}
55
56impl<S: Sample> ChannelRouterBlock<S> {
57 pub fn new(mode: ChannelMode, mono: bool, invert_left: bool, invert_right: bool) -> Self {
59 Self {
60 mode,
61 mono,
62 invert_left,
63 invert_right,
64 _phantom: PhantomData,
65 }
66 }
67
68 pub fn default_new() -> Self {
70 Self::new(ChannelMode::Stereo, false, false, false)
71 }
72}
73
74impl<S: Sample> Block<S> for ChannelRouterBlock<S> {
75 fn process(&mut self, inputs: &[&[S]], outputs: &mut [&mut [S]], _modulation_values: &[S], _context: &DspContext) {
76 if inputs.is_empty() {
78 return;
79 }
80
81 let left_in = inputs.first().copied();
82 let right_in = inputs.get(1).copied().or(left_in);
83
84 let (left_in, right_in) = match (left_in, right_in) {
85 (Some(l), Some(r)) => (l, r),
86 _ => return,
87 };
88
89 let num_samples = left_in.len().min(outputs.first().map(|o| o.len()).unwrap_or(0));
90
91 if num_samples == 0 {
92 return;
93 }
94
95 let half = S::from_f64(0.5);
96
97 for i in 0..num_samples {
98 let l_sample = left_in[i];
99 let r_sample = if inputs.len() > 1 { right_in[i] } else { l_sample };
100
101 let (mut l_out, mut r_out) = match self.mode {
102 ChannelMode::Stereo => (l_sample, r_sample),
103 ChannelMode::Left => (l_sample, l_sample),
104 ChannelMode::Right => (r_sample, r_sample),
105 ChannelMode::Swap => (r_sample, l_sample),
106 };
107
108 if self.mono {
109 let mono = (l_out + r_out) * half;
110 l_out = mono;
111 r_out = mono;
112 }
113
114 if self.invert_left {
115 l_out = -l_out;
116 }
117 if self.invert_right {
118 r_out = -r_out;
119 }
120
121 if !outputs.is_empty() {
122 outputs[0][i] = l_out;
123 }
124 if outputs.len() > 1 {
125 outputs[1][i] = r_out;
126 }
127 }
128 }
129
130 #[inline]
131 fn input_count(&self) -> usize {
132 2 }
134
135 #[inline]
136 fn output_count(&self) -> usize {
137 2 }
139
140 #[inline]
141 fn modulation_outputs(&self) -> &[ModulationOutput] {
142 &[]
143 }
144
145 #[inline]
146 fn channel_config(&self) -> ChannelConfig {
147 ChannelConfig::Explicit
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use crate::channel::ChannelLayout;
155
156 fn test_context(buffer_size: usize) -> DspContext {
157 DspContext {
158 sample_rate: 44100.0,
159 num_channels: 2,
160 buffer_size,
161 current_sample: 0,
162 channel_layout: ChannelLayout::Stereo,
163 }
164 }
165
166 #[test]
167 fn test_channel_router_input_output_counts_f32() {
168 let router = ChannelRouterBlock::<f32>::default_new();
169 assert_eq!(router.input_count(), 2);
170 assert_eq!(router.output_count(), 2);
171 }
172
173 #[test]
174 fn test_channel_router_input_output_counts_f64() {
175 let router = ChannelRouterBlock::<f64>::default_new();
176 assert_eq!(router.input_count(), 2);
177 assert_eq!(router.output_count(), 2);
178 }
179
180 #[test]
181 fn test_channel_router_returns_explicit_config() {
182 let router = ChannelRouterBlock::<f32>::default_new();
183 assert_eq!(router.channel_config(), ChannelConfig::Explicit);
184 }
185
186 #[test]
187 fn test_channel_router_stereo_passthrough_f32() {
188 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Stereo, false, false, false);
189 let context = test_context(4);
190
191 let left_in = [1.0f32, 2.0, 3.0, 4.0];
192 let right_in = [5.0f32, 6.0, 7.0, 8.0];
193 let mut left_out = [0.0f32; 4];
194 let mut right_out = [0.0f32; 4];
195
196 let inputs: [&[f32]; 2] = [&left_in, &right_in];
197 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
198
199 router.process(&inputs, &mut outputs, &[], &context);
200
201 assert_eq!(left_out, left_in);
202 assert_eq!(right_out, right_in);
203 }
204
205 #[test]
206 fn test_channel_router_stereo_passthrough_f64() {
207 let mut router = ChannelRouterBlock::<f64>::new(ChannelMode::Stereo, false, false, false);
208 let context = test_context(4);
209
210 let left_in = [1.0f64, 2.0, 3.0, 4.0];
211 let right_in = [5.0f64, 6.0, 7.0, 8.0];
212 let mut left_out = [0.0f64; 4];
213 let mut right_out = [0.0f64; 4];
214
215 let inputs: [&[f64]; 2] = [&left_in, &right_in];
216 let mut outputs: [&mut [f64]; 2] = [&mut left_out, &mut right_out];
217
218 router.process(&inputs, &mut outputs, &[], &context);
219
220 assert_eq!(left_out, left_in);
221 assert_eq!(right_out, right_in);
222 }
223
224 #[test]
225 fn test_channel_router_left_mode_f32() {
226 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Left, false, false, false);
227 let context = test_context(4);
228
229 let left_in = [1.0f32, 2.0, 3.0, 4.0];
230 let right_in = [5.0f32, 6.0, 7.0, 8.0];
231 let mut left_out = [0.0f32; 4];
232 let mut right_out = [0.0f32; 4];
233
234 let inputs: [&[f32]; 2] = [&left_in, &right_in];
235 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
236
237 router.process(&inputs, &mut outputs, &[], &context);
238
239 assert_eq!(left_out, left_in);
240 assert_eq!(right_out, left_in);
241 }
242
243 #[test]
244 fn test_channel_router_right_mode_f32() {
245 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Right, false, false, false);
246 let context = test_context(4);
247
248 let left_in = [1.0f32, 2.0, 3.0, 4.0];
249 let right_in = [5.0f32, 6.0, 7.0, 8.0];
250 let mut left_out = [0.0f32; 4];
251 let mut right_out = [0.0f32; 4];
252
253 let inputs: [&[f32]; 2] = [&left_in, &right_in];
254 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
255
256 router.process(&inputs, &mut outputs, &[], &context);
257
258 assert_eq!(left_out, right_in);
259 assert_eq!(right_out, right_in);
260 }
261
262 #[test]
263 fn test_channel_router_swap_mode_f32() {
264 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Swap, false, false, false);
265 let context = test_context(4);
266
267 let left_in = [1.0f32, 2.0, 3.0, 4.0];
268 let right_in = [5.0f32, 6.0, 7.0, 8.0];
269 let mut left_out = [0.0f32; 4];
270 let mut right_out = [0.0f32; 4];
271
272 let inputs: [&[f32]; 2] = [&left_in, &right_in];
273 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
274
275 router.process(&inputs, &mut outputs, &[], &context);
276
277 assert_eq!(left_out, right_in);
278 assert_eq!(right_out, left_in);
279 }
280
281 #[test]
282 fn test_channel_router_mono_sum_f32() {
283 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Stereo, true, false, false);
284 let context = test_context(4);
285
286 let left_in = [2.0f32, 4.0, 6.0, 8.0];
287 let right_in = [4.0f32, 6.0, 8.0, 10.0];
288 let mut left_out = [0.0f32; 4];
289 let mut right_out = [0.0f32; 4];
290
291 let inputs: [&[f32]; 2] = [&left_in, &right_in];
292 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
293
294 router.process(&inputs, &mut outputs, &[], &context);
295
296 let expected = [3.0f32, 5.0, 7.0, 9.0];
297 for i in 0..4 {
298 assert!((left_out[i] - expected[i]).abs() < 1e-6);
299 assert!((right_out[i] - expected[i]).abs() < 1e-6);
300 }
301 }
302
303 #[test]
304 fn test_channel_router_invert_left_f32() {
305 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Stereo, false, true, false);
306 let context = test_context(4);
307
308 let left_in = [1.0f32, 2.0, 3.0, 4.0];
309 let right_in = [5.0f32, 6.0, 7.0, 8.0];
310 let mut left_out = [0.0f32; 4];
311 let mut right_out = [0.0f32; 4];
312
313 let inputs: [&[f32]; 2] = [&left_in, &right_in];
314 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
315
316 router.process(&inputs, &mut outputs, &[], &context);
317
318 let expected_left = [-1.0f32, -2.0, -3.0, -4.0];
319 assert_eq!(left_out, expected_left);
320 assert_eq!(right_out, right_in);
321 }
322
323 #[test]
324 fn test_channel_router_invert_right_f32() {
325 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Stereo, false, false, true);
326 let context = test_context(4);
327
328 let left_in = [1.0f32, 2.0, 3.0, 4.0];
329 let right_in = [5.0f32, 6.0, 7.0, 8.0];
330 let mut left_out = [0.0f32; 4];
331 let mut right_out = [0.0f32; 4];
332
333 let inputs: [&[f32]; 2] = [&left_in, &right_in];
334 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
335
336 router.process(&inputs, &mut outputs, &[], &context);
337
338 let expected_right = [-5.0f32, -6.0, -7.0, -8.0];
339 assert_eq!(left_out, left_in);
340 assert_eq!(right_out, expected_right);
341 }
342
343 #[test]
344 fn test_channel_router_invert_both_f32() {
345 let mut router = ChannelRouterBlock::<f32>::new(ChannelMode::Stereo, false, true, true);
346 let context = test_context(4);
347
348 let left_in = [1.0f32, 2.0, 3.0, 4.0];
349 let right_in = [5.0f32, 6.0, 7.0, 8.0];
350 let mut left_out = [0.0f32; 4];
351 let mut right_out = [0.0f32; 4];
352
353 let inputs: [&[f32]; 2] = [&left_in, &right_in];
354 let mut outputs: [&mut [f32]; 2] = [&mut left_out, &mut right_out];
355
356 router.process(&inputs, &mut outputs, &[], &context);
357
358 let expected_left = [-1.0f32, -2.0, -3.0, -4.0];
359 let expected_right = [-5.0f32, -6.0, -7.0, -8.0];
360 assert_eq!(left_out, expected_left);
361 assert_eq!(right_out, expected_right);
362 }
363
364 #[test]
365 fn test_channel_mode_from_i32() {
366 assert_eq!(ChannelMode::from(0), ChannelMode::Stereo);
367 assert_eq!(ChannelMode::from(1), ChannelMode::Left);
368 assert_eq!(ChannelMode::from(2), ChannelMode::Right);
369 assert_eq!(ChannelMode::from(3), ChannelMode::Swap);
370 assert_eq!(ChannelMode::from(999), ChannelMode::Stereo);
371 }
372
373 #[test]
374 fn test_channel_mode_from_f32() {
375 assert_eq!(ChannelMode::from(0.0f32), ChannelMode::Stereo);
376 assert_eq!(ChannelMode::from(1.0f32), ChannelMode::Left);
377 assert_eq!(ChannelMode::from(2.0f32), ChannelMode::Right);
378 assert_eq!(ChannelMode::from(3.0f32), ChannelMode::Swap);
379 }
380}