1use std::io;
2use std::path::Path;
3
4use symphonia::core::audio::SampleBuffer;
5use symphonia::core::codecs::{CODEC_TYPE_NULL, DecoderOptions};
6use symphonia::core::errors::Error as SymphoniaError;
7use symphonia::core::formats::FormatOptions;
8use symphonia::core::io::MediaSourceStream;
9use symphonia::core::meta::MetadataOptions;
10use symphonia::core::probe::Hint;
11
12pub fn read_wav_f32(path: &Path) -> io::Result<(Vec<f32>, usize, u32)> {
17 let file = std::fs::File::open(path)
18 .map_err(|e| io::Error::other(format!("Failed to open '{}': {e}", path.display())))?;
19 let mss = MediaSourceStream::new(Box::new(file), Default::default());
20
21 let mut hint = Hint::new();
22 if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
23 hint.with_extension(ext);
24 }
25
26 let format_opts = FormatOptions::default();
27 let metadata_opts = MetadataOptions::default();
28 let decoder_opts = DecoderOptions::default();
29
30 let probed = symphonia::default::get_probe()
31 .format(&hint, mss, &format_opts, &metadata_opts)
32 .map_err(|e| {
33 io::Error::other(format!(
34 "Symphonia failed to probe format for '{}': {e}",
35 path.display()
36 ))
37 })?;
38 let mut format = probed.format;
39
40 let track = format
41 .tracks()
42 .iter()
43 .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
44 .or_else(|| format.tracks().first())
45 .ok_or_else(|| {
46 io::Error::other(format!("No usable audio track in '{}'", path.display()))
47 })?;
48
49 let channels = track.codec_params.channels.map(|c| c.count()).unwrap_or(1);
50 let sample_rate = track.codec_params.sample_rate.unwrap_or(48_000);
51 let track_id = track.id;
52
53 let mut decoder = symphonia::default::get_codecs()
54 .make(&track.codec_params, &decoder_opts)
55 .map_err(|e| {
56 io::Error::other(format!(
57 "Symphonia failed to create decoder for '{}': {e}",
58 path.display()
59 ))
60 })?;
61
62 let mut sample_buf = None;
63 let mut samples = Vec::new();
64
65 loop {
66 let packet = match format.next_packet() {
67 Ok(packet) => packet,
68 Err(SymphoniaError::IoError(e)) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
69 break;
70 }
71 Err(e) => {
72 return Err(io::Error::other(format!(
73 "Symphonia read error for '{}': {e}",
74 path.display()
75 )));
76 }
77 };
78
79 if packet.track_id() != track_id {
80 continue;
81 }
82
83 let decoded = decoder.decode(&packet).map_err(|e| {
84 io::Error::other(format!(
85 "Symphonia decode error for '{}': {e}",
86 path.display()
87 ))
88 })?;
89
90 if sample_buf.is_none() {
91 let spec = *decoded.spec();
92 sample_buf = Some(SampleBuffer::<f32>::new(decoded.capacity() as u64, spec));
93 }
94 let buf = sample_buf.as_mut().unwrap();
95 buf.copy_interleaved_ref(decoded);
96 samples.extend_from_slice(buf.samples());
97 }
98
99 if samples.is_empty() {
100 return Err(io::Error::other(format!(
101 "No samples decoded from '{}'",
102 path.display()
103 )));
104 }
105
106 Ok((samples, channels, sample_rate))
107}