audio_mixer/
lib.rs

1#[macro_use]
2extern crate bitflags;
3
4mod channel;
5mod coefficient;
6
7// Export Channel outside.
8pub use channel::Channel;
9use coefficient::{Coefficient, MixingCoefficient};
10
11use std::default::Default;
12use std::fmt::Debug;
13use std::ops::{AddAssign, Mul};
14
15// A mixer mixing M-channel input data to N-channel output data.
16// T::Coef is an associated type defined in MixingCoefficient, which indicates the type of the
17// mixing coefficient that would be used for type T. When T is f32, the T::Coef is f32. When T
18// is i16, the T::Coef is i32. When mixing data, a temporary variable with type T::Coef would be
19// created to hold the mixing result. Since the type of input and output audio data is T,
20// the methods provided from MixingCoefficient trait would be used to convert the value between
21// type T and T::Coef.
22#[derive(Debug)]
23pub struct Mixer<T>
24where
25    T: Copy + Debug + MixingCoefficient,
26    T::Coef: AddAssign + Copy + Debug + Default + Mul<T::Coef, Output = T::Coef>,
27{
28    coefficient: Coefficient<T>,
29}
30
31impl<T> Mixer<T>
32where
33    T: Copy + Debug + MixingCoefficient,
34    T::Coef: AddAssign + Copy + Debug + Default + Mul<T::Coef, Output = T::Coef>,
35{
36    pub fn new(input_channels: &[Channel], output_channels: &[Channel]) -> Self {
37        Self {
38            coefficient: Coefficient::create(input_channels, output_channels),
39        }
40    }
41
42    // To mix M-channel audio input data to N-channel output data, the data in output-channel i
43    // is the sum of product of data in input-channel j and the coefficient for mixing from
44    // input-channel j to output-channel i, for all j in M channels. That is,
45    // output_data(i) = Σ coefficient(j, i) * input_data(j), for all j in [0, M),
46    // where i is in [0, N) and coefficient is a function returning mixing coefficient from
47    // input channel j to output channel i.
48    pub fn mix(&self, input_buffer: &[T], output_buffer: &mut [T]) {
49        assert_eq!(
50            input_buffer.len(),
51            self.input_channels().len(),
52            "input slice must have the same size as the input channel's one."
53        );
54        assert_eq!(
55            output_buffer.len(),
56            self.output_channels().len(),
57            "output slice must have the same size as the output channel's one."
58        );
59        for (i, output) in output_buffer.iter_mut().enumerate() {
60            // T must implement Default that returns a zero value from default().
61            let mut value = T::Coef::default(); // Create a zero value.
62            for (j, input) in input_buffer.iter().enumerate() {
63                // T::Coef needs to implement `AddAssign` and `Mul` to make `+=` and `*` work.
64                // T needs to implement `Copy` so `*input` can be copied.
65                value += self.coefficient.get(j, i) * T::to_coefficient_value(*input);
66            }
67            *output = T::from_coefficient_value(
68                value,
69                self.coefficient.would_overflow_from_coefficient_value(),
70            );
71        }
72    }
73
74    pub fn input_channels(&self) -> &[Channel] {
75        self.coefficient.input_channels()
76    }
77
78    pub fn output_channels(&self) -> &[Channel] {
79        self.coefficient.output_channels()
80    }
81}