devalang_wasm/utils/
wav_parser.rs1pub fn parse_wav_generic(data: &[u8]) -> Result<(u16, u32, Vec<i16>), String> {
11 if data.len() < 44 {
12 return Err("File too short for WAV header".into());
13 }
14
15 if &data[0..4] != b"RIFF" || &data[8..12] != b"WAVE" {
17 return Err("Invalid RIFF/WAVE header".into());
18 }
19
20 let mut pos = 12; let mut channels = 1u16;
22 let mut sample_rate = 44100u32;
23 let mut bits = 16u16;
24 let mut raw_bytes: Option<Vec<u8>> = None;
25
26 while pos + 8 <= data.len() {
28 let chunk_id = &data[pos..pos + 4];
29 let chunk_size = u32::from_le_bytes(
30 data[pos + 4..pos + 8]
31 .try_into()
32 .map_err(|_| "Invalid chunk size bytes in WAV file")?,
33 ) as usize;
34 pos += 8;
35
36 if pos + chunk_size > data.len() {
37 break;
38 }
39
40 match chunk_id {
41 b"fmt " => {
42 if chunk_size < 16 {
43 return Err("fmt chunk too small".into());
44 }
45
46 let audio_format = u16::from_le_bytes(
47 data[pos..pos + 2]
48 .try_into()
49 .map_err(|_| "Invalid audio format bytes in WAV file")?,
50 );
51 channels = u16::from_le_bytes(
52 data[pos + 2..pos + 4]
53 .try_into()
54 .map_err(|_| "Invalid channel count bytes in WAV file")?,
55 );
56 sample_rate = u32::from_le_bytes(
57 data[pos + 4..pos + 8]
58 .try_into()
59 .map_err(|_| "Invalid sample rate bytes in WAV file")?,
60 );
61 bits = u16::from_le_bytes(
62 data[pos + 14..pos + 16]
63 .try_into()
64 .map_err(|_| "Invalid bit depth bytes in WAV file")?,
65 );
66
67 if audio_format != 1 {
68 return Err("Only uncompressed PCM supported".into());
69 }
70
71 if !(bits == 8 || bits == 16 || bits == 24 || bits == 32) {
72 return Err(format!(
73 "Unsupported bit depth {} (expected 8/16/24/32)",
74 bits
75 ));
76 }
77 }
78 b"data" => {
79 raw_bytes = Some(data[pos..pos + chunk_size].to_vec());
80 }
81 _ => { }
82 }
83
84 pos += chunk_size;
85 }
86
87 let bytes = raw_bytes.ok_or("data chunk not found".to_string())?;
88
89 let mut interleaved_f32: Vec<f32> = Vec::new();
91
92 match bits {
93 8 => {
94 for b in bytes.iter() {
96 interleaved_f32.push((*b as f32 - 128.0) / 128.0);
97 }
98 }
99 16 => {
100 for ch in bytes.chunks_exact(2) {
102 let v = i16::from_le_bytes([ch[0], ch[1]]);
103 interleaved_f32.push(v as f32 / 32768.0);
104 }
105 }
106 24 => {
107 for ch in bytes.chunks_exact(3) {
109 let assembled = (ch[0] as u32) | ((ch[1] as u32) << 8) | ((ch[2] as u32) << 16);
110
111 let signed = if (assembled & 0x800000) != 0 {
113 (assembled | 0xFF000000) as i32
114 } else {
115 assembled as i32
116 };
117
118 interleaved_f32.push(signed as f32 / 8388608.0);
119 }
120 }
121 32 => {
122 for ch in bytes.chunks_exact(4) {
124 let v = i32::from_le_bytes([ch[0], ch[1], ch[2], ch[3]]);
125 interleaved_f32.push(v as f32 / 2147483648.0);
126 }
127 }
128 _ => return Err("Unexpected bit depth".into()),
129 }
130
131 let chn = channels as usize;
132
133 if chn > 1 {
135 let frames = interleaved_f32.len() / chn;
136 let mut mono_f32 = Vec::with_capacity(frames);
137
138 for f in 0..frames {
139 let mut acc = 0.0;
140 for c in 0..chn {
141 acc += interleaved_f32[f * chn + c];
142 }
143 mono_f32.push(acc / chn as f32);
144 }
145
146 let mut out = Vec::with_capacity(mono_f32.len());
148 for s in mono_f32 {
149 out.push((s.clamp(-1.0, 1.0) * 32767.0) as i16);
150 }
151
152 Ok((1, sample_rate, out))
153 } else {
154 let mut out = Vec::with_capacity(interleaved_f32.len());
156 for s in interleaved_f32 {
157 out.push((s.clamp(-1.0, 1.0) * 32767.0) as i16);
158 }
159
160 Ok((1, sample_rate, out))
161 }
162}
163
164#[cfg(test)]
165#[path = "test_wav_parser.rs"]
166mod tests;