unity_asset_decode/audio/decoder.rs
1//! Audio decoder module
2//!
3//! This module provides audio decoding capabilities using Symphonia
4//! for various audio formats supported by Unity.
5
6use super::formats::AudioCompressionFormat;
7use super::types::{AudioClip, DecodedAudio};
8use crate::error::{BinaryError, Result};
9
10/// Main audio decoder
11///
12/// This struct provides methods for decoding various audio formats
13/// using the Symphonia audio library.
14pub struct AudioDecoder;
15
16impl AudioDecoder {
17 /// Create a new audio decoder
18 pub fn new() -> Self {
19 Self
20 }
21
22 /// Decode audio using Symphonia (supports many formats)
23 pub fn decode(&self, clip: &AudioClip) -> Result<DecodedAudio> {
24 use std::io::Cursor;
25 use symphonia::core::audio::{AudioBufferRef, Signal};
26 use symphonia::core::codecs::{CODEC_TYPE_NULL, DecoderOptions};
27 use symphonia::core::errors::Error as SymphoniaError;
28 use symphonia::core::formats::FormatOptions;
29 use symphonia::core::io::MediaSourceStream;
30 use symphonia::core::meta::MetadataOptions;
31 use symphonia::core::probe::Hint;
32
33 if clip.data.is_empty() {
34 return Err(BinaryError::invalid_data("No audio data to decode"));
35 }
36
37 // Create a media source from the audio data
38 let cursor = Cursor::new(clip.data.clone());
39 let media_source = MediaSourceStream::new(Box::new(cursor), Default::default());
40
41 // Create a probe hint based on the compression format
42 let mut hint = Hint::new();
43 match clip.compression_format() {
44 AudioCompressionFormat::Vorbis => hint.with_extension("ogg"),
45 AudioCompressionFormat::MP3 => hint.with_extension("mp3"),
46 AudioCompressionFormat::AAC => hint.with_extension("aac"),
47 AudioCompressionFormat::PCM => hint.with_extension("wav"),
48 _ => &mut hint,
49 };
50
51 // Get the metadata and format readers
52 let meta_opts: MetadataOptions = Default::default();
53 let fmt_opts: FormatOptions = Default::default();
54
55 // Probe the media source
56 let probed = symphonia::default::get_probe()
57 .format(&hint, media_source, &fmt_opts, &meta_opts)
58 .map_err(|e| BinaryError::generic(format!("Failed to probe audio format: {}", e)))?;
59
60 // Get the instantiated format reader
61 let mut format = probed.format;
62
63 // Find the first audio track with a known (decodeable) codec
64 let track = format
65 .tracks()
66 .iter()
67 .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
68 .ok_or_else(|| BinaryError::generic("No supported audio tracks found"))?;
69
70 // Use the default options for the decoder
71 let dec_opts: DecoderOptions = Default::default();
72
73 // Create a decoder for the track
74 let mut decoder = symphonia::default::get_codecs()
75 .make(&track.codec_params, &dec_opts)
76 .map_err(|e| BinaryError::generic(format!("Failed to create decoder: {}", e)))?;
77
78 // Store the track identifier, it will be used to filter packets
79 let track_id = track.id;
80
81 let mut samples = Vec::new();
82 let mut sample_rate = 44100u32;
83 let mut channels = 2u32;
84
85 // The decode loop
86 loop {
87 // Get the next packet from the media format
88 let packet = match format.next_packet() {
89 Ok(packet) => packet,
90 Err(SymphoniaError::ResetRequired) => {
91 // The track list has been changed. Re-examine it and create a new set of decoders,
92 // then restart the decode loop. This is an advanced feature and it is not
93 // unreasonable to consider this "the end of the stream". As of v0.5.0, the only
94 // usage of this is for chained OGG physical streams.
95 break;
96 }
97 Err(SymphoniaError::IoError(_)) => {
98 // The packet reader has reached the end of the stream
99 break;
100 }
101 Err(err) => {
102 // A unrecoverable error occurred, halt decoding
103 return Err(BinaryError::generic(format!("Decode error: {}", err)));
104 }
105 };
106
107 // Consume any new metadata that has been read since the last packet
108 while !format.metadata().is_latest() {
109 // Pop the latest metadata and consume it
110 format.metadata().pop();
111 }
112
113 // If the packet does not belong to the selected track, skip over it
114 if packet.track_id() != track_id {
115 continue;
116 }
117
118 // Decode the packet into an audio buffer
119 match decoder.decode(&packet) {
120 Ok(decoded) => {
121 // Get audio buffer information
122 let spec = *decoded.spec();
123 sample_rate = spec.rate;
124 channels = spec.channels.count() as u32;
125
126 // Convert the audio buffer to f32 samples
127 match decoded {
128 AudioBufferRef::F32(buf) => {
129 samples.extend_from_slice(buf.chan(0));
130 if channels > 1 {
131 for ch in 1..channels as usize {
132 if ch < buf.spec().channels.count() {
133 let channel_samples = buf.chan(ch);
134 // Interleave channels
135 for (i, &sample) in channel_samples.iter().enumerate() {
136 if i * channels as usize + ch < samples.len() {
137 samples.insert(i * channels as usize + ch, sample);
138 } else {
139 samples.push(sample);
140 }
141 }
142 }
143 }
144 }
145 }
146 AudioBufferRef::U8(buf) => {
147 for ch in 0..channels as usize {
148 if ch < buf.spec().channels.count() {
149 let channel_samples = buf.chan(ch);
150 for &sample in channel_samples {
151 let normalized = (sample as f32 - 128.0) / 128.0;
152 samples.push(normalized);
153 }
154 }
155 }
156 }
157 AudioBufferRef::U16(buf) => {
158 for ch in 0..channels as usize {
159 if ch < buf.spec().channels.count() {
160 let channel_samples = buf.chan(ch);
161 for &sample in channel_samples {
162 let normalized = (sample as f32 - 32768.0) / 32768.0;
163 samples.push(normalized);
164 }
165 }
166 }
167 }
168 AudioBufferRef::U32(buf) => {
169 for ch in 0..channels as usize {
170 if ch < buf.spec().channels.count() {
171 let channel_samples = buf.chan(ch);
172 for &sample in channel_samples {
173 let normalized =
174 (sample as f32 - 2147483648.0) / 2147483648.0;
175 samples.push(normalized);
176 }
177 }
178 }
179 }
180 AudioBufferRef::S8(buf) => {
181 for ch in 0..channels as usize {
182 if ch < buf.spec().channels.count() {
183 let channel_samples = buf.chan(ch);
184 for &sample in channel_samples {
185 let normalized = sample as f32 / 128.0;
186 samples.push(normalized);
187 }
188 }
189 }
190 }
191 AudioBufferRef::S16(buf) => {
192 for ch in 0..channels as usize {
193 if ch < buf.spec().channels.count() {
194 let channel_samples = buf.chan(ch);
195 for &sample in channel_samples {
196 let normalized = sample as f32 / 32768.0;
197 samples.push(normalized);
198 }
199 }
200 }
201 }
202 AudioBufferRef::S32(buf) => {
203 for ch in 0..channels as usize {
204 if ch < buf.spec().channels.count() {
205 let channel_samples = buf.chan(ch);
206 for &sample in channel_samples {
207 let normalized = sample as f32 / 2147483648.0;
208 samples.push(normalized);
209 }
210 }
211 }
212 }
213 AudioBufferRef::F64(buf) => {
214 for ch in 0..channels as usize {
215 if ch < buf.spec().channels.count() {
216 let channel_samples = buf.chan(ch);
217 for &sample in channel_samples {
218 samples.push(sample as f32);
219 }
220 }
221 }
222 }
223 AudioBufferRef::U24(buf) => {
224 for ch in 0..channels as usize {
225 if ch < buf.spec().channels.count() {
226 let channel_samples = buf.chan(ch);
227 for &sample in channel_samples {
228 let value = sample.inner() as i32;
229 let normalized = (value as f32 - 8388608.0) / 8388608.0;
230 samples.push(normalized);
231 }
232 }
233 }
234 }
235 AudioBufferRef::S24(buf) => {
236 for ch in 0..channels as usize {
237 if ch < buf.spec().channels.count() {
238 let channel_samples = buf.chan(ch);
239 for &sample in channel_samples {
240 let value = sample.inner();
241 let normalized = value as f32 / 8388608.0;
242 samples.push(normalized);
243 }
244 }
245 }
246 }
247 }
248 }
249 Err(SymphoniaError::IoError(_)) => {
250 // The packet reader has reached the end of the stream
251 break;
252 }
253 Err(SymphoniaError::DecodeError(_)) => {
254 // Decode error, try to continue
255 continue;
256 }
257 Err(err) => {
258 // A unrecoverable error occurred, halt decoding
259 return Err(BinaryError::generic(format!("Decode error: {}", err)));
260 }
261 }
262 }
263
264 if samples.is_empty() {
265 return Err(BinaryError::generic("No audio samples decoded"));
266 }
267
268 Ok(DecodedAudio::new(samples, sample_rate, channels))
269 }
270
271 /// Check if a format can be decoded
272 pub fn can_decode(&self, format: AudioCompressionFormat) -> bool {
273 matches!(
274 format,
275 AudioCompressionFormat::PCM
276 | AudioCompressionFormat::Vorbis
277 | AudioCompressionFormat::MP3
278 | AudioCompressionFormat::AAC
279 | AudioCompressionFormat::ADPCM
280 )
281 }
282
283 /// Get list of supported formats
284 pub fn supported_formats(&self) -> Vec<AudioCompressionFormat> {
285 vec![
286 AudioCompressionFormat::PCM,
287 AudioCompressionFormat::Vorbis,
288 AudioCompressionFormat::MP3,
289 AudioCompressionFormat::AAC,
290 AudioCompressionFormat::ADPCM,
291 ]
292 }
293}
294
295impl Default for AudioDecoder {
296 fn default() -> Self {
297 Self::new()
298 }
299}