1use anyhow::{anyhow, Result};
2use rubato::{
3 Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction,
4};
5use std::fs::File;
6use std::path::Path;
7use symphonia::core::audio::SampleBuffer;
8use symphonia::core::codecs::{DecoderOptions, CODEC_TYPE_NULL};
9use symphonia::core::errors::Error;
10use symphonia::core::formats::FormatOptions;
11use symphonia::core::io::MediaSourceStream;
12use symphonia::core::meta::MetadataOptions;
13use symphonia::core::probe::Hint;
14
15pub struct AudioData {
17 pub samples: Vec<f32>,
18 pub sample_rate: u32,
19}
20
21pub fn load_audio(path: &Path, target_sr: u32) -> Result<AudioData> {
27 let (samples, source_sr, channels) = decode(path)?;
28 let mono = to_mono(&samples, channels);
29 let resampled = resample(mono, source_sr, target_sr)?;
30
31 Ok(AudioData {
32 samples: resampled,
33 sample_rate: target_sr,
34 })
35}
36
37fn decode(path: &Path) -> Result<(Vec<f32>, u32, usize)> {
40 let src = File::open(path)?;
41 let mss = MediaSourceStream::new(Box::new(src), Default::default());
42
43 let mut hint = Hint::new();
45 if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
46 hint.with_extension(ext);
47 }
48
49 let probed = symphonia::default::get_probe().format(
50 &hint,
51 mss,
52 &FormatOptions::default(),
53 &MetadataOptions::default(),
54 )?;
55 let mut format = probed.format;
56
57 let track = format
58 .tracks()
59 .iter()
60 .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
61 .ok_or_else(|| anyhow!("no supported audio tracks"))?;
62
63 let track_id = track.id;
64 let mut decoder =
65 symphonia::default::get_codecs().make(&track.codec_params, &DecoderOptions::default())?;
66
67 let mut samples: Vec<f32> = Vec::new();
68 let mut source_sr = 0u32;
69 let mut channels = 0usize;
70
71 loop {
72 let packet = match format.next_packet() {
73 Ok(packet) => packet,
74 Err(Error::IoError(_)) => break,
75 Err(err) => return Err(anyhow!(err)),
76 };
77
78 if packet.track_id() != track_id {
79 continue;
80 }
81
82 match decoder.decode(&packet) {
83 Ok(decoded) => {
84 let spec = *decoded.spec();
85 source_sr = spec.rate;
86 channels = spec.channels.count();
87
88 let mut sample_buf = SampleBuffer::<f32>::new(decoded.capacity() as u64, spec);
89 sample_buf.copy_interleaved_ref(decoded);
90 samples.extend_from_slice(sample_buf.samples());
91 }
92 Err(Error::IoError(_)) => break,
93 Err(Error::DecodeError(_)) => (), Err(err) => return Err(anyhow!(err)),
95 }
96 }
97
98 if source_sr == 0 {
99 return Err(anyhow!("failed to decode any audio packets"));
100 }
101
102 Ok((samples, source_sr, channels))
103}
104
105fn to_mono(samples: &[f32], channels: usize) -> Vec<f32> {
107 if channels == 1 {
108 return samples.to_vec();
109 }
110 samples
111 .chunks(channels)
112 .map(|frame| frame.iter().sum::<f32>() / channels as f32)
113 .collect()
114}
115
116pub fn resample(samples: Vec<f32>, source_sr: u32, target_sr: u32) -> Result<Vec<f32>> {
119 if source_sr == target_sr {
120 return Ok(samples);
121 }
122
123 let params = SincInterpolationParameters {
124 sinc_len: 256,
125 f_cutoff: 0.95,
126 interpolation: SincInterpolationType::Linear,
127 oversampling_factor: 256,
128 window: WindowFunction::BlackmanHarris2,
129 };
130
131 let mut resampler = SincFixedIn::<f32>::new(
132 target_sr as f64 / source_sr as f64,
133 2.0,
134 params,
135 samples.len(),
136 1, )?;
138
139 let waves_out = resampler.process(&[samples], None)?;
140 Ok(waves_out.into_iter().next().unwrap())
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_to_mono_passthrough() {
149 let samples = vec![1.0, 2.0, 3.0];
150 let mono = to_mono(&samples, 1);
151 assert_eq!(mono, vec![1.0, 2.0, 3.0]);
152 }
153
154 #[test]
155 fn test_to_mono_stereo() {
156 let samples = vec![0.5, 1.5, 1.0, 3.0];
158 let mono = to_mono(&samples, 2);
159 assert_eq!(mono, vec![1.0, 2.0]);
160 }
161
162 #[test]
163 fn test_resample_identity() {
164 let samples = vec![1.0, 2.0, 3.0, 4.0];
166 let result = resample(samples.clone(), 22050, 22050).unwrap();
167 assert_eq!(result, samples);
168 }
169}