Cue lists in progress

Need to clean up zero-terminated strings in adtl
This commit is contained in:
Jamie Hardt
2020-12-10 14:48:25 -08:00
parent c947904d0f
commit 8519854596
6 changed files with 88 additions and 18 deletions

View File

@@ -46,15 +46,14 @@ impl RawLabel {
fn read_from(data : &[u8]) -> Result<Self, Error> { fn read_from(data : &[u8]) -> Result<Self, Error> {
let mut rdr = Cursor::new(data); let mut rdr = Cursor::new(data);
let length = data.len(); let length = data.len();
Ok( Self { Ok( Self {
cue_point_id : rdr.read_u32::<LittleEndian>()?, cue_point_id : rdr.read_u32::<LittleEndian>()?,
text : { text : {
let mut buf = vec![0u8; (length - 4) as usize ]; let mut buf = vec![0u8; (length - 4) as usize ];
rdr.read_exact(&mut buf)?; rdr.read_exact(&mut buf)?;
if buf.len() % 2 == 1 { rdr.read_u8()?; }; //if buf.len() % 2 == 1 { rdr.read_u8()?; };
buf buf
// String::from_utf8(buf).unwrap_or(String::from("<TEXT ENCODING ERROR>"))
} }
}) })
} }
@@ -76,9 +75,8 @@ impl RawNote {
text : { text : {
let mut buf = vec![0u8; (length - 4) as usize ]; let mut buf = vec![0u8; (length - 4) as usize ];
rdr.read_exact(&mut buf)?; rdr.read_exact(&mut buf)?;
if length % 2 == 1 { rdr.read_u8()?; }; //if length % 2 == 1 { rdr.read_u8()?; };
buf buf
//String::from_utf8(buf).unwrap_or(String::from("<TEXT ENCODING ERROR>"))
} }
}) })
} }
@@ -113,7 +111,7 @@ impl RawLtxt {
if length - 20 > 0 { if length - 20 > 0 {
let mut buf = vec![0u8; (length - 20) as usize]; let mut buf = vec![0u8; (length - 20) as usize];
rdr.read_exact(&mut buf)?; rdr.read_exact(&mut buf)?;
if length % 2 == 1 { rdr.read_u8()?; }; //if length % 2 == 1 { rdr.read_u8()?; };
Some( buf ) Some( buf )
//Some( String::from_utf8(buf).unwrap_or(String::from("<TEXT ENCODING ERROR>")) ) //Some( String::from_utf8(buf).unwrap_or(String::from("<TEXT ENCODING ERROR>")) )
} else { } else {
@@ -223,6 +221,7 @@ impl Cue {
} else { } else {
raw_adtl = vec![]; raw_adtl = vec![];
} }
Ok( Ok(
raw_cues.iter() raw_cues.iter()

View File

@@ -105,6 +105,7 @@ pub const BEXT_SIG: FourCC = FourCC::make(b"bext");
pub const JUNK_SIG: FourCC = FourCC::make(b"JUNK"); pub const JUNK_SIG: FourCC = FourCC::make(b"JUNK");
pub const FLLR_SIG: FourCC = FourCC::make(b"FLLR"); 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 CUE__SIG: FourCC = FourCC::make(b"cue ");
pub const ADTL_SIG: FourCC = FourCC::make(b"adtl"); pub const ADTL_SIG: FourCC = FourCC::make(b"adtl");

View File

@@ -15,6 +15,7 @@ production.
Apps we test against: Apps we test against:
- Avid Pro Tools - Avid Pro Tools
- iZotope RX Audio Editor
- FFMpeg - FFMpeg
- Audacity - Audacity
@@ -130,3 +131,4 @@ pub use bext::Bext;
pub use fmt::{WaveFmt, WaveFmtExtended, ChannelDescriptor, ChannelMask}; pub use fmt::{WaveFmt, WaveFmtExtended, ChannelDescriptor, ChannelMask};
pub use common_format::CommonFormat; pub use common_format::CommonFormat;
pub use audio_frame_reader::AudioFrameReader; pub use audio_frame_reader::AudioFrameReader;
pub use cue::Cue;

View File

@@ -21,11 +21,20 @@ pub fn collect_list_form(list_contents :& [u8]) -> Result<Vec<ListFormItem>, Err
while remain > 0 { while remain > 0 {
let this_sig = cursor.read_fourcc()?; let this_sig = cursor.read_fourcc()?;
let this_size = cursor.read_u32::<LittleEndian>()? as usize; let this_size = cursor.read_u32::<LittleEndian>()? as usize;
remain -= 8;
let mut content_buf = vec![0u8; this_size]; let mut content_buf = vec![0u8; this_size];
cursor.read_exact(&mut content_buf)?; cursor.read_exact(&mut content_buf)?;
remain -= this_size;
retval.push( ListFormItem { signature : this_sig, contents : content_buf } ); 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 ) Ok( retval )
} }

View File

@@ -28,7 +28,7 @@ impl<'a,R: Read + Seek> RawChunkReader<'a, R> {
impl<'a, R:Read + Seek> Read for RawChunkReader<'_, R> { impl<'a, R:Read + Seek> Read for RawChunkReader<'_, R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if self.position >= self.length { if self.position >= self.length {
Err(Error::new(ErrorKind::UnexpectedEof, "RawChunkReader encountered end-of-file")) Ok(0)
} else { } else {
self.reader.seek(Start(self.start + self.position))?; self.reader.seek(Start(self.start + self.position))?;
let to_read = min(self.length - self.position, buf.len() as u64); let to_read = min(self.length - self.position, buf.len() as u64);

View File

@@ -2,7 +2,7 @@
use std::fs::File; use std::fs::File;
use super::parser::Parser; 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::errors::Error as ParserError;
use super::raw_chunk_reader::RawChunkReader; use super::raw_chunk_reader::RawChunkReader;
use super::fmt::{WaveFmt, ChannelDescriptor, ChannelMask}; use super::fmt::{WaveFmt, ChannelDescriptor, ChannelMask};
@@ -146,8 +146,9 @@ impl<R: Read + Seek> WaveReader<R> {
/// Returns a vector of channel descriptors, one for each channel /// Returns a vector of channel descriptors, one for each channel
/// ///
/// ```rust /// ```rust
/// # use bwavfile::WaveReader; /// use bwavfile::WaveReader;
/// # use bwavfile::ChannelMask; /// use bwavfile::ChannelMask;
///
/// let mut f = WaveReader::open("tests/media/pt_24bit_51.wav").unwrap(); /// let mut f = WaveReader::open("tests/media/pt_24bit_51.wav").unwrap();
/// ///
/// let chans = f.channels().unwrap(); /// let chans = f.channels().unwrap();
@@ -174,20 +175,36 @@ impl<R: Read + Seek> WaveReader<R> {
/// Read cue points. /// 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<Vec<Cue>,ParserError> { pub fn cue_points(&mut self) -> Result<Vec<Cue>,ParserError> {
let mut cue_buffer : Vec<u8> = vec![]; let mut cue_buffer : Vec<u8> = vec![];
let mut adtl_buffer : Vec<u8> = vec![]; let mut adtl_buffer : Vec<u8> = vec![];
let cue_read = self.read_chunk(CUE__SIG, 0, &mut cue_buffer)?; 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) { match (cue_read, adtl_read) {
(0,_) => Ok( vec![] ), (0,_) => Ok( vec![] ),
(_,0) => Ok( Cue::collect_from(&cue_buffer, None)? ), (_,0) => Ok( Cue::collect_from(&cue_buffer, None)? ),
(_,_) => Ok( Cue::collect_from(&cue_buffer, Some(&adtl_buffer) )? ) (_,_) => Ok( Cue::collect_from(&cue_buffer, Some(&adtl_buffer) )? )
} }
} }
/// Read iXML data. /// Read iXML data.
@@ -352,13 +369,26 @@ impl<R: Read + Seek> WaveReader<R> {
} }
} }
impl<R:Read+Seek> WaveReader<R> { /* Private Implementation */ impl<R:Read+Seek> WaveReader<R> {
// 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<RawChunkReader<R>, ParserError> { fn chunk_reader(&mut self, signature: FourCC, at_index: u32) -> Result<RawChunkReader<R>, ParserError> {
let (start, length) = self.get_chunk_extent_at_index(signature, at_index)?; let (start, length) = self.get_chunk_extent_at_index(signature, at_index)?;
Ok( RawChunkReader::new(&mut self.inner, start, length) ) Ok( RawChunkReader::new(&mut self.inner, start, length) )
} }
fn read_list(&mut self, ident: FourCC, buffer: &mut Vec<u8>) -> Result<usize, ParserError> {
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<u8>) -> Result<usize, ParserError> { fn read_chunk(&mut self, ident: FourCC, at: u32, buffer: &mut Vec<u8>) -> Result<usize, ParserError> {
let result = self.chunk_reader(ident, at); let result = self.chunk_reader(ident, at);
@@ -374,14 +404,43 @@ impl<R:Read+Seek> WaveReader<R> { /* 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<Vec<(u64,u64)>, ParserError> {
let p = Parser::make(&mut self.inner)?.into_chunk_list()?; 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( p.iter().filter(|item| item.signature == fourcc)
Ok ((chunk.start, chunk.length)) .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<Option<u32>, 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 { } 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<u8> = vec![];
f.read_list(ADTL_SIG, &mut buf).unwrap();
assert_ne!(buf.len(), 0);
}