Writer impl

This commit is contained in:
Jamie Hardt
2020-12-25 21:58:22 -08:00
parent e4fc4732b5
commit 73d2cf8cd9
3 changed files with 103 additions and 16 deletions

View File

@@ -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");

View File

@@ -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;

View File

@@ -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<W> where W: Write + Seek {
inner : WaveChunkWriter<W>
}
impl<W> AudioFrameWriter<W> where W: Write + Seek {
pub fn write_integer_frame(&mut self, buffer: &[i32]) -> Result<u64,Error> {
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::<LittleEndian>(buffer[n] as i16)?,
(10..=24,24) => self.inner.write_i24::<LittleEndian>(buffer[n])?,
(25..=32,32) => self.inner.write_i32::<LittleEndian>(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<WaveWriter<W>, Error> {
self.inner.end()
}
}
pub struct WaveChunkWriter<W> where W: Write + Seek {
inner : WaveWriter<W>,
content_start_pos : u64,
@@ -28,8 +61,13 @@ impl<W> WaveChunkWriter<W> where W: Write + Seek {
Ok( WaveChunkWriter { inner , content_start_pos, length } )
}
fn end(self) -> WaveWriter<W> {
self.inner
fn end(mut self) -> Result<WaveWriter<W>, 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<W> WaveWriter<W> 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::<LittleEndian>(0)?;
let retval = chunk.end();
Ok( retval )
} else {
Ok( retval )
}
}
/// Create a new chunk writer, which takes posession of the `WaveWriter`.
@@ -119,12 +150,29 @@ impl<W> WaveWriter<W> where W: Write + Seek {
WaveChunkWriter::begin(self, ident)
}
pub fn audio_frame_writer(mut self) -> Result<AudioFrameWriter<W>, 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::<LittleEndian>(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::<LittleEndian>().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::<LittleEndian>().unwrap();
assert_eq!(cursor.read_fourcc().unwrap(), WAVE_SIG);
assert_eq!(cursor.read_fourcc().unwrap(), FMT__SIG);
let seek = cursor.read_u32::<LittleEndian>().unwrap();
cursor.seek(SeekFrom::Current(seek as i64)).unwrap();
assert_eq!(cursor.read_fourcc().unwrap(), ELM1_SIG);
let seek = cursor.read_u32::<LittleEndian>().unwrap();
cursor.seek(SeekFrom::Current(seek as i64)).unwrap();
assert_eq!(cursor.read_fourcc().unwrap(), DATA_SIG);
let data_size = cursor.read_u32::<LittleEndian>().unwrap();
assert_eq!(data_size, 9);
let tell = cursor.seek(SeekFrom::Current(0)).unwrap();
assert!(tell % 0x4000 == 0);
}