use crate::sample::Sample;
use crate::types::{MAX_AUX_BUSES, MAX_CHANNELS};
pub struct Buffer<'a, S: Sample = f32> {
inputs: [Option<&'a [S]>; MAX_CHANNELS],
outputs: [Option<&'a mut [S]>; MAX_CHANNELS],
num_input_channels: usize,
num_output_channels: usize,
num_samples: usize,
}
impl<'a, S: Sample> Buffer<'a, S> {
#[inline]
pub fn new(
inputs: impl IntoIterator<Item = &'a [S]>,
outputs: impl IntoIterator<Item = &'a mut [S]>,
num_samples: usize,
) -> Self {
let mut input_arr: [Option<&'a [S]>; MAX_CHANNELS] = [None; MAX_CHANNELS];
let mut num_input_channels = 0;
for (i, slice) in inputs.into_iter().take(MAX_CHANNELS).enumerate() {
input_arr[i] = Some(slice);
num_input_channels = i + 1;
}
let mut output_arr: [Option<&'a mut [S]>; MAX_CHANNELS] = std::array::from_fn(|_| None);
let mut num_output_channels = 0;
for (i, slice) in outputs.into_iter().take(MAX_CHANNELS).enumerate() {
output_arr[i] = Some(slice);
num_output_channels = i + 1;
}
Self {
inputs: input_arr,
outputs: output_arr,
num_input_channels,
num_output_channels,
num_samples,
}
}
#[inline]
pub fn num_samples(&self) -> usize {
self.num_samples
}
#[inline]
pub fn num_input_channels(&self) -> usize {
self.num_input_channels
}
#[inline]
pub fn num_output_channels(&self) -> usize {
self.num_output_channels
}
#[inline]
pub fn is_stereo(&self) -> bool {
self.num_input_channels == 2 && self.num_output_channels == 2
}
#[inline]
pub fn is_mono(&self) -> bool {
self.num_input_channels == 1 && self.num_output_channels == 1
}
#[inline]
pub fn input(&self, channel: usize) -> &[S] {
self.inputs
.get(channel)
.and_then(|opt| opt.as_ref())
.map(|ch| &ch[..self.num_samples])
.unwrap_or(&[])
}
#[inline]
pub fn output(&mut self, channel: usize) -> &mut [S] {
let n = self.num_samples;
self.outputs[channel]
.as_mut()
.map(|ch| &mut ch[..n])
.expect("output channel out of bounds")
}
#[inline]
pub fn output_checked(&mut self, channel: usize) -> Option<&mut [S]> {
let n = self.num_samples;
self.outputs
.get_mut(channel)
.and_then(|opt| opt.as_mut())
.map(|ch| &mut ch[..n])
}
#[inline]
pub fn inputs(&self) -> impl Iterator<Item = &[S]> + '_ {
let n = self.num_samples;
self.inputs[..self.num_input_channels]
.iter()
.filter_map(move |opt| opt.as_ref().map(|ch| &ch[..n]))
}
#[inline]
pub fn outputs_mut(&mut self) -> impl Iterator<Item = &mut [S]> + use<'_, 'a, S> {
let n = self.num_samples;
self.outputs[..self.num_output_channels]
.iter_mut()
.filter_map(move |opt| opt.as_mut().map(|ch| &mut ch[..n]))
}
#[inline]
pub fn zip_channels(&mut self) -> impl Iterator<Item = (&[S], &mut [S])> + use<'_, 'a, S> {
let n = self.num_samples;
let num_pairs = self.num_input_channels.min(self.num_output_channels);
self.inputs[..num_pairs]
.iter()
.zip(self.outputs[..num_pairs].iter_mut())
.filter_map(move |(i_opt, o_opt)| {
match (i_opt.as_ref(), o_opt.as_mut()) {
(Some(i), Some(o)) => Some((&i[..n], &mut o[..n])),
_ => None,
}
})
}
pub fn copy_to_output(&mut self) {
let num_channels = self.num_input_channels.min(self.num_output_channels);
let n = self.num_samples;
for ch in 0..num_channels {
if let (Some(input), Some(output)) = (self.inputs[ch].as_ref(), self.outputs[ch].as_mut()) {
output[..n].copy_from_slice(&input[..n]);
}
}
}
pub fn clear_outputs(&mut self) {
let n = self.num_samples;
for opt in self.outputs[..self.num_output_channels].iter_mut() {
if let Some(output) = opt.as_mut() {
output[..n].fill(S::ZERO);
}
}
}
pub fn apply_output_gain(&mut self, gain: S) {
let n = self.num_samples;
for opt in self.outputs[..self.num_output_channels].iter_mut() {
if let Some(output) = opt.as_mut() {
for sample in &mut output[..n] {
*sample = *sample * gain;
}
}
}
}
}
pub struct AuxiliaryBuffers<'a, S: Sample = f32> {
inputs: [[Option<&'a [S]>; MAX_CHANNELS]; MAX_AUX_BUSES],
input_channel_counts: [usize; MAX_AUX_BUSES],
num_input_buses: usize,
outputs: [[Option<&'a mut [S]>; MAX_CHANNELS]; MAX_AUX_BUSES],
output_channel_counts: [usize; MAX_AUX_BUSES],
num_output_buses: usize,
num_samples: usize,
}
impl<'a, S: Sample> AuxiliaryBuffers<'a, S> {
#[inline]
pub fn new(
inputs: impl IntoIterator<Item = impl IntoIterator<Item = &'a [S]>>,
outputs: impl IntoIterator<Item = impl IntoIterator<Item = &'a mut [S]>>,
num_samples: usize,
) -> Self {
let mut input_arr: [[Option<&'a [S]>; MAX_CHANNELS]; MAX_AUX_BUSES] =
[[None; MAX_CHANNELS]; MAX_AUX_BUSES];
let mut input_channel_counts = [0usize; MAX_AUX_BUSES];
let mut num_input_buses = 0;
for (bus_idx, bus) in inputs.into_iter().take(MAX_AUX_BUSES).enumerate() {
let mut ch_count = 0;
for (ch_idx, slice) in bus.into_iter().take(MAX_CHANNELS).enumerate() {
input_arr[bus_idx][ch_idx] = Some(slice);
ch_count = ch_idx + 1;
}
input_channel_counts[bus_idx] = ch_count;
if ch_count > 0 {
num_input_buses = bus_idx + 1;
}
}
let mut output_arr: [[Option<&'a mut [S]>; MAX_CHANNELS]; MAX_AUX_BUSES] =
std::array::from_fn(|_| std::array::from_fn(|_| None));
let mut output_channel_counts = [0usize; MAX_AUX_BUSES];
let mut num_output_buses = 0;
for (bus_idx, bus) in outputs.into_iter().take(MAX_AUX_BUSES).enumerate() {
let mut ch_count = 0;
for (ch_idx, slice) in bus.into_iter().take(MAX_CHANNELS).enumerate() {
output_arr[bus_idx][ch_idx] = Some(slice);
ch_count = ch_idx + 1;
}
output_channel_counts[bus_idx] = ch_count;
if ch_count > 0 {
num_output_buses = bus_idx + 1;
}
}
Self {
inputs: input_arr,
input_channel_counts,
num_input_buses,
outputs: output_arr,
output_channel_counts,
num_output_buses,
num_samples,
}
}
#[inline]
pub fn empty() -> Self {
Self {
inputs: [[None; MAX_CHANNELS]; MAX_AUX_BUSES],
input_channel_counts: [0; MAX_AUX_BUSES],
num_input_buses: 0,
outputs: std::array::from_fn(|_| std::array::from_fn(|_| None)),
output_channel_counts: [0; MAX_AUX_BUSES],
num_output_buses: 0,
num_samples: 0,
}
}
#[inline]
pub fn num_samples(&self) -> usize {
self.num_samples
}
#[inline]
pub fn num_input_buses(&self) -> usize {
self.num_input_buses
}
#[inline]
pub fn num_output_buses(&self) -> usize {
self.num_output_buses
}
#[inline]
pub fn is_empty(&self) -> bool {
self.num_input_buses == 0 && self.num_output_buses == 0
}
#[inline]
pub fn sidechain(&self) -> Option<AuxInput<'_, S>> {
self.input(0)
}
#[inline]
pub fn input(&self, bus: usize) -> Option<AuxInput<'_, S>> {
if bus >= MAX_AUX_BUSES {
return None;
}
let num_channels = self.input_channel_counts[bus];
if num_channels == 0 {
return None;
}
Some(AuxInput {
channels: &self.inputs[bus][..num_channels],
num_samples: self.num_samples,
})
}
#[inline]
pub fn output(&mut self, bus: usize) -> Option<AuxOutput<'_, 'a, S>> {
if bus >= MAX_AUX_BUSES {
return None;
}
let num_channels = self.output_channel_counts[bus];
if num_channels == 0 {
return None;
}
let num_samples = self.num_samples;
Some(AuxOutput {
channels: &mut self.outputs[bus][..num_channels],
num_samples,
})
}
#[inline]
pub fn iter_inputs(&self) -> impl Iterator<Item = AuxInput<'_, S>> + '_ {
let num_samples = self.num_samples;
self.inputs[..self.num_input_buses]
.iter()
.zip(self.input_channel_counts[..self.num_input_buses].iter())
.filter(|(_, &count)| count > 0)
.map(move |(channels, &count)| AuxInput {
channels: &channels[..count],
num_samples,
})
}
#[inline]
pub fn iter_outputs(&mut self) -> impl Iterator<Item = AuxOutput<'_, 'a, S>> + '_ {
let num_samples = self.num_samples;
let num_buses = self.num_output_buses;
self.outputs[..num_buses]
.iter_mut()
.zip(self.output_channel_counts[..num_buses].iter())
.filter(|(_, &count)| count > 0)
.map(move |(channels, &count)| AuxOutput {
channels: &mut channels[..count],
num_samples,
})
}
}
pub struct AuxInput<'a, S: Sample = f32> {
channels: &'a [Option<&'a [S]>],
num_samples: usize,
}
impl<'a, S: Sample> AuxInput<'a, S> {
#[inline]
pub fn num_samples(&self) -> usize {
self.num_samples
}
#[inline]
pub fn num_channels(&self) -> usize {
self.channels.len()
}
#[inline]
pub fn input(&self, index: usize) -> &[S] {
self.channels
.get(index)
.and_then(|opt| opt.as_ref())
.map(|ch| &ch[..self.num_samples])
.unwrap_or(&[])
}
#[inline]
pub fn sample(&self, channel: usize, index: usize) -> S {
self.input(channel)
.get(index)
.copied()
.unwrap_or(S::ZERO)
}
#[inline]
pub fn iter_inputs(&self) -> impl Iterator<Item = &[S]> + '_ {
let n = self.num_samples;
self.channels
.iter()
.filter_map(move |opt| opt.as_ref().map(|ch| &ch[..n]))
}
pub fn rms(&self, channel: usize) -> S {
let ch = self.input(channel);
if ch.is_empty() {
return S::ZERO;
}
let sum: S = ch.iter().fold(S::ZERO, |acc, &s| acc + s * s);
let len = S::from_f32(ch.len() as f32);
(sum / len).sqrt()
}
pub fn peak(&self, channel: usize) -> S {
self.input(channel)
.iter()
.map(|&s| s.abs())
.fold(S::ZERO, |a, b| a.max(b))
}
pub fn average(&self, channel: usize) -> S {
let ch = self.input(channel);
if ch.is_empty() {
return S::ZERO;
}
let sum: S = ch.iter().map(|&s| s.abs()).fold(S::ZERO, |a, b| a + b);
let len = S::from_f32(ch.len() as f32);
sum / len
}
}
pub struct AuxOutput<'borrow, 'data, S: Sample = f32> {
channels: &'borrow mut [Option<&'data mut [S]>],
num_samples: usize,
}
impl<'borrow, 'data, S: Sample> AuxOutput<'borrow, 'data, S> {
#[inline]
pub fn num_samples(&self) -> usize {
self.num_samples
}
#[inline]
pub fn num_channels(&self) -> usize {
self.channels.len()
}
#[inline]
pub fn output(&mut self, index: usize) -> &mut [S] {
let n = self.num_samples;
self.channels[index]
.as_mut()
.map(|ch| &mut ch[..n])
.expect("aux output channel out of bounds")
}
#[inline]
pub fn output_checked(&mut self, index: usize) -> Option<&mut [S]> {
let n = self.num_samples;
self.channels
.get_mut(index)
.and_then(|opt| opt.as_mut())
.map(|ch| &mut ch[..n])
}
#[inline]
pub fn iter_outputs(&mut self) -> impl Iterator<Item = &mut [S]> + use<'_, 'data, S> {
let n = self.num_samples;
self.channels
.iter_mut()
.filter_map(move |opt| opt.as_mut().map(|ch| &mut ch[..n]))
}
pub fn clear(&mut self) {
let n = self.num_samples;
for opt in self.channels.iter_mut() {
if let Some(ch) = opt.as_mut() {
ch[..n].fill(S::ZERO);
}
}
}
pub fn fill(&mut self, value: S) {
let n = self.num_samples;
for opt in self.channels.iter_mut() {
if let Some(ch) = opt.as_mut() {
ch[..n].fill(value);
}
}
}
}