riff_wave_reader/
lib.rs

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}