use alloc::vec::Vec;
use super::filter::Chain;
use super::{AudioBuffer, StreamInfo};
#[derive(Debug, Clone)]
struct Channel {
chain: Chain,
sum: f32,
count: u32,
held: f32,
}
#[derive(Debug, Clone)]
pub struct Resampler {
channels: Vec<Channel>,
step: u64,
period: u64,
phase: u64,
frame: Vec<f32>,
}
impl Resampler {
#[must_use]
pub fn new(info: StreamInfo, out_rate: u32) -> Resampler {
let channels = usize::from(info.channels);
let chain = Chain::for_stream(info);
Resampler {
channels: (0..channels)
.map(|_| Channel {
chain: chain.clone(),
sum: 0.0,
count: 0,
held: 0.0,
})
.collect(),
step: u64::from(out_rate.max(1)).saturating_mul(info.rate_den.max(1)),
period: info.rate_num.max(1),
phase: 0,
frame: alloc::vec![0.0; channels],
}
}
#[must_use]
pub fn channels(&self) -> usize {
self.channels.len()
}
#[must_use]
pub const fn ratio(&self) -> (u64, u64) {
(self.period, self.step)
}
pub fn reset(&mut self) {
self.phase = 0;
for channel in &mut self.channels {
channel.chain.reset();
channel.sum = 0.0;
channel.count = 0;
channel.held = 0.0;
}
}
pub fn process(&mut self, input: &[i16], out: &mut AudioBuffer) {
let channels = self.channels.len();
if channels == 0 || input.is_empty() {
return;
}
for chunk in input.chunks_exact(channels) {
for (channel, sample) in self.channels.iter_mut().zip(chunk) {
let x = f32::from(*sample) / 32768.0;
channel.sum += channel.chain.step(x);
channel.count += 1;
}
self.phase += self.step;
while self.phase >= self.period {
self.phase -= self.period;
for (slot, channel) in self.frame.iter_mut().zip(self.channels.iter_mut()) {
if channel.count > 0 {
channel.held = channel.sum / channel.count as f32;
channel.sum = 0.0;
channel.count = 0;
}
*slot = channel.held;
}
out.push_normalised(&self.frame);
}
}
}
}