From 9a275a69c3249e4005732e457a63eb9ffb5acc79 Mon Sep 17 00:00:00 2001 From: Jamie Hardt Date: Fri, 25 Dec 2020 12:30:08 -0800 Subject: [PATCH] Writer impl in progress --- README.md | 2 +- src/audio_frame_writer.rs | 45 ++++++------ src/fourcc.rs | 1 + src/parser.rs | 1 + src/wavewriter.rs | 140 +++++++++++++++++++++++++++++++------- 5 files changed, 138 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 1d43bc9..255fe65 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This is currently a work-in-progress! However many features presently work: | EBU Broadcast-WAVE metadata | ☑️ | | | Basic iXML/ADM metadata | ☑️ | | | Enhanced iXML metadata support | | | -| Broadcast-WAVE Level metadata | | | +| Broadcast-WAVE Level overview `levl` metadata | | | | Cue list metadata | ☑️ | | | Sampler and instrument metadata | | | | Enhanced Wave file form validation | ☑️ | 🚫 | diff --git a/src/audio_frame_writer.rs b/src/audio_frame_writer.rs index 0f331e4..8e1b42c 100644 --- a/src/audio_frame_writer.rs +++ b/src/audio_frame_writer.rs @@ -1,4 +1,4 @@ -use std::io::{Write,Seek}; +use std::io::{Write,Seek,SeekFrom}; use super::wavewriter::WaveWriter; use super::errors::Error; @@ -11,36 +11,33 @@ pub struct AudioFrameWriter { inner : W, form_size : u64, data_size : u64, + data_start : u64, format: WaveFmt } -impl AudioFrameWriter { - pub fn make(wave_writer : WaveWriter) -> Self { - Self { - inner: wave_writer.inner, - form_size: wave_writer.form_size, - data_size: 0u64, - format : wave_writer.format - } +impl AudioFrameWriter { + + pub fn new(inner: W, format: WaveFmt) -> Self { + todo!(); } - pub fn write_integer_frame(&mut self, buffer: &mut [i32]) -> Result { + pub fn write_audio_frame(&mut self, buffer: &[i32]) -> Result { assert!(buffer.len() as u16 == self.format.channel_count, - "write_integer_frame was called with a mis-sized buffer, expected {}, was {}", - self.format.channel_count, buffer.len()); + "read_integer_frame was called with a mis-sized buffer, expected {}, was {}", + self.format.channel_count, buffer.len()); - let framed_bits_per_sample = self.format.block_alignment * 8 / self.format.channel_count; - - for n in 0..(self.format.channel_count as usize) { - match (self.format.bits_per_sample, framed_bits_per_sample) { - (0..=8,8) => self.inner.write_u8(buffer[n] as u8 + 0x80_u8)?, // EBU 3285 §A2.2 - (9..=16,16) => self.inner.write_i16::(buffer[n] as i16)?, - (10..=24,24) => self.inner.write_i24::(buffer[n])?, - (25..=32,32) => self.inner.write_i32::(buffer[n])?, - (b,_)=> panic!("Unrecognized integer format, bits per sample {}, channels {}, block_alignment {}", - b, self.format.channel_count, self.format.block_alignment) - } + let framed_bits_per_sample = self.format.block_alignment * 8 / self.format.channel_count; + for n in 0..(self.format.channel_count as usize) { + match (self.format.bits_per_sample, framed_bits_per_sample) { + (0..=8,8) => self.inner.write_u8(( buffer[n] + 0x80) as u8 )?, // EBU 3285 §A2.2 + (9..=16,16) => self.inner.write_i16::(buffer[n] as i16)?, + (10..=24,24) => self.inner.write_i24::(buffer[n])?, + (25..=32,32) => self.inner.write_i32::(buffer[n])?, + (b,_)=> panic!("Unrecognized integer format, bits per sample {}, channels {}, block_alignment {}", + b, self.format.channel_count, self.format.block_alignment) } - Ok( 1 ) + } + + Ok( 1 ) } } \ No newline at end of file diff --git a/src/fourcc.rs b/src/fourcc.rs index a99cbb0..7a6555b 100644 --- a/src/fourcc.rs +++ b/src/fourcc.rs @@ -102,6 +102,7 @@ pub const DATA_SIG: FourCC = FourCC::make(b"data"); pub const FMT__SIG: FourCC = FourCC::make(b"fmt "); pub const BEXT_SIG: FourCC = FourCC::make(b"bext"); +pub const FACT_SIG: FourCC = FourCC::make(b"fact"); pub const JUNK_SIG: FourCC = FourCC::make(b"JUNK"); pub const FLLR_SIG: FourCC = FourCC::make(b"FLLR"); diff --git a/src/parser.rs b/src/parser.rs index eb718b4..09e7ca0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -45,6 +45,7 @@ pub struct Parser { ds64state: HashMap } +#[derive(Debug, PartialEq, Eq)] pub struct ChunkIteratorItem { pub signature: FourCC, pub start: u64, diff --git a/src/wavewriter.rs b/src/wavewriter.rs index 8820676..2407889 100644 --- a/src/wavewriter.rs +++ b/src/wavewriter.rs @@ -1,12 +1,19 @@ +use std::collections::HashMap; use std::io::{Write, Seek, SeekFrom}; use std::fs::File; use std::io::Cursor; use super::errors::Error; -use super::chunks::{WriteBWaveChunks}; -use super::fmt::{WaveFmt}; -use super::fourcc::{FourCC, RIFF_SIG, WAVE_SIG, FMT__SIG, JUNK_SIG, BEXT_SIG, DATA_SIG, FLLR_SIG, WriteFourCC}; -use super::audio_frame_writer::AudioFrameWriter; +use super::chunks::WriteBWaveChunks; +use super::fmt::WaveFmt; + +use super::common_format::CommonFormat; +use super::fourcc::{FourCC, RIFF_SIG, RF64_SIG, WAVE_SIG, FMT__SIG, JUNK_SIG, + DS64_SIG, FACT_SIG, DATA_SIG, BEXT_SIG, FLLR_SIG, WriteFourCC}; + + use super::bext::Bext; + +//use super::audio_frame_writer::AudioFrameWriter; use byteorder::LittleEndian; use byteorder::WriteBytesExt; @@ -15,51 +22,90 @@ use byteorder::WriteBytesExt; pub struct WaveWriter where W: Write + Seek { pub inner : W, pub form_size : u64, - pub format : WaveFmt + pub format : WaveFmt, + pub ds64_sizes : Option>, + pub bext_start : Option, + pub fact_start : Option, } impl WaveWriter { - fn create(path: &str, format: WaveFmt) -> Result { + pub fn create(path: &str, format: WaveFmt, broadcast_extension: Option) -> Result { let f = File::create(path)?; - Self::new(f, format) + Self::new(f, format, broadcast_extension) } } impl WaveWriter { /// Wrap a `Write` struct with a wavewriter. - fn new(inner : W, format: WaveFmt) -> Result { - let mut retval = Self { inner, form_size : 0 , format: format}; + pub fn new(inner : W, format: WaveFmt, broadcast_extension : Option) -> Result { + let mut retval = Self { inner, form_size : 0, format: format, + ds64_sizes : None, + bext_start : None, + fact_start : None, + }; + retval.inner.seek(SeekFrom::Start(0))?; retval.inner.write_fourcc(RIFF_SIG)?; retval.inner.write_u32::(0)?; retval.inner.write_fourcc(WAVE_SIG)?; retval.update_form_size(4)?; - retval.write_ds64_reservation()?; - retval.write_format(format)?; + + retval.append_head_chunks(format, broadcast_extension)?; + Ok( retval ) } /// Unwrap the inner writer. - fn into_inner(self) -> W { + pub fn into_inner(self) -> W { return self.inner; } - /// Return an AudioFrameWriter, consuming the reader. - fn audio_frame_writer(mut self) -> Result, Error> { + pub fn audio_frame_writer() { - let framing = 0x4000; - self.append_data_framing_chunk(framing)?; + } - self.inner.write_fourcc(DATA_SIG)?; - self.inner.write_u32::(0u32)?; - self.update_form_size(8)?; +} - Ok( AudioFrameWriter::make(self) ) + +impl WaveWriter { /* Private implementation */ + + fn append_head_chunks(&mut self, format : WaveFmt, broadcast_extension : Option) -> Result<(),Error> { + self.write_ds64_reservation()?; + self.write_format(format)?; + + if format.common_format() != CommonFormat::IntegerPCM { + self.append_fact_chunk()?; + } + + if let Some(bext) = broadcast_extension { + self.append_bext_chunk(bext)?; + } + + self.append_data_framing_chunk(0x4000)?; + + Ok(()) + } + + fn append_fact_chunk(&mut self) -> Result<(),Error> { + let buf = vec![0u8; 4]; + self.fact_start = Some( self.inner.seek(SeekFrom::Current(0))? + 8); + self.append_chunk(FACT_SIG, &buf)?; + Ok(()) + } + + fn append_bext_chunk(&mut self, bext: Bext) -> Result<(),Error> { + let buf = vec![0u8;0]; + let mut cursor = Cursor::new(buf); + cursor.write_bext(&bext)?; + let buf = cursor.into_inner(); + self.bext_start = Some( self.inner.seek(SeekFrom::Current(0))? + 8); + self.append_chunk(BEXT_SIG, &buf)?; + Ok(()) } fn append_data_framing_chunk(&mut self, framing: u64) -> Result<(), Error> { let current_length = self.inner.seek(SeekFrom::End(0))?; - let size_to_add = (current_length % framing) - 8; + let size_to_add = framing - ((current_length % framing) - 8); let chunk_size_to_add = size_to_add - 8; let buf = vec![ 0u8; chunk_size_to_add as usize]; @@ -83,10 +129,6 @@ impl WaveWriter { self.update_form_size(total_chunk_size)?; Ok( () ) } -} - - -impl WaveWriter { /* Private implementation */ fn write_ds64_reservation(&mut self) -> Result<(), Error> { let ds64_reservation_data = vec![0u8; 92]; @@ -113,6 +155,52 @@ impl WaveWriter { /* Private implementation */ } fn update_form_size_ds64(&mut self, new_size: u64) -> Result<(), Error> { - todo!() + if self.ds64_sizes.is_none() { + self.inner.seek(SeekFrom::Start(0))?; + self.inner.write_fourcc(RF64_SIG)?; + self.inner.seek(SeekFrom::Start(12))?; + self.inner.write_fourcc(DS64_SIG)?; + self.ds64_sizes = Some( HashMap::new() ); + } + + self.inner.seek(SeekFrom::Start(20))?; + self.inner.write_u64::(new_size)?; + + Ok(()) } } + +#[test] +fn test_simple_create() { + use super::fourcc::ReadFourCC; + use byteorder::ReadBytesExt; + + let buf = vec![0u8; 0]; + + let mut cursor = Cursor::new(buf); + let format = WaveFmt::new_pcm(48000, 24, 1); + + let w = WaveWriter::new(cursor, format, None).unwrap(); + + cursor = w.into_inner(); + + cursor.seek(SeekFrom::Start(0)).unwrap(); + + assert_eq!( cursor.read_fourcc().unwrap(), RIFF_SIG); + let form_size = cursor.read_u32::().unwrap(); + assert_eq!( cursor.read_fourcc().unwrap(), WAVE_SIG); + + assert_eq!( cursor.read_fourcc().unwrap(), JUNK_SIG); + let junk_size = cursor.read_u32::().unwrap(); + cursor.seek(SeekFrom::Current(junk_size as i64)).unwrap(); + + assert_eq!( cursor.read_fourcc().unwrap(), FMT__SIG); + let fmt_size = cursor.read_u32::().unwrap(); + cursor.seek(SeekFrom::Current(fmt_size as i64)).unwrap(); + + assert_eq!( cursor.read_fourcc().unwrap(), FLLR_SIG); + let junk2_size = cursor.read_u32::().unwrap(); + cursor.seek(SeekFrom::Current(junk2_size as i64)).unwrap(); + + assert_eq!( form_size , junk2_size + junk_size + fmt_size + 4 + 8 * 3); +}