use rubato::{FftFixedIn, Resampler};
pub struct AudioResampler {
resampler: FftFixedIn<f64>,
input_buffer: Vec<f64>,
output_buffer: Vec<i16>,
}
impl AudioResampler {
pub fn new(source_rate: u32, target_rate: u32) -> Result<Self, String> {
let chunk_size = 1024;
let resampler = FftFixedIn::<f64>::new(
source_rate as usize,
target_rate as usize,
chunk_size,
2, 1, )
.map_err(|e| format!("failed to create resampler: {e}"))?;
Ok(Self {
resampler,
input_buffer: Vec::new(),
output_buffer: Vec::new(),
})
}
pub fn process(&mut self, samples: &[i16]) -> Vec<i16> {
self.input_buffer
.extend(samples.iter().map(|&s| s as f64 / i16::MAX as f64));
let input_frames_needed = self.resampler.input_frames_next();
while self.input_buffer.len() >= input_frames_needed {
let chunk: Vec<f64> = self.input_buffer.drain(..input_frames_needed).collect();
match self.resampler.process(&[chunk], None) {
Ok(output) => {
if !output.is_empty() {
self.output_buffer
.extend(output[0].iter().map(|&s| (s * i16::MAX as f64) as i16));
}
}
Err(e) => {
eprintln!("resampling error: {e}");
}
}
}
std::mem::take(&mut self.output_buffer)
}
pub fn reset(&mut self) {
self.input_buffer.clear();
self.output_buffer.clear();
}
pub fn buffered_input(&self) -> usize {
self.input_buffer.len()
}
pub fn buffered_output(&self) -> usize {
self.output_buffer.len()
}
}
impl std::fmt::Debug for AudioResampler {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioResampler")
.field("input_buffer_len", &self.input_buffer.len())
.field("output_buffer_len", &self.output_buffer.len())
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resampler_creation() {
let resampler = AudioResampler::new(16000, 48000);
assert!(resampler.is_ok());
}
#[test]
fn test_resample_16k_to_48k() {
let mut resampler = AudioResampler::new(16000, 48000).unwrap();
let input: Vec<i16> = vec![1000; 2048];
let output = resampler.process(&input);
assert!(!output.is_empty(), "Should have some output");
}
#[test]
fn test_resample_48k_to_16k() {
let mut resampler = AudioResampler::new(48000, 16000).unwrap();
let input: Vec<i16> = vec![1000; 2048];
let output = resampler.process(&input);
assert!(!output.is_empty(), "Should have some output");
}
#[test]
fn test_resampler_reset() {
let mut resampler = AudioResampler::new(16000, 48000).unwrap();
let input: Vec<i16> = vec![1000; 100];
let _ = resampler.process(&input);
assert!(resampler.buffered_input() > 0);
resampler.reset();
assert_eq!(resampler.buffered_input(), 0);
assert_eq!(resampler.buffered_output(), 0);
}
}