diff --git a/src/cue.rs b/src/cue.rs index bf43f18..c8d499e 100644 --- a/src/cue.rs +++ b/src/cue.rs @@ -46,15 +46,14 @@ impl RawLabel { fn read_from(data : &[u8]) -> Result { let mut rdr = Cursor::new(data); let length = data.len(); - + Ok( Self { cue_point_id : rdr.read_u32::()?, text : { let mut buf = vec![0u8; (length - 4) as usize ]; rdr.read_exact(&mut buf)?; - if buf.len() % 2 == 1 { rdr.read_u8()?; }; + //if buf.len() % 2 == 1 { rdr.read_u8()?; }; buf - // String::from_utf8(buf).unwrap_or(String::from("")) } }) } @@ -76,9 +75,8 @@ impl RawNote { text : { let mut buf = vec![0u8; (length - 4) as usize ]; rdr.read_exact(&mut buf)?; - if length % 2 == 1 { rdr.read_u8()?; }; + //if length % 2 == 1 { rdr.read_u8()?; }; buf - //String::from_utf8(buf).unwrap_or(String::from("")) } }) } @@ -113,7 +111,7 @@ impl RawLtxt { if length - 20 > 0 { let mut buf = vec![0u8; (length - 20) as usize]; rdr.read_exact(&mut buf)?; - if length % 2 == 1 { rdr.read_u8()?; }; + //if length % 2 == 1 { rdr.read_u8()?; }; Some( buf ) //Some( String::from_utf8(buf).unwrap_or(String::from("")) ) } else { @@ -223,6 +221,7 @@ impl Cue { } else { raw_adtl = vec![]; } + Ok( raw_cues.iter() diff --git a/src/fourcc.rs b/src/fourcc.rs index dc852fc..a99cbb0 100644 --- a/src/fourcc.rs +++ b/src/fourcc.rs @@ -105,6 +105,7 @@ pub const BEXT_SIG: FourCC = FourCC::make(b"bext"); pub const JUNK_SIG: FourCC = FourCC::make(b"JUNK"); pub const FLLR_SIG: FourCC = FourCC::make(b"FLLR"); +pub const LIST_SIG: FourCC = FourCC::make(b"LIST"); pub const CUE__SIG: FourCC = FourCC::make(b"cue "); pub const ADTL_SIG: FourCC = FourCC::make(b"adtl"); diff --git a/src/lib.rs b/src/lib.rs index 095a8b7..bf09aab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ production. Apps we test against: - Avid Pro Tools +- iZotope RX Audio Editor - FFMpeg - Audacity @@ -130,3 +131,4 @@ pub use bext::Bext; pub use fmt::{WaveFmt, WaveFmtExtended, ChannelDescriptor, ChannelMask}; pub use common_format::CommonFormat; pub use audio_frame_reader::AudioFrameReader; +pub use cue::Cue; \ No newline at end of file diff --git a/src/list_form.rs b/src/list_form.rs index 61046d7..4890617 100644 --- a/src/list_form.rs +++ b/src/list_form.rs @@ -21,11 +21,20 @@ pub fn collect_list_form(list_contents :& [u8]) -> Result, Err while remain > 0 { let this_sig = cursor.read_fourcc()?; let this_size = cursor.read_u32::()? as usize; + remain -= 8; let mut content_buf = vec![0u8; this_size]; - cursor.read_exact(&mut content_buf)?; + remain -= this_size; + retval.push( ListFormItem { signature : this_sig, contents : content_buf } ); + + if this_size % 2 == 1 { + cursor.read_u8()?; + //panic!("Got this far!"); + remain -= 1; + } } + Ok( retval ) } \ No newline at end of file diff --git a/src/raw_chunk_reader.rs b/src/raw_chunk_reader.rs index e292d6a..5805475 100644 --- a/src/raw_chunk_reader.rs +++ b/src/raw_chunk_reader.rs @@ -28,7 +28,7 @@ impl<'a,R: Read + Seek> RawChunkReader<'a, R> { impl<'a, R:Read + Seek> Read for RawChunkReader<'_, R> { fn read(&mut self, buf: &mut [u8]) -> Result { if self.position >= self.length { - Err(Error::new(ErrorKind::UnexpectedEof, "RawChunkReader encountered end-of-file")) + Ok(0) } else { self.reader.seek(Start(self.start + self.position))?; let to_read = min(self.length - self.position, buf.len() as u64); diff --git a/src/wavereader.rs b/src/wavereader.rs index b3986e4..6426957 100644 --- a/src/wavereader.rs +++ b/src/wavereader.rs @@ -2,7 +2,7 @@ use std::fs::File; use super::parser::Parser; -use super::fourcc::{FourCC, FMT__SIG,DATA_SIG, BEXT_SIG, JUNK_SIG, FLLR_SIG, CUE__SIG, ADTL_SIG}; +use super::fourcc::{FourCC, ReadFourCC, FMT__SIG,DATA_SIG, BEXT_SIG, LIST_SIG, JUNK_SIG, FLLR_SIG, CUE__SIG, ADTL_SIG}; use super::errors::Error as ParserError; use super::raw_chunk_reader::RawChunkReader; use super::fmt::{WaveFmt, ChannelDescriptor, ChannelMask}; @@ -146,8 +146,9 @@ impl WaveReader { /// Returns a vector of channel descriptors, one for each channel /// /// ```rust - /// # use bwavfile::WaveReader; - /// # use bwavfile::ChannelMask; + /// use bwavfile::WaveReader; + /// use bwavfile::ChannelMask; + /// /// let mut f = WaveReader::open("tests/media/pt_24bit_51.wav").unwrap(); /// /// let chans = f.channels().unwrap(); @@ -174,20 +175,36 @@ impl WaveReader { /// Read cue points. /// + /// ```rust + /// use bwavfile::WaveReader; + /// use bwavfile::Cue; /// + /// let mut f = WaveReader::open("tests/media/izotope_test.wav").unwrap(); + /// let cue_points = f.cue_points().unwrap(); + /// + /// assert_eq!(cue_points.len(), 3); + /// assert_eq!(cue_points[0].ident, 1); + /// assert_eq!(cue_points[0].frame, 12532); + /// //assert_eq!(cue_points[0].label, Some(String::from("Marker 1"))); + /// + /// assert_eq!(cue_points[1].ident, 2); + /// assert_eq!(cue_points[1].frame, 20997); + /// + /// assert_eq!(cue_points[2].ident, 3); + /// assert_eq!(cue_points[2].frame, 26711); + /// ``` pub fn cue_points(&mut self) -> Result,ParserError> { let mut cue_buffer : Vec = vec![]; let mut adtl_buffer : Vec = vec![]; let cue_read = self.read_chunk(CUE__SIG, 0, &mut cue_buffer)?; - let adtl_read = self.read_chunk(ADTL_SIG, 0, &mut adtl_buffer)?; + let adtl_read = self.read_list(ADTL_SIG, &mut adtl_buffer)?; match (cue_read, adtl_read) { (0,_) => Ok( vec![] ), (_,0) => Ok( Cue::collect_from(&cue_buffer, None)? ), (_,_) => Ok( Cue::collect_from(&cue_buffer, Some(&adtl_buffer) )? ) } - } /// Read iXML data. @@ -352,13 +369,26 @@ impl WaveReader { } } -impl WaveReader { /* Private Implementation */ +impl WaveReader { + + // Private implementation + // + // As time passes thi get smore obnoxious because I haven't implemented recursive chunk + // parsing in the raw parser and I'm working around it 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) ) } + fn read_list(&mut self, ident: FourCC, buffer: &mut Vec) -> Result { + if let Some(index) = self.get_list_form(ident)? { + self.read_chunk(LIST_SIG, index, buffer) + } else { + Ok( 0 ) + } + } + fn read_chunk(&mut self, ident: FourCC, at: u32, buffer: &mut Vec) -> Result { let result = self.chunk_reader(ident, at); @@ -374,14 +404,43 @@ impl WaveReader { /* Private Implementation */ } } - fn get_chunk_extent_at_index(&mut self, fourcc: FourCC, index: u32) -> Result<(u64,u64), ParserError> { + /// Extent of every chunk with the given fourcc + fn get_chunks_extents(&mut self, fourcc: FourCC) -> Result, 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)) + Ok( p.iter().filter(|item| item.signature == fourcc) + .map(|item| (item.start, item.length)).collect() ) + } + + /// Index of first LIST for with the given FORM fourcc + fn get_list_form(&mut self, fourcc: FourCC) -> Result, ParserError> { + for (n, (start, length)) in self.get_chunks_extents(LIST_SIG)?.iter().enumerate() { + let mut reader = RawChunkReader::new(&mut self.inner, *start, *length); + let this_fourcc = reader.read_fourcc()?; + if this_fourcc == fourcc { + return Ok( Some( n as u32 ) ); + } + } + + Ok( None ) + } + + fn get_chunk_extent_at_index(&mut self, fourcc: FourCC, index: u32) -> Result<(u64,u64), ParserError> { + if let Some((start, length)) = self.get_chunks_extents(fourcc)?.iter().nth(index as usize) { + Ok ((*start, *length)) } else { - Err( ParserError::ChunkMissing { signature : fourcc }) + Err( ParserError::ChunkMissing { signature : fourcc } ) } } } +#[test] +fn test_list_form() { + let mut f = WaveReader::open("tests/media/izotope_test.wav").unwrap(); + let mut buf : Vec = vec![]; + + f.read_list(ADTL_SIG, &mut buf).unwrap(); + + assert_ne!(buf.len(), 0); + +} \ No newline at end of file