diff options
Diffstat (limited to 'third_party/rust/audio-mixer/src/lib.rs')
-rw-r--r-- | third_party/rust/audio-mixer/src/lib.rs | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/third_party/rust/audio-mixer/src/lib.rs b/third_party/rust/audio-mixer/src/lib.rs new file mode 100644 index 0000000000..10bf54603e --- /dev/null +++ b/third_party/rust/audio-mixer/src/lib.rs @@ -0,0 +1,81 @@ +#[macro_use] +extern crate bitflags; + +mod channel; +mod coefficient; + +// Export Channel outside. +pub use channel::Channel; +use coefficient::{Coefficient, MixingCoefficient}; + +use std::default::Default; +use std::fmt::Debug; +use std::ops::{AddAssign, Mul}; + +// A mixer mixing M-channel input data to N-channel output data. +// T::Coef is an associated type defined in MixingCoefficient, which indicates the type of the +// mixing coefficient that would be used for type T. When T is f32, the T::Coef is f32. When T +// is i16, the T::Coef is i32. When mixing data, a temporary variable with type T::Coef would be +// created to hold the mixing result. Since the type of input and output audio data is T, +// the methods provided from MixingCoefficient trait would be used to convert the value between +// type T and T::Coef. +#[derive(Debug)] +pub struct Mixer<T> +where + T: Copy + Debug + MixingCoefficient, + T::Coef: AddAssign + Copy + Debug + Default + Mul<T::Coef, Output = T::Coef>, +{ + coefficient: Coefficient<T>, +} + +impl<T> Mixer<T> +where + T: Copy + Debug + MixingCoefficient, + T::Coef: AddAssign + Copy + Debug + Default + Mul<T::Coef, Output = T::Coef>, +{ + pub fn new(input_channels: &[Channel], output_channels: &[Channel]) -> Self { + Self { + coefficient: Coefficient::create(input_channels, output_channels), + } + } + + // To mix M-channel audio input data to N-channel output data, the data in output-channel i + // is the sum of product of data in input-channel j and the coefficient for mixing from + // input-channel j to output-channel i, for all j in M channels. That is, + // output_data(i) = Σ coefficient(j, i) * input_data(j), for all j in [0, M), + // where i is in [0, N) and coefficient is a function returning mixing coefficient from + // input channel j to output channel i. + pub fn mix(&self, input_buffer: &[T], output_buffer: &mut [T]) { + assert_eq!( + input_buffer.len(), + self.input_channels().len(), + "input slice must have the same size as the input channel's one." + ); + assert_eq!( + output_buffer.len(), + self.output_channels().len(), + "output slice must have the same size as the output channel's one." + ); + for (i, output) in output_buffer.iter_mut().enumerate() { + // T must implement Default that returns a zero value from default(). + let mut value = T::Coef::default(); // Create a zero value. + for (j, input) in input_buffer.iter().enumerate() { + // T::Coef needs to implement `AddAssign` and `Mul` to make `+=` and `*` work. + // T needs to implement `Copy` so `*input` can be copied. + value += self.coefficient.get(j, i) * T::to_coefficient_value(*input); + } + *output = T::from_coefficient_value( + value, + self.coefficient.would_overflow_from_coefficient_value(), + ); + } + } + + pub fn input_channels(&self) -> &[Channel] { + &self.coefficient.input_channels() + } + + pub fn output_channels(&self) -> &[Channel] { + &self.coefficient.output_channels() + } +} |