1use byteorder::{ByteOrder, LittleEndian};
2
3use std::io::Read;
4use std::io::Seek;
5use std::io::SeekFrom;
6
7mod error;
8pub use error::Error;
9
10#[derive(Debug)]
11pub struct RiffWaveReader<T: Read + Seek> {
12 reader: T,
13 pub riff_chunk: RiffChunk,
14 pub fmt_chunk: FmtChunk,
15 pub fact_chunk: Option<FactChunk>,
16 pub data_chunk: DataChunk,
17 pub other_chunks: Vec<OtherChunk>,
18}
19
20impl<T: Read + Seek> RiffWaveReader<T> {
21 pub fn new(mut reader: T) -> Result<RiffWaveReader<T>, Error> {
22 let riff_chunk = reader.read_riff_chunk()?;
23
24 if riff_chunk.id != FourCC::Riff {
25 return Err(Error::NotRiff);
26 }
27
28 if riff_chunk.file_type != FourCC::Wave {
29 return Err(Error::NotWave);
30 }
31
32 let fmt_chunk = reader.read_fmt_chunk()?;
33
34 let fact_chunk = reader.read_fact_chunk()?;
35
36 let mut other_chunks = vec![];
37 reader.read_other_chunks(&mut other_chunks)?;
38
39 let data_chunk = reader.read_data_chunk()?;
40
41 let riff_reader = RiffWaveReader {
42 reader,
43 riff_chunk,
44 fmt_chunk,
45 fact_chunk,
46 data_chunk,
47 other_chunks,
48 };
49
50 Ok(riff_reader)
51 }
52
53 pub fn data(&mut self) -> Result<impl Iterator<Item = u8>, Error> {
54 let mut data = vec![];
55 self.reader.read_to_end(&mut data)?;
56
57 Ok(data.into_iter())
58 }
59
60 pub fn print_info(&self) {
61 println!("{}", self);
62 }
63
64 pub fn into_reader(self) -> T {
65 self.reader
66 }
67}
68
69trait ReadExt: Read + Seek {
70 fn read_riff_chunk(&mut self) -> Result<RiffChunk, Error>;
71
72 fn read_fmt_chunk(&mut self) -> Result<FmtChunk, Error>;
73
74 fn read_extended_info(&mut self, size: u16) -> Result<Option<ExtendedInfo>, Error>;
75
76 fn read_fact_chunk(&mut self) -> Result<Option<FactChunk>, Error>;
77
78 fn read_other_chunks(&mut self, other_chunks: &mut Vec<OtherChunk>) -> Result<(), Error>;
79
80 fn read_data_chunk(&mut self) -> Result<DataChunk, Error>;
81
82 fn read_fourcc(&mut self) -> Result<FourCC, Error>;
83
84 fn read_u32(&mut self) -> Result<u32, Error>;
85
86 fn read_u16(&mut self) -> Result<u16, Error>;
87
88 fn read_u128(&mut self) -> Result<u128, Error>;
89
90 fn read_is_fourcc(&mut self) -> Result<bool, Error>;
91}
92
93impl<T: Read + Seek> ReadExt for T {
94 fn read_riff_chunk(&mut self) -> Result<RiffChunk, Error> {
95 let id = self.read_fourcc()?;
96 let file_size = self.read_u32()?;
97 let file_type = self.read_fourcc()?;
98
99 Ok(RiffChunk {
100 id,
101 file_size,
102 file_type,
103 })
104 }
105
106 fn read_fmt_chunk(&mut self) -> Result<FmtChunk, Error> {
107 let id = self.read_fourcc()?;
108 if id != FourCC::Fmt {
109 return Err(Error::InvalidFmtChunk);
110 }
111
112 let data_size = self.read_u32()?;
113 let format = Format::from(self.read_u16()?);
114 let num_channels = self.read_u16()?;
115 let sample_rate = self.read_u32()?;
116 let byte_rate = self.read_u32()?;
117 let block_align = self.read_u16()?;
118 let bits_per_raw_sample = self.read_u16()?;
119
120 let (extra_info_size, extended_info) = if self.read_is_fourcc()? {
121 (0, None)
122 } else {
123 let extra_info_size = self.read_u16()?;
124 (extra_info_size, self.read_extended_info(extra_info_size)?)
125 };
126
127 Ok(FmtChunk {
128 id,
129 data_size,
130 format,
131 num_channels,
132 sample_rate,
133 byte_rate,
134 block_align,
135 bits_per_raw_sample,
136 extra_info_size,
137 extended_info,
138 })
139 }
140
141 fn read_extended_info(&mut self, size: u16) -> Result<Option<ExtendedInfo>, Error> {
142 if size == 0 {
143 return Ok(None);
144 }
145
146 if size < 22 {
147 return Err(Error::InvalidExtendedInfo);
148 }
149
150 let bits_per_coded_sample = self.read_u16()?;
151 let channel_mask = self.read_u32()?;
152 let sub_format = self.read_u128()?;
153
154 let remaining_size = (size - 22) as usize;
155 let mut remaining_data = vec![0; remaining_size];
156 self.read_exact(&mut remaining_data[..])?;
157
158 Ok(Some(ExtendedInfo {
159 bits_per_coded_sample,
160 channel_mask,
161 sub_format,
162 remaining_data,
163 }))
164 }
165
166 fn read_fact_chunk(&mut self) -> Result<Option<FactChunk>, Error> {
167 let id = self.read_fourcc()?;
168 if id != FourCC::Fact {
169 self.seek(SeekFrom::Current(-4))?;
170 return Ok(None);
171 }
172
173 let data_size = self.read_u32()?;
174 let sample_length = self.read_u32()?;
175
176 let remaining_size = (data_size - 4) as usize;
177 let mut remaining_data = vec![0; remaining_size];
178 self.read_exact(&mut remaining_data[..])?;
179
180 Ok(Some(FactChunk {
181 id,
182 data_size,
183 sample_length,
184 remaining_data,
185 }))
186 }
187
188 fn read_other_chunks(&mut self, other_chunks: &mut Vec<OtherChunk>) -> Result<(), Error> {
189 loop {
190 let fourcc = self.read_fourcc()?;
191
192 if fourcc == FourCC::Data {
193 self.seek(SeekFrom::Current(-4))?;
194 return Ok(());
195 }
196
197 let data_size = self.read_u32()?;
198 let mut data = vec![0; data_size as usize];
199 self.read_exact(&mut data)?;
200
201 let chunk = OtherChunk {
202 id: fourcc,
203 data_size,
204 data,
205 };
206
207 other_chunks.push(chunk);
208 }
209 }
210
211 fn read_data_chunk(&mut self) -> Result<DataChunk, Error> {
212 let id = self.read_fourcc()?;
213 let data_size = self.read_u32()?;
214
215 let pad_byte = if data_size % 2 == 0 { 0 } else { 1 };
216
217 Ok(DataChunk {
218 id,
219 data_size,
220 pad_byte,
221 })
222 }
223
224 fn read_fourcc(&mut self) -> Result<FourCC, Error> {
225 let mut buf = [0; 4];
226
227 self.read_exact(&mut buf)?;
228
229 Ok(FourCC::from(&buf[..]))
230 }
231
232 fn read_u32(&mut self) -> Result<u32, Error> {
233 let mut buf = [0; 4];
234
235 self.read_exact(&mut buf)?;
236
237 Ok(LittleEndian::read_u32(&buf))
238 }
239
240 fn read_u16(&mut self) -> Result<u16, Error> {
241 let mut buf = [0; 2];
242
243 self.read_exact(&mut buf)?;
244
245 Ok(LittleEndian::read_u16(&buf))
246 }
247
248 fn read_u128(&mut self) -> Result<u128, Error> {
249 let mut buf = [0; 16];
250
251 self.read_exact(&mut buf)?;
252
253 Ok(LittleEndian::read_u128(&buf))
254 }
255
256 fn read_is_fourcc(&mut self) -> Result<bool, Error> {
257 let fourcc = self.read_fourcc()?;
258 self.seek(SeekFrom::Current(-4))?;
259
260 Ok(if let FourCC::Other(_) = fourcc {
261 false
262 } else {
263 true
264 })
265 }
266}
267
268#[derive(Debug)]
269pub struct RiffChunk {
270 pub id: FourCC,
271 pub file_size: u32,
272 pub file_type: FourCC,
273}
274
275#[derive(Debug)]
276pub struct FmtChunk {
277 pub id: FourCC,
278 pub data_size: u32,
279 pub format: Format,
280 pub num_channels: u16,
281 pub sample_rate: u32,
282 pub byte_rate: u32,
283 pub block_align: u16,
284 pub bits_per_raw_sample: u16,
285 pub extra_info_size: u16,
286 pub extended_info: Option<ExtendedInfo>,
287}
288
289#[derive(Debug)]
290pub struct ExtendedInfo {
291 pub bits_per_coded_sample: u16,
292 pub channel_mask: u32,
293 pub sub_format: u128,
294 pub remaining_data: Vec<u8>,
295}
296
297#[derive(Debug)]
298pub struct FactChunk {
299 pub id: FourCC,
300 pub data_size: u32,
301 pub sample_length: u32,
302 pub remaining_data: Vec<u8>,
303}
304
305#[derive(Debug)]
306pub struct OtherChunk {
307 pub id: FourCC,
308 pub data_size: u32,
309 pub data: Vec<u8>,
310}
311
312#[derive(Debug)]
313pub struct DataChunk {
314 pub id: FourCC,
315 pub data_size: u32,
316 pub pad_byte: u8,
317}
318
319#[derive(Debug, PartialEq, Clone)]
320pub enum FourCC {
321 Riff,
322 Fmt,
323 Data,
324 Wave,
325 Fact,
326 Other(String),
327}
328
329impl From<&[u8]> for FourCC {
330 #[allow(clippy::unreadable_literal)]
331 fn from(data: &[u8]) -> Self {
332 match data {
333 b"RIFF" => FourCC::Riff,
334 b"WAVE" => FourCC::Wave,
335 b"fmt " => FourCC::Fmt,
336 b"data" => FourCC::Data,
337 b"Data" => FourCC::Data,
338 b"fact" => FourCC::Fact,
339 _ => {
340 let fourcc = unsafe { std::str::from_utf8_unchecked(&data) };
341 FourCC::Other(fourcc.to_owned())
342 }
343 }
344 }
345}
346
347#[derive(Debug, Copy, Clone)]
348pub enum Format {
349 UncompressedPCM,
350 IeeeFloatingPoint,
351 G711ALaw,
352 G711ULaw,
353 ExtendedWave,
354 Other(u16),
355}
356
357impl From<u16> for Format {
358 fn from(format: u16) -> Self {
359 match format {
360 1 => Format::UncompressedPCM,
361 3 => Format::IeeeFloatingPoint,
362 6 => Format::G711ALaw,
363 7 => Format::G711ULaw,
364 65534 => Format::ExtendedWave,
365 _ => Format::Other(format),
366 }
367 }
368}
369
370impl<T: Read + Seek> std::fmt::Display for RiffWaveReader<T> {
371 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
372 let size = self.riff_chunk.file_size;
373 let format = self.fmt_chunk.format;
374 let num_channels = self.fmt_chunk.num_channels;
375 let sample_rate = self.fmt_chunk.sample_rate;
376 let byte_rate = self.fmt_chunk.byte_rate;
377 let block_align = self.fmt_chunk.block_align;
378 let bits_per_sample = self.fmt_chunk.bits_per_raw_sample;
379 let extra_info_size = self.fmt_chunk.extra_info_size;
380
381 let extended = if let Some(extended) = &self.fmt_chunk.extended_info {
382 format!(
383 "\n----- Extended -----
384Bits per Coded: {}
385Channel Mask: {:#018b}
386Sub Format: {:x}
387Remaining Data: {:x?}",
388 extended.bits_per_coded_sample,
389 extended.channel_mask,
390 extended.sub_format,
391 extended.remaining_data,
392 )
393 } else {
394 String::from("")
395 };
396
397 let fact = if let Some(fact) = &self.fact_chunk {
398 format!(
399 "\n------- Fact -------
400Fact Length: {}
401Sample Length: {}
402Remaining Data: {:x?}",
403 fact.data_size, fact.sample_length, fact.remaining_data,
404 )
405 } else {
406 String::from("")
407 };
408
409 let other_chunks = {
410 let chunk_ids = self
411 .other_chunks
412 .iter()
413 .map(|c| {
414 if let FourCC::Other(id) = &c.id {
415 id.clone()
416 } else {
417 String::from("")
418 }
419 })
420 .collect::<Vec<_>>();
421
422 if chunk_ids.is_empty() {
423 String::from("")
424 } else {
425 format!(
426 "\n--- Other Chunks ---
427Chunk Ids: {:?}",
428 chunk_ids
429 )
430 }
431 };
432
433 let data = format!(
434 "\n------- Data -------
435Data Length: {}
436Padding Byte: {}",
437 self.data_chunk.data_size, self.data_chunk.pad_byte
438 );
439
440 write!(
441 f,
442 "------ Header ------
443Size: {}
444Format: {:?}
445Channels: {}
446Sample Rate: {}
447Byte Rate: {}
448Block Align: {}
449Bits per Raw: {}
450Extra Info: {}{}{}{}{}",
451 size,
452 format,
453 num_channels,
454 sample_rate,
455 byte_rate,
456 block_align,
457 bits_per_sample,
458 extra_info_size,
459 extended,
460 fact,
461 other_chunks,
462 data
463 )
464 }
465}