use crate::AudioError;
use rubato::{
Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction,
};
pub fn resample(y: &[f64], orig_sr: u32, target_sr: u32) -> Result<Vec<f64>, AudioError> {
if orig_sr == target_sr {
return Ok(y.to_vec());
}
let ratio = target_sr as f64 / orig_sr as f64;
let expected_len = (y.len() as f64 * ratio).ceil() as usize;
let params = SincInterpolationParameters {
sinc_len: 256,
f_cutoff: 0.95,
interpolation: SincInterpolationType::Linear,
oversampling_factor: 256,
window: WindowFunction::BlackmanHarris2,
};
let chunk_size = 1024.min(y.len());
let mut resampler = SincFixedIn::<f64>::new(
ratio, 2.0, params, chunk_size, 1, )
.map_err(|e| AudioError::Resample(e.to_string()))?;
let mut output = Vec::with_capacity(expected_len);
let mut pos = 0;
while pos + chunk_size <= y.len() {
let chunk = vec![y[pos..pos + chunk_size].to_vec()];
let result = resampler
.process(&chunk, None)
.map_err(|e| AudioError::Resample(e.to_string()))?;
output.extend_from_slice(&result[0]);
pos += chunk_size;
}
if pos < y.len() {
let remaining = &y[pos..];
let chunk = vec![remaining.to_vec()];
let result = resampler
.process_partial(Some(&chunk), None)
.map_err(|e| AudioError::Resample(e.to_string()))?;
output.extend_from_slice(&result[0]);
} else {
let result = resampler
.process_partial::<Vec<f64>>(None, None)
.map_err(|e| AudioError::Resample(e.to_string()))?;
output.extend_from_slice(&result[0]);
}
output.truncate(expected_len);
output.resize(expected_len, 0.0);
Ok(output)
}