diff --git a/src/audio_frame_reader.rs b/src/audio_frame_reader.rs index b4d4a0f..e9b13ef 100644 --- a/src/audio_frame_reader.rs +++ b/src/audio_frame_reader.rs @@ -62,13 +62,6 @@ impl AudioFrameReader { Ok( (seek_result - self.start) / self.format.block_alignment as u64 ) } - /// Create a frame buffer sized to hold frames of the reader - /// - /// This is a conveneince method that creates a `Vec` with - /// as many elements as there are channels in the underlying stream. - pub fn create_frame_buffer(&self) -> Vec { - vec![0i32; self.format.channel_count as usize] - } /// Read a frame /// diff --git a/src/audio_frame_writer.rs b/src/audio_frame_writer.rs new file mode 100644 index 0000000..0f331e4 --- /dev/null +++ b/src/audio_frame_writer.rs @@ -0,0 +1,46 @@ +use std::io::{Write,Seek}; + +use super::wavewriter::WaveWriter; +use super::errors::Error; +use super::fmt::WaveFmt; + +use byteorder::LittleEndian; +use byteorder::WriteBytesExt; + +pub struct AudioFrameWriter { + inner : W, + form_size : u64, + data_size : 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 + } + } + + pub fn write_integer_frame(&mut self, buffer: &mut [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()); + + 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) + } + } + Ok( 1 ) + } +} \ No newline at end of file diff --git a/src/fmt.rs b/src/fmt.rs index 146a3ea..b4ab4a8 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -212,6 +212,15 @@ impl WaveFmt { CommonFormat::make( self.tag, self.extended_format.map(|ext| ext.type_guid)) } + /// Create a frame buffer sized to hold frames for a reader or writer + /// + /// This is a conveneince method that creates a `Vec` with + /// as many elements as there are channels in the underlying stream. + pub fn create_frame_buffer(&self) -> Vec { + vec![0i32; self.channel_count as usize] + } + + /// Channel descriptors for each channel. pub fn channels(&self) -> Vec { match self.channel_count { diff --git a/src/lib.rs b/src/lib.rs index 48b1e2a..5441b9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,6 +112,7 @@ mod common_format; mod parser; mod audio_frame_reader; +mod audio_frame_writer; mod list_form; mod chunks; diff --git a/src/wavereader.rs b/src/wavereader.rs index eaad8cb..1a750a6 100644 --- a/src/wavereader.rs +++ b/src/wavereader.rs @@ -28,7 +28,7 @@ use std::io::{Read, Seek}; * assert_eq!(format.channel_count, 1); * * let mut frame_reader = r.audio_frame_reader().unwrap(); - * let mut buffer = frame_reader.create_frame_buffer(); + * let mut buffer = format.create_frame_buffer(); * * let read = frame_reader.read_integer_frame(&mut buffer).unwrap(); * diff --git a/src/wavewriter.rs b/src/wavewriter.rs index 5e824fb..8820676 100644 --- a/src/wavewriter.rs +++ b/src/wavewriter.rs @@ -4,17 +4,18 @@ use std::io::Cursor; use super::errors::Error; use super::chunks::{WriteBWaveChunks}; -use super::bext::Bext; use super::fmt::{WaveFmt}; -use super::fourcc::{FourCC, RIFF_SIG, WAVE_SIG, FMT__SIG, JUNK_SIG, BEXT_SIG, DATA_SIG, WriteFourCC}; +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 byteorder::LittleEndian; use byteorder::WriteBytesExt; /// This isn't working yet, do not use. pub struct WaveWriter where W: Write + Seek { - inner : W, - form_size : u64 + pub inner : W, + pub form_size : u64, + pub format : WaveFmt } impl WaveWriter { @@ -27,7 +28,7 @@ impl WaveWriter { impl WaveWriter { /// Wrap a `Write` struct with a wavewriter. fn new(inner : W, format: WaveFmt) -> Result { - let mut retval = Self { inner, form_size : 0 }; + let mut retval = Self { inner, form_size : 0 , format: format}; retval.inner.seek(SeekFrom::Start(0))?; retval.inner.write_fourcc(RIFF_SIG)?; retval.inner.write_u32::(0)?; @@ -43,6 +44,30 @@ impl WaveWriter { return self.inner; } + /// Return an AudioFrameWriter, consuming the reader. + fn audio_frame_writer(mut self) -> Result, Error> { + + 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) ) + } + + 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 chunk_size_to_add = size_to_add - 8; + + let buf = vec![ 0u8; chunk_size_to_add as usize]; + self.append_chunk(FLLR_SIG, &buf)?; + + Ok( () ) + } + /// Append data as a new chunk to the wave file. fn append_chunk(&mut self, ident: FourCC, data: &[u8]) -> Result<(),Error> { assert!(data.len() < (u32::MAX as usize), diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 1fa4d86..759151c 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -81,11 +81,12 @@ fn test_minimal_wave() { fn test_read() { let path = "tests/media/audacity_16bit.wav"; - let w = WaveReader::open(path).expect("Failure opening test file"); + let mut w = WaveReader::open(path).expect("Failure opening test file"); + let mut buffer = w.format().unwrap().create_frame_buffer(); let mut reader = w.audio_frame_reader().unwrap(); - let mut buffer = reader.create_frame_buffer(); + assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(buffer[0], -2823_i32); @@ -99,12 +100,11 @@ fn test_read() { fn test_locate_multichannel_read() { let path = "tests/media/ff_pink.wav"; - let w = WaveReader::open(path).expect("Failure opening test file"); + let mut w = WaveReader::open(path).expect("Failure opening test file"); + let mut buffer = w.format().unwrap().create_frame_buffer(); let mut reader = w.audio_frame_reader().unwrap(); - let mut buffer = reader.create_frame_buffer(); - assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(buffer[0], 332702_i32); assert_eq!(buffer[1], 3258791_i32);