mittens_engine/engine/ecs/system/
audio_decode.rs1use std::fs::File;
9use std::path::Path;
10
11use symphonia::core::audio::{AudioBufferRef, Signal};
12use symphonia::core::codecs::DecoderOptions;
13use symphonia::core::errors::Error as SymphoniaError;
14use symphonia::core::formats::FormatOptions;
15use symphonia::core::io::MediaSourceStream;
16use symphonia::core::meta::MetadataOptions;
17use symphonia::core::probe::Hint;
18use symphonia::core::sample::Sample;
19
20#[derive(Debug, Clone)]
24pub struct DecodedAudio {
25 pub samples: Vec<f32>,
26 pub channels: u16,
27 pub sample_rate: u32,
28}
29
30#[derive(Debug, Clone)]
31pub enum DecodeError {
32 OpenFailed(String),
33 ProbeFailed(String),
34 NoTrack,
35 DecoderInitFailed(String),
36 DecodeFailed(String),
37 Unsupported(String),
38}
39
40impl std::fmt::Display for DecodeError {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 match self {
43 DecodeError::OpenFailed(s) => write!(f, "open failed: {s}"),
44 DecodeError::ProbeFailed(s) => write!(f, "probe failed: {s}"),
45 DecodeError::NoTrack => write!(f, "no default track"),
46 DecodeError::DecoderInitFailed(s) => write!(f, "decoder init failed: {s}"),
47 DecodeError::DecodeFailed(s) => write!(f, "decode failed: {s}"),
48 DecodeError::Unsupported(s) => write!(f, "unsupported: {s}"),
49 }
50 }
51}
52
53impl std::error::Error for DecodeError {}
54
55pub fn decode_audio_file(path: impl AsRef<Path>) -> Result<DecodedAudio, DecodeError> {
57 let path = path.as_ref();
58 let file = File::open(path).map_err(|e| DecodeError::OpenFailed(e.to_string()))?;
59 let mss = MediaSourceStream::new(Box::new(file), Default::default());
60
61 let mut hint = Hint::new();
62 if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
63 hint.with_extension(ext);
64 }
65
66 let probed = symphonia::default::get_probe()
67 .format(
68 &hint,
69 mss,
70 &FormatOptions::default(),
71 &MetadataOptions::default(),
72 )
73 .map_err(|e| DecodeError::ProbeFailed(e.to_string()))?;
74
75 let mut format = probed.format;
76 let track = format.default_track().ok_or(DecodeError::NoTrack)?;
77 let track_id = track.id;
78 let codec_params = track.codec_params.clone();
79 let sample_rate = codec_params
80 .sample_rate
81 .ok_or_else(|| DecodeError::Unsupported("missing sample_rate".into()))?;
82 let channels = codec_params
83 .channels
84 .map(|c| c.count() as u16)
85 .ok_or_else(|| DecodeError::Unsupported("missing channel layout".into()))?;
86
87 let mut decoder = symphonia::default::get_codecs()
88 .make(&codec_params, &DecoderOptions::default())
89 .map_err(|e| DecodeError::DecoderInitFailed(e.to_string()))?;
90
91 let mut samples: Vec<f32> = Vec::new();
92
93 loop {
94 let packet = match format.next_packet() {
95 Ok(p) => p,
96 Err(SymphoniaError::IoError(e)) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
97 break;
98 }
99 Err(SymphoniaError::ResetRequired) => {
100 decoder.reset();
102 continue;
103 }
104 Err(e) => return Err(DecodeError::DecodeFailed(e.to_string())),
105 };
106 if packet.track_id() != track_id {
107 continue;
108 }
109
110 let decoded = match decoder.decode(&packet) {
111 Ok(d) => d,
112 Err(SymphoniaError::DecodeError(_)) => {
113 continue;
115 }
116 Err(e) => return Err(DecodeError::DecodeFailed(e.to_string())),
117 };
118
119 interleave_into(&decoded, &mut samples);
120 }
121
122 Ok(DecodedAudio {
123 samples,
124 channels,
125 sample_rate,
126 })
127}
128
129fn interleave_into(buf: &AudioBufferRef<'_>, out: &mut Vec<f32>) {
131 match buf {
132 AudioBufferRef::F32(b) => interleave_planar::<f32>(b, out),
133 AudioBufferRef::F64(b) => interleave_planar::<f64>(b, out),
134 AudioBufferRef::S8(b) => interleave_planar::<i8>(b, out),
135 AudioBufferRef::S16(b) => interleave_planar::<i16>(b, out),
136 AudioBufferRef::S24(b) => interleave_planar::<symphonia::core::sample::i24>(b, out),
137 AudioBufferRef::S32(b) => interleave_planar::<i32>(b, out),
138 AudioBufferRef::U8(b) => interleave_planar::<u8>(b, out),
139 AudioBufferRef::U16(b) => interleave_planar::<u16>(b, out),
140 AudioBufferRef::U24(b) => interleave_planar::<symphonia::core::sample::u24>(b, out),
141 AudioBufferRef::U32(b) => interleave_planar::<u32>(b, out),
142 }
143}
144
145fn interleave_planar<S>(buf: &symphonia::core::audio::AudioBuffer<S>, out: &mut Vec<f32>)
146where
147 S: Sample + symphonia::core::conv::IntoSample<f32>,
148{
149 let channels = buf.spec().channels.count();
150 let frames = buf.frames();
151 out.reserve(frames * channels);
152 for f in 0..frames {
153 for c in 0..channels {
154 let s: S = buf.chan(c)[f];
155 out.push(s.into_sample());
156 }
157 }
158}