use log;
use rubato::{
Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction,
};
#[derive(Debug, Clone, Copy)]
pub enum ResamplerQuality {
Quick,
Low,
Medium,
High,
VeryHigh,
}
impl ResamplerQuality {
fn sinc_params(self) -> SincInterpolationParameters {
match self {
Self::Quick => SincInterpolationParameters {
sinc_len: 32,
f_cutoff: 0.85,
interpolation: SincInterpolationType::Nearest,
oversampling_factor: 64,
window: WindowFunction::Hann,
},
Self::Low => SincInterpolationParameters {
sinc_len: 64,
f_cutoff: 0.90,
interpolation: SincInterpolationType::Nearest,
oversampling_factor: 128,
window: WindowFunction::Hann,
},
Self::Medium => SincInterpolationParameters {
sinc_len: 128,
f_cutoff: 0.92,
interpolation: SincInterpolationType::Linear,
oversampling_factor: 160,
window: WindowFunction::BlackmanHarris,
},
Self::High => SincInterpolationParameters {
sinc_len: 192,
f_cutoff: 0.94,
interpolation: SincInterpolationType::Cubic,
oversampling_factor: 192,
window: WindowFunction::BlackmanHarris2,
},
Self::VeryHigh => SincInterpolationParameters {
sinc_len: 256,
f_cutoff: 0.95,
interpolation: SincInterpolationType::Cubic,
oversampling_factor: 256,
window: WindowFunction::BlackmanHarris2,
},
}
}
}
pub struct StreamResampler {
inner: SincFixedIn<f32>,
buffer: Vec<f32>,
chunk_size: usize,
}
impl StreamResampler {
pub fn new(from_rate: u32, to_rate: u32, quality: ResamplerQuality) -> Self {
let ratio = to_rate as f64 / from_rate as f64;
let chunk_size: usize = 480;
let inner = SincFixedIn::<f32>::new(
ratio,
2.0, quality.sinc_params(),
chunk_size,
1, )
.expect("failed to create rubato resampler");
Self {
inner,
buffer: Vec::with_capacity(chunk_size * 2),
chunk_size,
}
}
pub fn process(&mut self, input: &[f32]) -> Vec<f32> {
self.buffer.extend_from_slice(input);
let mut output = Vec::new();
while self.buffer.len() >= self.chunk_size {
let chunk: Vec<f32> = self.buffer.drain(..self.chunk_size).collect();
match self.inner.process(&[chunk], None) {
Ok(result) => {
if let Some(ch) = result.first() {
output.extend_from_slice(ch);
}
}
Err(e) => {
log::warn!("StreamResampler: process error: {}", e);
break;
}
}
}
output
}
pub fn flush(&mut self) -> Vec<f32> {
if self.buffer.is_empty() {
return Vec::new();
}
self.buffer.resize(self.chunk_size, 0.0);
let chunk: Vec<f32> = self.buffer.drain(..).collect();
match self.inner.process(&[chunk], None) {
Ok(result) => result.into_iter().next().unwrap_or_default(),
Err(e) => {
log::warn!("StreamResampler: flush error: {}", e);
Vec::new()
}
}
}
pub fn reset(&mut self) {
self.buffer.clear();
self.inner.reset();
}
}