use {
crate::OperationError,
rodio::{Decoder, Source, buffer::SamplesBuffer, source::UniformSourceIterator},
std::{io::Cursor, path::Path},
tokio::fs::read,
};
pub async fn load_audio<const SR: usize, P>(
audio_path: P,
mono: bool,
) -> Result<(Vec<f32>, usize), OperationError>
where
P: AsRef<Path>,
{
let file = Cursor::new(read(audio_path).await?);
let decoder = Decoder::new(file)?;
let channels = if mono { 1 } else { decoder.channels() } as usize;
let samples =
UniformSourceIterator::new(decoder.convert_samples::<f32>(), channels as _, SR as _)
.collect::<Vec<f32>>();
if samples.is_empty() {
return Err(OperationError::InputInvalid("Audio is empty.".to_owned()));
}
Ok((samples, channels))
}
pub fn resample<const SSR: usize, const TSR: usize>(
samples: &[f32],
src_channels: usize,
tgt_channels: usize,
) -> Vec<f32> {
if samples.is_empty() || src_channels == 0 || tgt_channels == 0 {
return Vec::new();
}
UniformSourceIterator::new(
SamplesBuffer::new(src_channels as _, SSR as _, samples),
tgt_channels as _,
TSR as _,
)
.collect()
}