use std::io::{self, Read, Seek};
use crate::bit_io::BitReader;
use crate::frame::subframe::{self};
use crate::frame::{self, Frame};
use crate::metadata::{self, Application, Cuesheet, Picture, SeekTable, Streaminfo, VorbisComment};
#[derive(Debug, thiserror::Error)]
pub enum DecodeError {
#[error("parse: {0}")]
Parse(#[from] metadata::Error),
#[error("frame: {0}")]
Frame(#[from] frame::Error),
#[error("IO: {0}")]
Io(#[from] io::Error),
#[error(
"channel count mismatch: frame declares {frame} channels, but STREAMINFO declares {streaminfo}"
)]
ChannelCountMismatch {
frame: usize,
streaminfo: usize,
},
#[error("There were multiple STREAMINFO blocks")]
MultipleStreaminfo,
#[error("There were multiple seektables")]
MultipleSeektable,
#[error("There were multiple Vorbis comment blocks")]
MultipleVorbisComment,
}
pub struct Flac<R: Read + Seek> {
pub streaminfo: Streaminfo,
pub applications: Vec<Application>,
pub comment: Option<VorbisComment>,
pub cuesheets: Vec<Cuesheet>,
pub pictures: Vec<Picture>,
pub seektable: Option<SeekTable>,
reader: BitReader<R>,
}
impl<R: Read + Seek> Flac<R> {
pub fn new(inner: R) -> Result<Self, DecodeError> {
let mut reader = BitReader::new(inner);
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
if magic != crate::MAGIC {
return Err(io::Error::new(io::ErrorKind::InvalidData, "not a FLAC file").into());
}
let mut streaminfo = None;
let mut applications = Vec::new();
let mut comment = None;
let mut cuesheets = Vec::new();
let mut pictures = Vec::new();
let mut seektable = None;
for block in metadata::BlockIter::new(&mut reader) {
let block = block?;
match block.data {
metadata::BlockData::Streaminfo(d) => streaminfo = Some(d),
metadata::BlockData::Application(d) => applications.push(d),
metadata::BlockData::VorbisComment(d) => comment
.replace(d)
.is_none_or_err(DecodeError::MultipleVorbisComment)?,
metadata::BlockData::Cuesheet(d) => cuesheets.push(d),
metadata::BlockData::Picture(d) => pictures.push(d),
metadata::BlockData::SeekTable(d) => seektable
.replace(d)
.is_none_or_err(DecodeError::MultipleSeektable)?,
metadata::BlockData::Padding => {}
}
}
let streaminfo = streaminfo.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "missing STREAMINFO block")
})?;
Ok(Self {
streaminfo,
applications,
comment,
cuesheets,
pictures,
seektable,
reader,
})
}
pub fn inner(self) -> BitReader<R> {
self.reader
}
pub fn frames(self) -> FrameIter<R> {
FrameIter {
total_channels: self.streaminfo.num_channels(),
inner: self,
blocks: Vec::new(),
}
}
pub fn interleaved_samples(self) -> Result<Vec<i32>, DecodeError> {
let mut samples = Vec::new();
for frame in self.frames() {
let frame = frame?;
samples.extend(frame.samples);
}
Ok(samples)
}
}
#[derive(Debug, Clone)]
pub struct DecodedFrame {
pub header: frame::Header,
pub samples: Vec<i32>,
pub block_size: usize,
}
pub struct FrameIter<R: Read + Seek> {
inner: Flac<R>,
total_channels: usize,
blocks: Vec<subframe::Block>,
}
impl<R: Read + Seek> Iterator for FrameIter<R> {
type Item = Result<DecodedFrame, DecodeError>;
fn next(&mut self) -> Option<Self::Item> {
let (header, _footer) = match Frame::read_streaming(
&mut self.inner.reader,
&self.inner.streaminfo,
|_, block| {
let mut block = block?;
block.scale(self.inner.streaminfo.bits_per_sample());
self.blocks.push(block);
Ok(())
},
) {
Ok(x) => x,
Err(frame::Error::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => return None,
Err(e) => return Some(Err(e.into())),
};
if header.channels.count() != self.total_channels {
return Some(Err(DecodeError::ChannelCountMismatch {
frame: header.channels.count(),
streaminfo: self.total_channels,
}));
}
if let [ch0, ch1] = self.blocks.as_mut_slice() {
subframe::Block::decorrelate(ch0, ch1, header.channels);
}
let block_size = header.block_size.samples();
let mut samples = Vec::with_capacity(block_size * self.total_channels);
for sample_idx in 0..block_size {
for channel in &self.blocks {
samples.push(channel[sample_idx]);
}
}
self.blocks.clear();
Some(Ok(DecodedFrame {
header,
samples,
block_size,
}))
}
}
trait OptionToResult {
fn is_none_or_err<E>(&self, err: E) -> Result<(), E>;
}
impl<T> OptionToResult for Option<T> {
#[inline]
fn is_none_or_err<E>(&self, err: E) -> Result<(), E> {
if self.is_none() { Ok(()) } else { Err(err) }
}
}