Skip to content

Commit 7e8beb9

Browse files
committed
[add] decoder implementations.
1 parent 2d02586 commit 7e8beb9

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

  • crates/lambda-rs-platform/src/audio/symphonia

crates/lambda-rs-platform/src/audio/symphonia/mod.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,129 @@
44
//!
55
//! This module will provide WAV and OGG Vorbis decode helpers for `lambda-rs`.
66
//! It is intentionally internal and MAY change between releases.
7+
8+
use std::{
9+
fmt,
10+
io::Cursor,
11+
};
12+
13+
use symphonia::core::{
14+
errors::Error,
15+
formats::FormatOptions,
16+
io::MediaSourceStream,
17+
meta::MetadataOptions,
18+
probe::Hint,
19+
};
20+
21+
/// Fully decoded, interleaved `f32` samples with associated metadata.
22+
#[derive(Clone, Debug, PartialEq)]
23+
pub struct DecodedAudio {
24+
pub samples: Vec<f32>,
25+
pub sample_rate: u32,
26+
pub channels: u16,
27+
}
28+
29+
/// Vendor-free errors produced by audio decoding helpers.
30+
#[derive(Clone, Debug)]
31+
pub enum AudioDecodeError {
32+
UnsupportedFormat { details: String },
33+
InvalidData { details: String },
34+
DecodeFailed { details: String },
35+
}
36+
37+
impl fmt::Display for AudioDecodeError {
38+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
39+
match self {
40+
Self::UnsupportedFormat { details } => {
41+
return write!(formatter, "unsupported audio format: {details}");
42+
}
43+
Self::InvalidData { details } => {
44+
return write!(formatter, "invalid audio data: {details}");
45+
}
46+
Self::DecodeFailed { details } => {
47+
return write!(formatter, "audio decode failed: {details}");
48+
}
49+
}
50+
}
51+
}
52+
53+
impl std::error::Error for AudioDecodeError {}
54+
55+
fn hint_for_decode(extensions: &[&str]) -> Hint {
56+
let mut hint_value = Hint::new();
57+
for extension in extensions {
58+
hint_value.with_extension(extension);
59+
}
60+
return hint_value;
61+
}
62+
63+
fn map_probe_error(source_description: &str, error: Error) -> AudioDecodeError {
64+
match error {
65+
Error::Unsupported(_) => {
66+
return AudioDecodeError::UnsupportedFormat {
67+
details: format!("unsupported or unrecognized {source_description}"),
68+
};
69+
}
70+
Error::IoError(_) => {
71+
return AudioDecodeError::InvalidData {
72+
details: format!("failed to read {source_description} bytes"),
73+
};
74+
}
75+
other => {
76+
return AudioDecodeError::DecodeFailed {
77+
details: format!("{source_description} probe error: {other}"),
78+
};
79+
}
80+
}
81+
}
82+
83+
fn probe_bytes(
84+
bytes: &[u8],
85+
source_description: &str,
86+
extensions: &[&str],
87+
) -> Result<(), AudioDecodeError> {
88+
let hint_value = hint_for_decode(extensions);
89+
90+
let cursor = Cursor::new(bytes.to_vec());
91+
let media_source =
92+
MediaSourceStream::new(Box::new(cursor), Default::default());
93+
94+
let probe_result = symphonia::default::get_probe()
95+
.format(
96+
&hint_value,
97+
media_source,
98+
&FormatOptions::default(),
99+
&MetadataOptions::default(),
100+
)
101+
.map_err(|error| map_probe_error(source_description, error))?;
102+
103+
if probe_result.format.tracks().is_empty() {
104+
return Err(AudioDecodeError::InvalidData {
105+
details: "no audio tracks found".to_string(),
106+
});
107+
}
108+
109+
return Ok(());
110+
}
111+
112+
/// Decode WAV bytes into interleaved `f32` samples.
113+
#[cfg(feature = "audio-decode-wav")]
114+
pub fn decode_wav_bytes(
115+
bytes: &[u8],
116+
) -> Result<DecodedAudio, AudioDecodeError> {
117+
probe_bytes(bytes, "WAV", &["wav"])?;
118+
return Err(AudioDecodeError::DecodeFailed {
119+
details: "WAV decoding not implemented yet".to_string(),
120+
});
121+
}
122+
123+
/// Decode OGG Vorbis bytes into interleaved `f32` samples.
124+
#[cfg(feature = "audio-decode-vorbis")]
125+
pub fn decode_ogg_vorbis_bytes(
126+
bytes: &[u8],
127+
) -> Result<DecodedAudio, AudioDecodeError> {
128+
probe_bytes(bytes, "OGG Vorbis", &["ogg", "oga"])?;
129+
return Err(AudioDecodeError::DecodeFailed {
130+
details: "OGG Vorbis decoding not implemented yet".to_string(),
131+
});
132+
}

0 commit comments

Comments
 (0)