#[cfg(feature = "local-whisper")]
use anyhow::{Context, Result};
pub const WHISPER_SAMPLE_RATE: u32 = 16000;
#[cfg(feature = "local-whisper")]
pub fn resample_to_16k(samples: &[f32], source_rate: u32, channels: u16) -> Result<Vec<f32>> {
use rubato::{FftFixedIn, Resampler};
let mono_samples = if channels > 1 {
stereo_to_mono(samples, channels)
} else {
samples.to_vec()
};
if source_rate == WHISPER_SAMPLE_RATE {
return Ok(mono_samples);
}
let mut resampler = FftFixedIn::<f32>::new(
source_rate as usize,
WHISPER_SAMPLE_RATE as usize,
1024, 2, 1, )
.context("Failed to create resampler")?;
let mut output = Vec::new();
let chunk_size = resampler.input_frames_max();
for chunk in mono_samples.chunks(chunk_size) {
let mut padded = chunk.to_vec();
if padded.len() < chunk_size {
padded.resize(chunk_size, 0.0);
}
let result = resampler
.process(&[padded], None)
.context("Resampling failed")?;
output.extend_from_slice(&result[0]);
}
Ok(output)
}
#[cfg(feature = "local-whisper")]
fn stereo_to_mono(samples: &[f32], channels: u16) -> Vec<f32> {
samples
.chunks(channels as usize)
.map(|frame| frame.iter().sum::<f32>() / channels as f32)
.collect()
}