use crate::AudioError;
use std::fs::File;
use std::path::Path;
use symphonia::core::audio::SampleBuffer;
use symphonia::core::codecs::CODEC_TYPE_NULL;
use symphonia::core::io::MediaSourceStream;
use symphonia::core::probe::Hint;
pub fn load(path: &str, target_sr: Option<u32>, mono: bool) -> Result<(Vec<f64>, u32), AudioError> {
let (all_samples, native_sr, n_channels) = decode_file(path)?;
let samples = if n_channels == 1 {
all_samples
} else if mono {
let n_frames = all_samples.len() / n_channels;
let channels: Vec<Vec<f64>> = (0..n_channels)
.map(|ch| {
(0..n_frames)
.map(|f| all_samples[f * n_channels + ch])
.collect()
})
.collect();
crate::to_mono(&channels)
} else {
all_samples
};
let (final_samples, final_sr) = match target_sr {
Some(sr) if sr != native_sr => {
let resampled = crate::resample(&samples, native_sr, sr)?;
(resampled, sr)
}
_ => (samples, native_sr),
};
Ok((final_samples, final_sr))
}
pub fn get_duration(y: &[f64], sr: u32) -> f64 {
y.len() as f64 / sr as f64
}
pub fn get_samplerate(path: &str) -> Result<u32, AudioError> {
let file = File::open(path)?;
let mss = MediaSourceStream::new(Box::new(file), Default::default());
let mut hint = Hint::new();
if let Some(ext) = Path::new(path).extension().and_then(|e| e.to_str()) {
hint.with_extension(ext);
}
let probed = symphonia::default::get_probe().format(
&hint,
mss,
&Default::default(),
&Default::default(),
)?;
let track = probed
.format
.tracks()
.iter()
.find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
.ok_or(AudioError::NoTrack)?;
track.codec_params.sample_rate.ok_or(AudioError::NoTrack)
}
fn decode_file(path: &str) -> Result<(Vec<f64>, u32, usize), AudioError> {
let file = File::open(path)?;
let mss = MediaSourceStream::new(Box::new(file), Default::default());
let mut hint = Hint::new();
if let Some(ext) = Path::new(path).extension().and_then(|e| e.to_str()) {
hint.with_extension(ext);
}
let probed = symphonia::default::get_probe().format(
&hint,
mss,
&Default::default(),
&Default::default(),
)?;
let mut format = probed.format;
let track = format
.tracks()
.iter()
.find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
.ok_or(AudioError::NoTrack)?;
let track_id = track.id;
let n_channels = track
.codec_params
.channels
.map(|ch| ch.count())
.unwrap_or(1);
let sample_rate = track.codec_params.sample_rate.ok_or(AudioError::NoTrack)?;
let mut decoder =
symphonia::default::get_codecs().make(&track.codec_params, &Default::default())?;
let mut all_samples = Vec::new();
let mut sample_buf: Option<SampleBuffer<f64>> = None;
loop {
let packet = match format.next_packet() {
Ok(packet) => packet,
Err(symphonia::core::errors::Error::IoError(ref e))
if e.kind() == std::io::ErrorKind::UnexpectedEof =>
{
break;
}
Err(e) => return Err(e.into()),
};
if packet.track_id() != track_id {
continue;
}
match decoder.decode(&packet) {
Ok(decoded) => {
if sample_buf.is_none() {
sample_buf = Some(SampleBuffer::<f64>::new(
decoded.capacity() as u64,
*decoded.spec(),
));
}
let buf = sample_buf.as_mut().unwrap();
buf.copy_interleaved_ref(decoded);
all_samples.extend_from_slice(buf.samples());
}
Err(symphonia::core::errors::Error::DecodeError(_)) => {
continue;
}
Err(e) => return Err(e.into()),
}
}
Ok((all_samples, sample_rate, n_channels))
}