mirror of
https://github.com/iluvcapra/bwavfile.git
synced 2026-05-17 04:33:26 +00:00
Merge branch 'master' of https://github.com/iluvcapra/bwavfile
This commit is contained in:
@@ -4,7 +4,7 @@ use std::path::Path;
|
||||
|
||||
use std::io::Cursor;
|
||||
use std::io::SeekFrom;
|
||||
use std::io::SeekFrom::{Current, Start};
|
||||
use std::io::SeekFrom::Start;
|
||||
use std::io::{BufReader, Read, Seek};
|
||||
|
||||
use super::bext::Bext;
|
||||
@@ -18,11 +18,13 @@ use super::fourcc::{
|
||||
IXML_SIG, JUNK_SIG, LIST_SIG,
|
||||
};
|
||||
use super::parser::Parser;
|
||||
use super::CommonFormat;
|
||||
use super::{CommonFormat, Sample, I24};
|
||||
|
||||
use byteorder::LittleEndian;
|
||||
use byteorder::ReadBytesExt;
|
||||
|
||||
use dasp_sample::Sample as _; // Expose to_sample()
|
||||
|
||||
/// Read audio frames
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// is advanced one frame.
|
||||
/// The function will attempt to fill the buffer, but will stop without error when the end of
|
||||
/// the file is reached.
|
||||
///
|
||||
/// Regardless of the number of bits in the audio sample, this method
|
||||
/// always writes `i32` samples back to the buffer. These samples are
|
||||
/// written back "right-aligned" so samples that are shorter than i32
|
||||
/// will leave the MSB bits empty.
|
||||
/// The reader will convert from the file's sample type into the buffer's sample type.
|
||||
/// Note that no dithering will be applied during sample type conversion,
|
||||
/// if dithering is required then it will need to be applied manually.
|
||||
///
|
||||
/// For example: A full-code sample in 16 bit (0xFFFF) will be written
|
||||
/// back to the buffer as 0x0000FFFF.
|
||||
///
|
||||
///
|
||||
/// ### Panics
|
||||
///
|
||||
/// 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.
|
||||
pub fn read_integer_frame(&mut self, buffer: &mut [i32]) -> Result<u64, Error> {
|
||||
assert!(
|
||||
buffer.len() as u16 == self.format.channel_count,
|
||||
"read_integer_frame was called with a mis-sized buffer, expected {}, was {}",
|
||||
self.format.channel_count,
|
||||
buffer.len()
|
||||
);
|
||||
/// The return value is the number of frames read into the buffer.
|
||||
pub fn read_frames<S>(&mut self, buffer: &mut [S]) -> Result<u64, Error>
|
||||
where
|
||||
S: Sample,
|
||||
{
|
||||
use CommonFormat::*;
|
||||
|
||||
let framed_bits_per_sample = self.format.block_alignment * 8 / self.format.channel_count;
|
||||
let channel_count = self.format.channel_count as usize;
|
||||
let common_format = self.format.common_format();
|
||||
let bits_per_sample = self.format.bits_per_sample;
|
||||
|
||||
let tell = self.inner.seek(Current(0))?;
|
||||
|
||||
if (tell - self.start) < self.length {
|
||||
for n in 0..(self.format.channel_count as usize) {
|
||||
buffer[n] = 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)
|
||||
if buffer.len() % channel_count != 0 {
|
||||
return Err(Error::InvalidBufferSize {
|
||||
buffer_size: buffer.len(),
|
||||
channel_count: 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;
|
||||
|
||||
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
|
||||
),
|
||||
}?;
|
||||
|
||||
Ok(frames_to_read)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_into_buffer<S, F>(
|
||||
sample_count: usize,
|
||||
buffer: &mut [S],
|
||||
mut read_fn: F,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
F: FnMut() -> Result<S, Error>,
|
||||
{
|
||||
for output in buffer.iter_mut().take(sample_count) {
|
||||
*output = read_fn()?;
|
||||
}
|
||||
|
||||
pub fn read_float_frame(&mut self, buffer: &mut [f32]) -> Result<u64, Error> {
|
||||
assert!(
|
||||
buffer.len() as u16 == self.format.channel_count,
|
||||
"read_float_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;
|
||||
|
||||
let tell = self.inner.seek(Current(0))?;
|
||||
|
||||
if (tell - self.start) < self.length {
|
||||
for n in 0..(self.format.channel_count as usize) {
|
||||
buffer[n] = 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)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wave, Broadcast-WAV and RF64/BW64 parser/reader.
|
||||
@@ -173,9 +176,9 @@ impl<R: Read + Seek> AudioFrameReader<R> {
|
||||
/// assert_eq!(format.channel_count, 1);
|
||||
///
|
||||
/// 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!(read, 1);
|
||||
@@ -216,7 +219,7 @@ impl WaveReader<BufReader<File>> {
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, ParserError> {
|
||||
let f = File::open(path)?;
|
||||
let inner = BufReader::new(f);
|
||||
Ok(Self::new(inner)?)
|
||||
Self::new(inner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,10 +227,9 @@ impl WaveReader<File> {
|
||||
/// Open a file for reading with unbuffered IO.
|
||||
///
|
||||
/// A convenience that opens `path` and calls `Self::new()`
|
||||
|
||||
pub fn open_unbuffered<P: AsRef<Path>>(path: P) -> Result<Self, ParserError> {
|
||||
let inner = File::open(path)?;
|
||||
return Ok(Self::new(inner)?);
|
||||
Self::new(inner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +272,7 @@ impl<R: Read + Seek> WaveReader<R> {
|
||||
|
||||
/// Unwrap the inner reader.
|
||||
pub fn into_inner(self) -> R {
|
||||
return self.inner;
|
||||
self.inner
|
||||
}
|
||||
|
||||
///
|
||||
@@ -279,12 +281,12 @@ impl<R: Read + Seek> WaveReader<R> {
|
||||
pub fn audio_frame_reader(mut self) -> Result<AudioFrameReader<R>, ParserError> {
|
||||
let format = self.format()?;
|
||||
let audio_chunk_reader = self.get_chunk_extent_at_index(DATA_SIG, 0)?;
|
||||
Ok(AudioFrameReader::new(
|
||||
AudioFrameReader::new(
|
||||
self.inner,
|
||||
format,
|
||||
audio_chunk_reader.0,
|
||||
audio_chunk_reader.1,
|
||||
)?)
|
||||
)
|
||||
}
|
||||
|
||||
/// The count of audio frames in the file.
|
||||
@@ -580,18 +582,16 @@ impl<R: Read + Seek> WaveReader<R> {
|
||||
&mut self,
|
||||
ident: FourCC,
|
||||
at: u32,
|
||||
mut buffer: &mut Vec<u8>,
|
||||
buffer: &mut Vec<u8>,
|
||||
) -> Result<usize, ParserError> {
|
||||
match self.get_chunk_extent_at_index(ident, at) {
|
||||
Ok((start, length)) => {
|
||||
buffer.resize(length as usize, 0x0);
|
||||
self.inner.seek(SeekFrom::Start(start))?;
|
||||
self.inner
|
||||
.read(&mut buffer)
|
||||
.map_err(|e| ParserError::IOError(e))
|
||||
self.inner.read(buffer).map_err(ParserError::IOError)
|
||||
}
|
||||
Err(ParserError::ChunkMissing { signature: _ }) => Ok(0),
|
||||
Err(any) => Err(any.into()),
|
||||
Err(any) => Err(any),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,7 +608,7 @@ impl<R: Read + Seek> WaveReader<R> {
|
||||
/// Index of first LIST for with the given FORM fourcc
|
||||
fn get_list_form(&mut self, fourcc: FourCC) -> Result<Option<u32>, ParserError> {
|
||||
for (n, (start, _)) in self.get_chunks_extents(LIST_SIG)?.iter().enumerate() {
|
||||
self.inner.seek(SeekFrom::Start(*start as u64))?;
|
||||
self.inner.seek(SeekFrom::Start(*start))?;
|
||||
let this_fourcc = self.inner.read_fourcc()?;
|
||||
if this_fourcc == fourcc {
|
||||
return Ok(Some(n as u32));
|
||||
@@ -623,7 +623,7 @@ impl<R: Read + Seek> WaveReader<R> {
|
||||
fourcc: FourCC,
|
||||
index: u32,
|
||||
) -> Result<(u64, u64), ParserError> {
|
||||
if let Some((start, length)) = self.get_chunks_extents(fourcc)?.iter().nth(index as usize) {
|
||||
if let Some((start, length)) = self.get_chunks_extents(fourcc)?.get(index as usize) {
|
||||
Ok((*start, *length))
|
||||
} else {
|
||||
Err(ParserError::ChunkMissing { signature: fourcc })
|
||||
|
||||
Reference in New Issue
Block a user