From 73d2cf8cd99f845bb15a5ba747946fe258365012 Mon Sep 17 00:00:00 2001 From: Jamie Hardt Date: Fri, 25 Dec 2020 21:58:22 -0800 Subject: [PATCH] Writer impl --- src/fourcc.rs | 2 +- src/wavereader.rs | 1 - src/wavewriter.rs | 116 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 103 insertions(+), 16 deletions(-) diff --git a/src/fourcc.rs b/src/fourcc.rs index df17a7f..53486e9 100644 --- a/src/fourcc.rs +++ b/src/fourcc.rs @@ -102,7 +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 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/wavereader.rs b/src/wavereader.rs index 1a750a6..0331fc4 100644 --- a/src/wavereader.rs +++ b/src/wavereader.rs @@ -5,7 +5,6 @@ use std::fs::File; use super::parser::Parser; 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}; use super::bext::Bext; use super::audio_frame_reader::AudioFrameReader; diff --git a/src/wavewriter.rs b/src/wavewriter.rs index 6876182..54044da 100644 --- a/src/wavewriter.rs +++ b/src/wavewriter.rs @@ -2,15 +2,48 @@ use std::fs::File; use std::io::{Write,Seek,SeekFrom}; use super::Error; -use super::fourcc::{FourCC, WriteFourCC, RIFF_SIG, WAVE_SIG, FMT__SIG,FACT_SIG}; +use super::fourcc::{FourCC, WriteFourCC, RIFF_SIG, WAVE_SIG, FMT__SIG, DATA_SIG, ELM1_SIG}; use super::fmt::WaveFmt; -use super::common_format::CommonFormat; +//use super::common_format::CommonFormat; use super::chunks::WriteBWaveChunks; use byteorder::LittleEndian; use byteorder::WriteBytesExt; +pub struct AudioFrameWriter where W: Write + Seek { + inner : WaveChunkWriter +} + +impl AudioFrameWriter where W: Write + Seek { + pub fn write_integer_frame(&mut self, buffer: &[i32]) -> Result { + let format = self.inner.inner.format; + assert!(buffer.len() as u16 == format.channel_count, + "read_integer_frame was called with a mis-sized buffer, expected {}, was {}", + format.channel_count, buffer.len()); + + let framed_bits_per_sample = format.block_alignment * 8 / format.channel_count; + + for n in 0..(format.channel_count as usize) { + match (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, format.channel_count, format.block_alignment) + } + } + + Ok(1) + } + + pub fn end(self) -> Result, Error> { + self.inner.end() + } +} + + pub struct WaveChunkWriter where W: Write + Seek { inner : WaveWriter, content_start_pos : u64, @@ -28,8 +61,13 @@ impl WaveChunkWriter where W: Write + Seek { Ok( WaveChunkWriter { inner , content_start_pos, length } ) } - fn end(self) -> WaveWriter { - self.inner + fn end(mut self) -> Result, Error> { + if self.length % 2 == 1 { + self.inner.inner.seek(SeekFrom::End(0))?; + self.inner.inner.write(&[0u8])?; + self.inner.increment_form_length(1)?; + } + Ok( self.inner ) } fn increment_chunk_length(&mut self, amount: u64) -> Result<(), std::io::Error> { @@ -98,16 +136,9 @@ impl WaveWriter where W: Write + Seek { let mut chunk = retval.begin_chunk(FMT__SIG)?; chunk.write_wave_fmt(&format)?; - let retval = chunk.end(); + let retval = chunk.end()?; - if format.common_format() != CommonFormat::IntegerPCM { - let mut chunk = retval.begin_chunk(FACT_SIG)?; - chunk.write_u32::(0)?; - let retval = chunk.end(); - Ok( retval ) - } else { - Ok( retval ) - } + Ok( retval ) } /// Create a new chunk writer, which takes posession of the `WaveWriter`. @@ -119,12 +150,29 @@ impl WaveWriter where W: Write + Seek { WaveChunkWriter::begin(self, ident) } + pub fn audio_frame_writer(mut self) -> Result, Error> { + // append elm1 chunk + + let framing = 0x4000; + + let lip = self.inner.seek(SeekFrom::End(0))?; + let to_add = framing - (lip % framing) - 16; + let mut chunk = self.begin_chunk(ELM1_SIG)?; + let buf = vec![0u8; to_add as usize]; + chunk.write(&buf)?; + let closed = chunk.end()?; + + let inner = closed.begin_chunk(DATA_SIG)?; + Ok( AudioFrameWriter { inner } ) + } + fn increment_form_length(&mut self, amount: u64) -> Result<(), std::io::Error> { self.form_length = self.form_length + amount; self.inner.seek(SeekFrom::Start(4))?; self.inner.write_u32::(self.form_length as u32)?; Ok(()) } + } #[test] @@ -144,6 +192,46 @@ fn test_new() { assert_eq!(cursor.read_fourcc().unwrap(), FMT__SIG); let fmt_size = cursor.read_u32::().unwrap(); assert_eq!(form_size, fmt_size + 8 + 4); - } +#[test] +fn test_write_audio() { + use std::io::Cursor; + use super::fourcc::ReadFourCC; + use byteorder::ReadBytesExt; + + let mut cursor = Cursor::new(vec![0u8;0]); + let format = WaveFmt::new_pcm(48000, 24, 1); + let w = WaveWriter::new(&mut cursor, format).unwrap(); + + let mut frame_writer = w.audio_frame_writer().unwrap(); + + frame_writer.write_integer_frame(&[0i32]).unwrap(); + frame_writer.write_integer_frame(&[0i32]).unwrap(); + frame_writer.write_integer_frame(&[0i32]).unwrap(); + + frame_writer.end().unwrap(); + + cursor.seek(SeekFrom::Start(0)).unwrap(); + + cursor.seek(SeekFrom::Start(0)).unwrap(); + assert_eq!(cursor.read_fourcc().unwrap(), RIFF_SIG); + let _ = cursor.read_u32::().unwrap(); + assert_eq!(cursor.read_fourcc().unwrap(), WAVE_SIG); + assert_eq!(cursor.read_fourcc().unwrap(), FMT__SIG); + let seek = cursor.read_u32::().unwrap(); + cursor.seek(SeekFrom::Current(seek as i64)).unwrap(); + + assert_eq!(cursor.read_fourcc().unwrap(), ELM1_SIG); + let seek = cursor.read_u32::().unwrap(); + cursor.seek(SeekFrom::Current(seek as i64)).unwrap(); + + assert_eq!(cursor.read_fourcc().unwrap(), DATA_SIG); + let data_size = cursor.read_u32::().unwrap(); + assert_eq!(data_size, 9); + + let tell = cursor.seek(SeekFrom::Current(0)).unwrap(); + assert!(tell % 0x4000 == 0); + + +} \ No newline at end of file