Introduce generic read_frames and write_frames functions

This commit is contained in:
Ian Hobson
2023-05-12 16:52:06 +02:00
parent 7290d5ec81
commit 3400778991
10 changed files with 269 additions and 156 deletions

9
Cargo.lock generated
View File

@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@@ -32,6 +34,7 @@ version = "1.1.0"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"clap", "clap",
"dasp_sample",
"encoding", "encoding",
"serde_json", "serde_json",
"uuid", "uuid",
@@ -58,6 +61,12 @@ dependencies = [
"vec_map", "vec_map",
] ]
[[package]]
name = "dasp_sample"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
[[package]] [[package]]
name = "encoding" name = "encoding"
version = "0.2.33" version = "0.2.33"

View File

@@ -15,6 +15,7 @@ keywords = ["audio", "broadcast", "multimedia","smpte"]
[dependencies] [dependencies]
byteorder = "1.3.4" byteorder = "1.3.4"
dasp_sample = "0.11.0"
encoding = "0.2.33" encoding = "0.2.33"
uuid = "0.8.1" uuid = "0.8.1"
clap = "2.33.3" clap = "2.33.3"

View File

@@ -208,7 +208,7 @@ fn create_blits_file(file_name: &str, sample_rate: u32, bits_per_sample: u16) ->
let mut fw = file.audio_frame_writer()?; let mut fw = file.audio_frame_writer()?;
for frame in frames { for frame in frames {
let buf = vec![frame.0, frame.1, frame.2, frame.3, frame.4, frame.5]; let buf = vec![frame.0, frame.1, frame.2, frame.3, frame.4, frame.5];
fw.write_integer_frames(&buf)?; fw.write_frames(&buf)?;
} }
fw.end()?; fw.end()?;

View File

