use rubato::audioadapter_buffers::direct::InterleavedSlice;
use rubato::{Async, FixedAsync, Indexing, Resampler, SincInterpolationParameters, WindowFunction};
const CHUNK: usize = 1024;
const MAX_RATIO_SHIFT: f64 = 2.1;
pub struct Resample {
inner: Async<f32>,
channels: usize,
pending: Vec<f32>,
out_buf: Vec<f32>,
out_max: usize,
delay_left: usize,
}
impl Resample {
pub fn new(rate_in: u32, rate_out: u32, channels: u16, speed: f64) -> Option<Self> {
let channels = channels as usize;
if rate_in == 0 || rate_out == 0 || channels == 0 || speed <= 0.0 {
return None;
}
let ratio = rate_out as f64 / (rate_in as f64 * speed);
let params = SincInterpolationParameters::new(256, WindowFunction::BlackmanHarris2);
let inner = Async::<f32>::new_sinc(
ratio,
MAX_RATIO_SHIFT,
¶ms,
CHUNK,
channels,
FixedAsync::Input,
)
.ok()?;
let out_max = inner.output_frames_max();
let delay_left = inner.output_delay();
Some(Resample {
inner,
channels,
pending: Vec::with_capacity(CHUNK * channels * 2),
out_buf: vec![0.0; out_max * channels],
out_max,
delay_left,
})
}
pub fn push(&mut self, input: &[f32], sink: &mut Vec<f32>) {
self.pending.extend_from_slice(input);
loop {
let need = self.inner.input_frames_next();
if self.pending.len() < need * self.channels {
return;
}
self.run(need, None, sink);
self.pending.drain(..need * self.channels);
}
}
pub fn flush(&mut self, sink: &mut Vec<f32>) {
let have = self.pending.len() / self.channels;
if have == 0 {
return;
}
let need = self.inner.input_frames_next();
self.pending.resize(need * self.channels, 0.0);
self.run(need, Some(have), sink);
self.pending.clear();
}
fn run(&mut self, need: usize, partial: Option<usize>, sink: &mut Vec<f32>) {
let Resample {
inner,
channels,
pending,
out_buf,
out_max,
delay_left,
} = self;
let channels = *channels;
let Ok(input) = InterleavedSlice::new(&pending[..need * channels], channels, need) else {
return;
};
let indexing = Indexing {
input_offset: 0,
output_offset: 0,
partial_len: partial,
active_channels_mask: None,
};
let produced = {
let Ok(mut output) = InterleavedSlice::new_mut(&mut out_buf[..], channels, *out_max)
else {
return;
};
inner
.process_into_buffer(&input, &mut output, Some(&indexing))
.map(|(_, out)| out)
};
if let Ok(out_frames) = produced {
let skip = (*delay_left).min(out_frames);
*delay_left -= skip;
sink.extend_from_slice(&out_buf[skip * channels..out_frames * channels]);
}
}
}