use std::fs::File; use super::parser::Parser; use super::fourcc::{FourCC, FMT__SIG, BEXT_SIG, DATA_SIG}; use super::errors::Error as ParserError; use super::raw_chunk_reader::RawChunkReader; use super::chunks::{WaveFmt, Bext}; use super::audio_frame_reader::AudioFrameReader; use super::chunks::ReadBWaveChunks; //use super::validation; use std::io::SeekFrom::{Start}; use std::io::{Read, Seek}; /** * Wave, Broadcast-WAV and RF64/BW64 parser/reader. * * ## Resources * * ### Implementation of Broadcast Wave Files * - [EBU Tech 3285][ebu3285] (May 2011), "Specification of the Broadcast Wave Format (BWF)" * * * ### Implementation of 64-bit Wave Files * - [ITU-R 2088][itu2088] (October 2019), "Long-form file format for the international exchange of audio programme materials with metadata" * - Presently in force, adopted by the EBU in [EBU Tech 3306v2][ebu3306v2] (June 2018). * * - [EBU Tech 3306v1][ebu3306v1] (July 2009), "MBWF / RF64: An extended File Format for Audio" * - No longer in force, however long-established. * * * ### Implementation of Wave format `fmt` chunk * - [MSDN WAVEFORMATEX](https://docs.microsoft.com/en-us/windows/win32/api/mmeapi/ns-mmeapi-waveformatex) * - [MSDN WAVEFORMATEXTENSIBLE](https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatextensible) * * * ### Other resources * - [RFC 3261][rfc3261] (June 1998) "WAVE and AVI Codec Registries" * - [Peter Kabal, McGill University](http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html) * - [Multimedia Programming Interface and Data Specifications 1.0](http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf) * IBM Corporation and Microsoft Corporation, (August 1991) * * [ebu3285]: https://tech.ebu.ch/docs/tech/tech3285.pdf * [ebu3306v1]: https://tech.ebu.ch/docs/tech/tech3306v1_1.pdf * [ebu3306v2]: https://tech.ebu.ch/docs/tech/tech3306.pdf * [itu2088]: https://www.itu.int/dms_pubrec/itu-r/rec/bs/R-REC-BS.2088-1-201910-I!!PDF-E.pdf * [rfc3261]: https://tools.ietf.org/html/rfc2361 */ #[derive(Debug)] pub struct WaveReader { pub inner: R, } impl WaveReader { /** * Open a file for reading. * * A convenience that opens `path` and calls `Self::new()` */ pub fn open(path: &str) -> Result { let inner = File::open(path)?; return Ok( Self::new(inner)? ) } } impl WaveReader { /** * Wrap a `Read` struct in a new `WaveReader`. * * This is the primary entry point into the `WaveReader` interface. The * stream passed as `inner` must be at the beginning of the header of the * WAVE data. For a .wav file, this means it must be at the start of the * file. * * This function does a minimal validation on the provided stream and * will return an `Err(errors::Error)` immediately if there is a structural * inconsistency that makes the stream unreadable or if it's missing * essential components that make interpreting the audio data impoossible. */ pub fn new(inner: R) -> Result { let mut retval = Self { inner }; retval.validate_readable()?; Ok(retval) } /** * Unwrap and reliqnish ownership of the inner reader. */ pub fn into_inner(self) -> R { return self.inner; } /** * Create an `AudioFrameReader` for reading each audio frame. */ pub fn audio_frame_reader(&mut self) -> Result>, ParserError> { let format = self.format()?; let audio_chunk_reader = self.chunk_reader(DATA_SIG, 0)?; Ok(AudioFrameReader::new(audio_chunk_reader, format)) } /** * The count of audio frames in the file. */ pub fn frame_length(&mut self) -> Result { let (_, data_length ) = self.get_chunk_extent_at_index(DATA_SIG, 0)?; let format = self.format()?; Ok( data_length / (format.block_alignment as u64) ) } /** * Sample and frame format of this wave file. */ pub fn format(&mut self) -> Result { self.chunk_reader(FMT__SIG, 0)?.read_wave_fmt() } /** * The Broadcast-WAV metadata record for this file. */ pub fn broadcast_extension(&mut self) -> Result { self.chunk_reader(BEXT_SIG, 0)?.read_bext() } } impl WaveReader { /* Private Implementation */ fn chunk_reader(&mut self, signature: FourCC, at_index: u32) -> Result, ParserError> { let (start, length) = self.get_chunk_extent_at_index(signature, at_index)?; Ok( RawChunkReader::new(&mut self.inner, start, length) ) } pub fn get_chunk_extent_at_index(&mut self, fourcc: FourCC, index: u32) -> Result<(u64,u64), ParserError> { let p = Parser::make(&mut self.inner)?.into_chunk_list()?; if let Some(chunk) = p.iter().filter(|item| item.signature == fourcc).nth(index as usize) { Ok ((chunk.start, chunk.length)) } else { Err( ParserError::ChunkMissing { signature : fourcc }) } } }