@@ -4,11 +4,14 @@
//! This program demonstrates splitting a multichannel file into separate monophonic files for each //! This program demonstrates splitting a multichannel file into separate monophonic files for each
//! individual channel. //! individual channel.
use std::io; use std::io::{Read, Seek};
use std::path::Path; use std::path::Path;
extern crate bwavfile; extern crate bwavfile;
use bwavfile::{ChannelDescriptor, ChannelMask, Error, WaveFmt, WaveReader, WaveWriter}; use bwavfile::{
ChannelDescriptor, ChannelMask, CommonFormat, Error, Sample, WaveFmt, WaveReader, WaveWriter,
I24,
};
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
@@ -48,17 +51,25 @@ fn name_suffix(
} }
} }
fn process_file(infile: &str, delim: &str, numeric_channel_names: bool) -> Result<(), Error> { fn deinterleave_file<S, R>(
let mut input_file = WaveReader::open(infile)?; mut input_file: WaveReader<R>,
input_format: WaveFmt,
settings: Settings,
) -> Result<(), Error>
where
S: Sample,
R: Read + Seek,
{
let frames_per_read = 4096;
let channel_desc = input_file.channels()?; let channel_desc = input_file.channels()?;
let input_format = input_file.format()?; let channel_count = channel_desc.len();
if channel_desc.len() == 1 { if channel_desc.len() == 1 {
println!("Input file in monoaural, exiting."); println!("Input file in monoaural, exiting.");
return Ok(()); return Ok(());
} }
let infile_path = Path::new(infile); let infile_path = Path::new(&settings.input_path);
let basename = infile_path let basename = infile_path
.file_stem() .file_stem()
.expect("Unable to extract file basename") .expect("Unable to extract file basename")
@@ -68,41 +79,91 @@ fn process_file(infile: &str, delim: &str, numeric_channel_names: bool) -> Resul
.parent() .parent()
.expect("Unable to derive parent directory"); .expect("Unable to derive parent directory");
let ouptut_format = let output_block_alignment = input_format.bits_per_sample / 8;
WaveFmt::new_pcm_mono(input_format.sample_rate, input_format.bits_per_sample); let output_format = WaveFmt {
let mut input_wave_reader = input_file.audio_frame_reader()?; channel_count: 1,
let mut output_wave_writers = channel_desc block_alignment: output_block_alignment,
bytes_per_second: output_block_alignment as u32 * input_format.sample_rate,
..input_format
};
let mut reader = input_file.audio_frame_reader()?;
let mut writers = channel_desc
.iter() .iter()
.enumerate() .enumerate()
.map(|(n, channel)| { .map(|(n, channel)| {
let suffix = name_suffix(numeric_channel_names, delim, n + 1, channel); let suffix = name_suffix(
settings.use_numeric_names,
&settings.delimiter,
n + 1,
channel,
);
let outfile_name = output_dir let outfile_name = output_dir
.join(format!("{}{}.wav", basename, suffix)) .join(format!("{}{}.wav", basename, suffix))
.into_os_string() .into_os_string()
.into_string() .into_string()
.unwrap(); .unwrap();
WaveWriter::create(&outfile_name, ouptut_format) println!("Will create file {}", outfile_name);
WaveWriter::create(&outfile_name, output_format)
.expect("Failed to create new file") .expect("Failed to create new file")
.audio_frame_writer() .audio_frame_writer()
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let mut buffer = input_format.create_frame_buffer(1); let mut input_buffer = vec![S::EQUILIBRIUM; frames_per_read * channel_count];
while input_wave_reader.read_integer_frame(&mut buffer)? > 0 { let mut output_buffer = vec![S::EQUILIBRIUM; frames_per_read];
for (n, writer) in output_wave_writers.iter_mut().enumerate() {
writer.write_integer_frames(&buffer[n..=n])?; loop {
let frames_read = reader.read_frames(&mut input_buffer)? as usize;
if frames_read == 0 {
break;
}
output_buffer.resize(frames_read, S::EQUILIBRIUM);
for (n, writer) in writers.iter_mut().enumerate() {
for (output, input) in output_buffer
.iter_mut()
.zip(input_buffer.iter().skip(n).step_by(channel_count))
{
*output = *input;
}
writer.write_frames(&output_buffer)?;
} }
} }
for writer in output_wave_writers.drain(..) { for writer in writers.drain(..) {
writer.end()?; writer.end()?;
} }
Ok(()) Ok(())
} }
fn main() -> io::Result<()> { fn process_file<R>(mut input: WaveReader<R>, settings: Settings) -> Result<(), Error>
where
R: Read + Seek,
{
let format = input.format()?;
use CommonFormat::*;
match (format.common_format(), format.bits_per_sample) {
(IntegerPCM, 8) => deinterleave_file::<u8, R>(input, format, settings),
(IntegerPCM, 16) => deinterleave_file::<i16, R>(input, format, settings),
(IntegerPCM, 24) => deinterleave_file::<I24, R>(input, format, settings),
(IntegerPCM, 32) => deinterleave_file::<i32, R>(input, format, settings),
(IeeeFloatPCM, 32) => deinterleave_file::<f32, R>(input, format, settings),
other => panic!("Unsupported format: {:?}", other),
}
}
struct Settings {
input_path: String,
delimiter: String,
use_numeric_names: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let matches = App::new("wave-deinter") let matches = App::new("wave-deinter")
.version(crate_version!()) .version(crate_version!())
.author(crate_authors!()) .author(crate_authors!())
@@ -129,13 +190,12 @@ fn main() -> io::Result<()> {
) )
.get_matches(); .get_matches();
let delimiter = matches.value_of("channel_delimiter").unwrap(); let settings = Settings {
let use_numeric_names = matches.is_present("numeric_names"); input_path: matches.value_of("INPUT").unwrap().into(),
let infile = matches.value_of("INPUT").unwrap(); delimiter: matches.value_of("channel_delimiter").unwrap().into(),
use_numeric_names: matches.is_present("numeric_names"),
};
match process_file(infile, delimiter, use_numeric_names) { process_file(WaveReader::open(&settings.input_path)?, settings)?;
Err(Error::IOError(io)) => Err(io), Ok(())
Err(e) => panic!("Error: {:?}", e),
Ok(()) => Ok(()),
}
} }

View File

@@ -1,9 +1,11 @@
use super::common_format::{CommonFormat, UUID_BFORMAT_PCM, UUID_PCM}; use crate::common_format::{CommonFormat, UUID_BFORMAT_PCM, UUID_PCM};
use crate::Sample;
use std::io::Cursor; use std::io::Cursor;
use uuid::Uuid; use uuid::Uuid;
use byteorder::LittleEndian; use byteorder::LittleEndian;
use byteorder::{ReadBytesExt, WriteBytesExt}; use byteorder::ReadBytesExt;
// Need more test cases for ADMAudioID // Need more test cases for ADMAudioID
#[allow(dead_code)] #[allow(dead_code)]
@@ -309,8 +311,8 @@ impl WaveFmt {
/// ///
/// This is a conveneince method that creates a `Vec<i32>` with /// This is a conveneince method that creates a `Vec<i32>` with
/// as many elements as there are channels in the underlying stream. /// as many elements as there are channels in the underlying stream.
pub fn create_frame_buffer(&self, length: usize) -> Vec<i32> { pub fn create_frame_buffer<S: Sample>(&self, length: usize) -> Vec<S> {
vec![0i32; self.channel_count as usize * length] vec![S::EQUILIBRIUM; self.channel_count as usize * length]
} }
/// Create a raw byte buffer to hold `length` blocks from a reader or /// Create a raw byte buffer to hold `length` blocks from a reader or
@@ -319,27 +321,6 @@ impl WaveFmt {
vec![0u8; self.block_alignment as usize * length] vec![0u8; self.block_alignment as usize * length]
} }
/// Write frames into a byte vector
pub fn pack_frames(&self, from_frames: &[i32], into_bytes: &mut [u8]) {
let mut write_cursor = Cursor::new(into_bytes);
assert!(
from_frames.len() % self.channel_count as usize == 0,
"frames buffer does not contain a number of samples % channel_count == 0"
);
for frame in from_frames {
match (self.valid_bits_per_sample(), self.bits_per_sample) {
(0..=8,8) => write_cursor.write_u8((frame + 0x80) as u8 ).unwrap(), // EBU 3285 §A2.2
(9..=16,16) => write_cursor.write_i16::<LittleEndian>(*frame as i16).unwrap(),
(10..=24,24) => write_cursor.write_i24::<LittleEndian>(*frame).unwrap(),
(25..=32,32) => write_cursor.write_i32::<LittleEndian>(*frame).unwrap(),
(b,_)=> panic!("Unrecognized integer format, bits per sample {}, channels {}, block_alignment {}",
b, self.channel_count, self.block_alignment)
}
}
}
/// Read bytes into frames /// Read bytes into frames
pub fn unpack_frames(&self, from_bytes: &[u8], into_frames: &mut [i32]) { pub fn unpack_frames(&self, from_bytes: &[u8], into_frames: &mut [i32]) {
let mut rdr = Cursor::new(from_bytes); let mut rdr = Cursor::new(from_bytes);

View File

@@ -52,6 +52,8 @@ mod chunks;
mod cue; mod cue;
mod fmt; mod fmt;
mod sample;
mod wavereader; mod wavereader;
mod wavewriter; mod wavewriter;
@@ -60,5 +62,6 @@ pub use common_format::CommonFormat;
pub use cue::Cue; pub use cue::Cue;
pub use errors::Error; pub use errors::Error;
pub use fmt::{ADMAudioID, ChannelDescriptor, ChannelMask, WaveFmt, WaveFmtExtended}; pub use fmt::{ADMAudioID, ChannelDescriptor, ChannelMask, WaveFmt, WaveFmtExtended};
pub use sample::{Sample, I24};
pub use wavereader::{AudioFrameReader, WaveReader}; pub use wavereader::{AudioFrameReader, WaveReader};
pub use wavewriter::{AudioFrameWriter, WaveWriter}; pub use wavewriter::{AudioFrameWriter, WaveWriter};

14
src/sample.rs Normal file
View File

@@ -0,0 +1,14 @@
pub use dasp_sample::I24;
use dasp_sample::Duplex;
pub trait Sample:
dasp_sample::Sample + Duplex<u8> + Duplex<i16> + Duplex<I24> + Duplex<i32> + Duplex<f32>
{
}
impl Sample for u8 {}
impl Sample for i16 {}
impl Sample for I24 {}
impl Sample for i32 {}
impl Sample for f32 {}

View File

@@ -18,11 +18,13 @@ use super::fourcc::{
IXML_SIG, JUNK_SIG, LIST_SIG, IXML_SIG, JUNK_SIG, LIST_SIG,
}; };
use super::parser::Parser; use super::parser::Parser;
use super::CommonFormat; use super::{CommonFormat, Sample, I24};
use byteorder::LittleEndian; use byteorder::LittleEndian;
use byteorder::ReadBytesExt; use byteorder::ReadBytesExt;
use dasp_sample::Sample as _; // Expose to_sample()
/// Read audio frames /// Read audio frames
/// ///
/// The inner reader is interpreted as a raw audio data /// The inner reader is interpreted as a raw audio data
@@ -88,78 +90,79 @@ impl<R: Read + Seek> AudioFrameReader<R> {
Ok((seek_result - self.start) / self.format.block_alignment as u64) Ok((seek_result - self.start) / self.format.block_alignment as u64)
} }
/// Read a frame /// Reads frames from the file into the provided buffer
/// ///
/// A single frame is read from the audio stream and the read location /// The function will attempt to fill the buffer, but will stop without error when the end of
/// is advanced one frame. /// the file is reached.
/// ///
/// Regardless of the number of bits in the audio sample, this method /// The reader will convert from the file's sample type into the buffer's sample type.
/// always writes `i32` samples back to the buffer. These samples are /// Note that no dithering will be applied during sample type conversion,
/// written back "right-aligned" so samples that are shorter than i32 /// if dithering is required then it will need to be applied manually.
/// will leave the MSB bits empty.
/// ///
/// For example: A full-code sample in 16 bit (0xFFFF) will be written /// The return value is the number of frames read into the buffer.
/// back to the buffer as 0x0000FFFF. pub fn read_frames<S>(&mut self, buffer: &mut [S]) -> Result<u64, Error>
/// where
/// S: Sample,
/// ### Panics {
/// use CommonFormat::*;
/// The `buffer` must have a number of elements equal to the number of
/// channels and this method will panic if this is not the case. let channel_count = self.format.channel_count as usize;
pub fn read_integer_frame(&mut self, buffer: &mut [i32]) -> Result<u64, Error> { let common_format = self.format.common_format();
let bits_per_sample = self.format.bits_per_sample;
assert!( assert!(
buffer.len() as u16 == self.format.channel_count, buffer.len() % channel_count == 0,
"read_integer_frame was called with a mis-sized buffer, expected {}, was {}", "read_frames was called with a mis-sized buffer, expected a multiple of {}, was {}",
self.format.channel_count, channel_count,
buffer.len() buffer.len()
); );
let framed_bits_per_sample = self.format.block_alignment * 8 / self.format.channel_count; let position = self.inner.stream_position()? - self.start;
let frames_requested = (buffer.len() / channel_count) as u64;
let bytes_per_frame = self.format.block_alignment as u64;
let frames_remaining = (self.length - position) / bytes_per_frame;
let frames_to_read = frames_requested.min(frames_remaining);
let samples_to_read = frames_to_read as usize * channel_count;
let tell = self.inner.stream_position()?; match (common_format, bits_per_sample) {
(IntegerPCM, 8) => read_into_buffer(samples_to_read, buffer, || {
Ok(self.inner.read_u8()?.to_sample())
}),
(IntegerPCM, 16) => read_into_buffer(samples_to_read, buffer, || {
Ok(self.inner.read_i16::<LittleEndian>()?.to_sample())
}),
(IntegerPCM, 24) => read_into_buffer(samples_to_read, buffer, || {
Ok(I24::from(self.inner.read_i24::<LittleEndian>()?).to_sample())
}),
(IntegerPCM, 32) => read_into_buffer(samples_to_read, buffer, || {
Ok(self.inner.read_i32::<LittleEndian>()?.to_sample())
}),
(IeeeFloatPCM, 32) => read_into_buffer(samples_to_read, buffer, || {
Ok(self.inner.read_f32::<LittleEndian>()?.to_sample())
}),
(_, _) => panic!(
"Unsupported format, bits per sample {}, channels {}, sample format: {:?}",
bits_per_sample, channel_count, common_format
),
}?;
if (tell - self.start) < self.length { Ok(frames_to_read)
for sample in buffer.iter_mut().take(self.format.channel_count as usize) {
*sample = match (self.format.bits_per_sample, framed_bits_per_sample) {
(0..=8,8) => self.inner.read_u8()? as i32 - 0x80_i32, // EBU 3285 §A2.2
(9..=16,16) => self.inner.read_i16::<LittleEndian>()? as i32,
(10..=24,24) => self.inner.read_i24::<LittleEndian>()?,
(25..=32,32) => self.inner.read_i32::<LittleEndian>()?,
(b,_)=> panic!("Unrecognized integer format, bits per sample {}, channels {}, block_alignment {}",
b, self.format.channel_count, self.format.block_alignment)
}
}
Ok(1)
} else {
Ok(0)
} }
} }
pub fn read_float_frame(&mut self, buffer: &mut [f32]) -> Result<u64, Error> { fn read_into_buffer<S, F>(
assert!( sample_count: usize,
buffer.len() as u16 == self.format.channel_count, buffer: &mut [S],
"read_float_frame was called with a mis-sized buffer, expected {}, was {}", mut read_fn: F,
self.format.channel_count, ) -> Result<(), Error>
buffer.len() where
); F: FnMut() -> Result<S, Error>,
{
for output in buffer.iter_mut().take(sample_count) {
*output = read_fn()?;
}
let framed_bits_per_sample = self.format.block_alignment * 8 / self.format.channel_count; Ok(())
let tell = self.inner.stream_position()?;
if (tell - self.start) < self.length {
for sample in buffer.iter_mut().take(self.format.channel_count as usize) {
*sample = match (self.format.bits_per_sample, framed_bits_per_sample) {
(25..=32,32) => self.inner.read_f32::<LittleEndian>()?,
(b,_)=> panic!("Unrecognized integer format, bits per sample {}, channels {}, block_alignment {}",
b, self.format.channel_count, self.format.block_alignment)
}
}
Ok(1)
} else {
Ok(0)
}
}
} }
/// Wave, Broadcast-WAV and RF64/BW64 parser/reader. /// Wave, Broadcast-WAV and RF64/BW64 parser/reader.
@@ -173,9 +176,9 @@ impl<R: Read + Seek> AudioFrameReader<R> {
/// assert_eq!(format.channel_count, 1); /// assert_eq!(format.channel_count, 1);
/// ///
/// let mut frame_reader = r.audio_frame_reader().unwrap(); /// let mut frame_reader = r.audio_frame_reader().unwrap();
/// let mut buffer = format.create_frame_buffer(1); /// let mut buffer = format.create_frame_buffer::<i32>(1);
/// ///
/// let read = frame_reader.read_integer_frame(&mut buffer).unwrap(); /// let read = frame_reader.read_frames(&mut buffer).unwrap();
/// ///
/// assert_eq!(buffer, [0i32]); /// assert_eq!(buffer, [0i32]);
/// assert_eq!(read, 1); /// assert_eq!(read, 1);

View File

@@ -2,12 +2,14 @@ use std::fs::File;
use std::io::{BufWriter, Cursor, Seek, SeekFrom, Write}; use std::io::{BufWriter, Cursor, Seek, SeekFrom, Write};
use std::path::Path; use std::path::Path;
use crate::CommonFormat;
use super::fmt::WaveFmt; use super::fmt::WaveFmt;
use super::fourcc::{ use super::fourcc::{
FourCC, WriteFourCC, AXML_SIG, BEXT_SIG, DATA_SIG, DS64_SIG, ELM1_SIG, FMT__SIG, IXML_SIG, FourCC, WriteFourCC, AXML_SIG, BEXT_SIG, DATA_SIG, DS64_SIG, ELM1_SIG, FMT__SIG, IXML_SIG,
JUNK_SIG, RF64_SIG, RIFF_SIG, WAVE_SIG, JUNK_SIG, RF64_SIG, RIFF_SIG, WAVE_SIG,
}; };
use super::Error; use super::{Error, Sample, I24};
//use super::common_format::CommonFormat; //use super::common_format::CommonFormat;
use super::bext::Bext; use super::bext::Bext;
use super::chunks::WriteBWaveChunks; use super::chunks::WriteBWaveChunks;
@@ -33,28 +35,67 @@ where
AudioFrameWriter { inner } AudioFrameWriter { inner }
} }
fn write_integer_frames_to_buffer(&self, from_frames: &[i32], to_buffer: &mut [u8]) {
assert!(
from_frames.len() % self.inner.inner.format.channel_count as usize == 0,
"frames buffer does not contain a number of samples % channel_count == 0"
);
self.inner.inner.format.pack_frames(from_frames, to_buffer);
}
/// Write interleaved samples in `buffer` /// Write interleaved samples in `buffer`
/// ///
/// # Panics /// # Panics
/// ///
/// This function will panic if `buffer.len()` modulo the Wave file's channel count /// This function will panic if `buffer.len()` modulo the Wave file's channel count
/// is not zero. /// is not zero.
pub fn write_integer_frames(&mut self, buffer: &[i32]) -> Result<u64, Error> { pub fn write_frames<S>(&mut self, buffer: &[S]) -> Result<u64, Error>
where
S: Sample,
{
let format = &self.inner.inner.format;
let channel_count = format.channel_count as usize;
assert!(
buffer.len() % channel_count == 0,
"frames buffer does not contain a number of samples % channel_count == 0"
);
let mut write_buffer = self let mut write_buffer = self
.inner .inner
.inner .inner
.format .format
.create_raw_buffer(buffer.len() / self.inner.inner.format.channel_count as usize); .create_raw_buffer(buffer.len() / channel_count);
self.write_integer_frames_to_buffer(buffer, &mut write_buffer); let into_bytes: &mut [u8] = &mut write_buffer;
let mut write_cursor = Cursor::new(into_bytes);
let common_format = format.common_format();
let bits_per_sample = format.bits_per_sample;
match (common_format, bits_per_sample) {
(_, 8) => {
for sample in buffer {
write_cursor.write_u8(sample.to_sample())?
}
}
(_, 16) => {
for sample in buffer {
write_cursor.write_i16::<LittleEndian>(sample.to_sample())?
}
}
(_, 24) => {
for sample in buffer {
write_cursor.write_i24::<LittleEndian>(sample.to_sample::<I24>().inner())?
}
}
(CommonFormat::IntegerPCM, 32) => {
for sample in buffer {
write_cursor.write_i32::<LittleEndian>(sample.to_sample())?
}
}
(CommonFormat::IeeeFloatPCM, 32) => {
for sample in buffer {
write_cursor.write_f32::<LittleEndian>(sample.to_sample())?
}
}
(_, _) => panic!(
"Unrecognized format, bits per sample {}, channels {}, sample format {:?}",
bits_per_sample, channel_count, common_format
),
}
self.inner.write_all(&write_buffer)?; self.inner.write_all(&write_buffer)?;
Ok(write_buffer.len() as u64 / self.inner.inner.format.channel_count as u64) Ok(write_buffer.len() as u64 / self.inner.inner.format.channel_count as u64)
@@ -194,9 +235,9 @@ where
/// ///
/// let mut frame_writer = w.audio_frame_writer().unwrap(); /// let mut frame_writer = w.audio_frame_writer().unwrap();
/// ///
/// frame_writer.write_integer_frames(&[0i32]).unwrap(); /// frame_writer.write_frames(&[0i32]).unwrap();
/// frame_writer.write_integer_frames(&[0i32]).unwrap(); /// frame_writer.write_frames(&[0i32]).unwrap();
/// frame_writer.write_integer_frames(&[0i32]).unwrap(); /// frame_writer.write_frames(&[0i32]).unwrap();
/// frame_writer.end().unwrap(); /// frame_writer.end().unwrap();
/// ``` /// ```
/// ///
@@ -432,9 +473,9 @@ fn test_write_audio() {
let mut frame_writer = w.audio_frame_writer().unwrap(); let mut frame_writer = w.audio_frame_writer().unwrap();
frame_writer.write_integer_frames(&[0i32]).unwrap(); frame_writer.write_frames(&[0i32]).unwrap();
frame_writer.write_integer_frames(&[0i32]).unwrap(); frame_writer.write_frames(&[0i32]).unwrap();
frame_writer.write_integer_frames(&[0i32]).unwrap(); frame_writer.write_frames(&[0i32]).unwrap();
frame_writer.end().unwrap(); frame_writer.end().unwrap();
@@ -500,14 +541,14 @@ fn test_write_bext() {
let mut frame_writer = w.audio_frame_writer().unwrap(); let mut frame_writer = w.audio_frame_writer().unwrap();
frame_writer.write_integer_frames(&[0i32]).unwrap(); frame_writer.write_frames(&[0i32]).unwrap();
frame_writer.write_integer_frames(&[0i32]).unwrap(); frame_writer.write_frames(&[0i32]).unwrap();
frame_writer.write_integer_frames(&[0i32]).unwrap(); frame_writer.write_frames(&[0i32]).unwrap();
frame_writer.end().unwrap(); frame_writer.end().unwrap();
} }
// NOTE! This test of RF64 writing takes several minutes to complete. // NOTE! This test of RF64 writing takes several minutes to complete in debug builds
#[test] #[test]
fn test_create_rf64() { fn test_create_rf64() {
use super::fourcc::ReadFourCC; use super::fourcc::ReadFourCC;
@@ -526,7 +567,7 @@ fn test_create_rf64() {
let mut af = w.audio_frame_writer().unwrap(); let mut af = w.audio_frame_writer().unwrap();
for _ in 0..(four_and_a_half_hours_of_frames * format.channel_count as u64 / buflen) { for _ in 0..(four_and_a_half_hours_of_frames * format.channel_count as u64 / buflen) {
af.write_integer_frames(&buf).unwrap(); af.write_frames(&buf).unwrap();
} }
af.end().unwrap(); af.end().unwrap();

View File

@@ -3,6 +3,7 @@ extern crate bwavfile;
use bwavfile::ChannelMask; use bwavfile::ChannelMask;
use bwavfile::Error; use bwavfile::Error;
use bwavfile::WaveReader; use bwavfile::WaveReader;
use bwavfile::I24;
#[test] #[test]
fn test_open() { fn test_open() {
@@ -80,16 +81,16 @@ fn test_read() {
let path = "tests/media/audacity_16bit.wav"; let path = "tests/media/audacity_16bit.wav";
let mut 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(1); let mut buffer = w.format().unwrap().create_frame_buffer::<i16>(1);
let mut reader = w.audio_frame_reader().unwrap(); let mut reader = w.audio_frame_reader().unwrap();
assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(reader.read_frames(&mut buffer).unwrap(), 1);
assert_eq!(buffer[0], -2823_i32); assert_eq!(buffer[0], -2823_i16);
assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(reader.read_frames(&mut buffer).unwrap(), 1);
assert_eq!(buffer[0], 2012_i32); assert_eq!(buffer[0], 2012_i16);
assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(reader.read_frames(&mut buffer).unwrap(), 1);
assert_eq!(buffer[0], 4524_i32); assert_eq!(buffer[0], 4524_i16);
} }
#[test] #[test]
@@ -97,21 +98,21 @@ fn test_locate_multichannel_read() {
let path = "tests/media/ff_pink.wav"; let path = "tests/media/ff_pink.wav";
let mut 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(1); let mut buffer = w.format().unwrap().create_frame_buffer::<I24>(1);
let mut reader = w.audio_frame_reader().unwrap(); let mut reader = w.audio_frame_reader().unwrap();
assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(reader.read_frames(&mut buffer).unwrap(), 1);
assert_eq!(buffer[0], 332702_i32); assert_eq!(buffer[0], I24::from(332702));
assert_eq!(buffer[1], 3258791_i32); assert_eq!(buffer[1], I24::from(3258791));
assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(reader.read_frames(&mut buffer).unwrap(), 1);
assert_eq!(buffer[0], -258742_i32); // 0x800000 = 8388608 // 8129866 - 8388608 assert_eq!(buffer[0], I24::from(-258742)); // 0x800000 = 8388608 // 8129866 - 8388608
assert_eq!(buffer[1], 0x0D7EF9_i32); assert_eq!(buffer[1], I24::from(0x0D7EF9));
assert_eq!(reader.locate(100).unwrap(), 100); assert_eq!(reader.locate(100).unwrap(), 100);
assert_eq!(reader.read_integer_frame(&mut buffer).unwrap(), 1); assert_eq!(reader.read_frames(&mut buffer).unwrap(), 1);
assert_eq!(buffer[0], 0x109422_i32); assert_eq!(buffer[0], I24::from(0x109422));
assert_eq!(buffer[1], -698901_i32); // 7689707 - 8388608 assert_eq!(buffer[1], I24::from(-698901)); // 7689707 - 8388608
} }
#[test] #[test]