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,
frames_in: u64,
frames_out: u64,
}
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,
frames_in: 0,
frames_out: 0,
})
}
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.frames_in += need as u64;
self.pending.drain(..need * self.channels);
}
}
pub fn flush(&mut self, sink: &mut Vec<f32>) {
let have = self.pending.len() / self.channels;
self.frames_in += have as u64;
let want = (self.frames_in as f64 * self.inner.resample_ratio()).round() as u64;
let start = sink.len();
let already = self.frames_out;
let mut partial = have;
while self.frames_out < want {
let need = self.inner.input_frames_next();
self.pending.resize(need * self.channels, 0.0);
if self.run(need, Some(partial), sink) == 0 {
break;
}
partial = 0;
self.pending.clear();
}
self.pending.clear();
sink.truncate(start + (want.saturating_sub(already) as usize) * self.channels);
self.frames_out = self.frames_out.min(want);
}
fn run(&mut self, need: usize, partial: Option<usize>, sink: &mut Vec<f32>) -> usize {
let Resample {
inner,
channels,
pending,
out_buf,
out_max,
delay_left,
frames_out,
..
} = self;
let channels = *channels;
let Ok(input) = InterleavedSlice::new(&pending[..need * channels], channels, need) else {
return 0;
};
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 0;
};
inner
.process_into_buffer(&input, &mut output, Some(&indexing))
.map(|(_, out)| out)
};
let Ok(out_frames) = produced else {
return 0;
};
let skip = (*delay_left).min(out_frames);
*delay_left -= skip;
sink.extend_from_slice(&out_buf[skip * channels..out_frames * channels]);
*frames_out += (out_frames - skip) as u64;
out_frames - skip
}
}