#![warn(missing_docs)]
#![forbid(unsafe_code)]
mod audio;
pub mod byteorder;
mod crc;
pub mod decode;
pub mod encode;
pub mod metadata;
pub mod stream;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Io(std::io::Error),
Utf8(Box<std::string::FromUtf8Error>),
MissingFlacTag,
MissingStreaminfo,
MultipleStreaminfo,
MultipleSeekTable,
MultipleVorbisComment,
InvalidSeekTableSize,
InvalidSeekTablePoint,
Cuesheet(metadata::CuesheetError),
InvalidPictureType,
MultiplePngIcon,
MultipleGeneralIcon,
ReservedMetadataBlock,
InvalidMetadataBlock,
InvalidMetadataBlockSize,
InsufficientApplicationBlock,
ExcessiveVorbisEntries,
ExcessiveStringLength,
ExcessivePictureSize,
ShortBlock,
ExcessiveBlockSize,
InvalidSyncCode,
InvalidBlockSize,
BlockSizeMismatch,
InvalidSampleRate,
NonSubsetSampleRate,
NonSubsetBitsPerSample,
SampleRateMismatch,
ExcessiveChannels,
InvalidChannels,
ChannelsMismatch,
InvalidBitsPerSample,
ExcessiveBps,
BitsPerSampleMismatch,
InvalidFrameNumber,
InvalidSeek,
ExcessiveFrameNumber,
Crc8Mismatch,
Crc16Mismatch,
InvalidSubframeHeader,
InvalidSubframeHeaderType,
ExcessiveWastedBits,
MissingResiduals,
InvalidCodingMethod,
InvalidPartitionOrder,
InvalidFixedOrder,
InvalidLpcOrder,
InvalidQlpPrecision,
NegativeLpcShift,
NoBestLpcOrder,
InsufficientLpcSamples,
ZeroLpCoefficients,
LpNegativeShiftError,
AccumulatorOverflow,
TooManySamples,
ExcessiveTotalSamples,
NoSamples,
SampleCountMismatch,
ResidualOverflow,
SamplesNotDivisibleByChannels,
InvalidTotalBytes,
InvalidTotalSamples,
ChannelCountMismatch,
ChannelLengthMismatch,
}
impl From<std::io::Error> for Error {
#[inline]
fn from(error: std::io::Error) -> Self {
Self::Io(error)
}
}
impl From<std::string::FromUtf8Error> for Error {
#[inline]
fn from(error: std::string::FromUtf8Error) -> Self {
Self::Utf8(Box::new(error))
}
}
impl From<metadata::CuesheetError> for Error {
fn from(error: metadata::CuesheetError) -> Self {
Self::Cuesheet(error)
}
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
Self::Utf8(e) => e.fmt(f),
Self::Cuesheet(e) => e.fmt(f),
Self::MissingFlacTag => "missing FLAC tag".fmt(f),
Self::MissingStreaminfo => "STREAMINFO block not first in file".fmt(f),
Self::MultipleStreaminfo => "multiple STREAMINFO blocks found in file".fmt(f),
Self::MultipleSeekTable => "multiple SEEKTABLE blocks found in file".fmt(f),
Self::MultipleVorbisComment => "multiple VORBIS_COMMENT blocks found in file".fmt(f),
Self::InvalidSeekTableSize => "invalid SEEKTABLE block size".fmt(f),
Self::InvalidSeekTablePoint => "invalid SEEKTABLE point".fmt(f),
Self::InvalidPictureType => "reserved PICTURE type".fmt(f),
Self::MultiplePngIcon => "multiple PNG icons in PICTURE blocks".fmt(f),
Self::MultipleGeneralIcon => "multiple general file icons in PICTURE blocks".fmt(f),
Self::ReservedMetadataBlock => "reserved metadata block".fmt(f),
Self::InvalidMetadataBlock => "invalid metadata block".fmt(f),
Self::InvalidMetadataBlockSize => "invalid metadata block size".fmt(f),
Self::InsufficientApplicationBlock => "APPLICATION block too small for data".fmt(f),
Self::ExcessiveVorbisEntries => "excessive number of VORBIS_COMMENT entries".fmt(f),
Self::ExcessiveStringLength => "excessive string length".fmt(f),
Self::ExcessivePictureSize => "excessive PICTURE data size".fmt(f),
Self::ExcessiveBlockSize => "excessive metadata block size".fmt(f),
Self::InvalidSyncCode => "invalid frame sync code".fmt(f),
Self::InvalidBlockSize => "invalid frame block size".fmt(f),
Self::ShortBlock => "block size <= 14 must be last in stream".fmt(f),
Self::BlockSizeMismatch => {
"block size in frame larger than maximum block size in STREAMINFO".fmt(f)
}
Self::InvalidSampleRate => "invalid frame sample rate".fmt(f),
Self::NonSubsetSampleRate => "sample rate undefined for subset stream".fmt(f),
Self::NonSubsetBitsPerSample => "bits-per-sample undefined for subset stream".fmt(f),
Self::SampleRateMismatch => {
"sample rate in frame differs from sample rate in STREAMINFO".fmt(f)
}
Self::ExcessiveChannels => "excessive channel count".fmt(f),
Self::InvalidChannels => "invalid frame channel assignment".fmt(f),
Self::ChannelsMismatch => {
"channel count in frame differs from channel count in STREAMINFO".fmt(f)
}
Self::InvalidBitsPerSample => "invalid frame bits-per-sample".fmt(f),
Self::ExcessiveBps => "bits-per-sample higher than 32".fmt(f),
Self::BitsPerSampleMismatch => {
"bits-per-sample in frame differs from bits-per-sample in STREAMINFO".fmt(f)
}
Self::InvalidFrameNumber => "invalid frame number".fmt(f),
Self::InvalidSeek => "seeking beyond end of stream".fmt(f),
Self::ExcessiveFrameNumber => "excessive frame number".fmt(f),
Self::Crc8Mismatch => "CRC-8 mismatch in frame header".fmt(f),
Self::Crc16Mismatch => "CRC-16 mismatch in frame footer".fmt(f),
Self::InvalidSubframeHeader => "invalid subframe header".fmt(f),
Self::InvalidSubframeHeaderType => "invalid subframe header type".fmt(f),
Self::ExcessiveWastedBits => "excessive number of wasted BPS".fmt(f),
Self::MissingResiduals => "insufficient number of residuals".fmt(f),
Self::InvalidCodingMethod => "invalid residual coding method".fmt(f),
Self::InvalidPartitionOrder => "invalid residual partition order".fmt(f),
Self::InvalidFixedOrder => "invalid FIXED subframe predictor order".fmt(f),
Self::InvalidLpcOrder => "invalid LPC subframe predictor order".fmt(f),
Self::InvalidQlpPrecision => "invalid QLP precision bits".fmt(f),
Self::NegativeLpcShift => "negative shift in LPC subframe".fmt(f),
Self::NoBestLpcOrder => "no best LPC order found".fmt(f),
Self::InsufficientLpcSamples => {
"insufficient samples to calculate LPC parameters".fmt(f)
}
Self::ZeroLpCoefficients => "LP coefficients are all 0".fmt(f),
Self::LpNegativeShiftError => "excessive negative shift in LP quantization".fmt(f),
Self::AccumulatorOverflow => "accumulator overflow in LPC subframe".fmt(f),
Self::TooManySamples => "more samples in stream than indicated in STREAMINFO".fmt(f),
Self::ExcessiveTotalSamples => "too many samples requested".fmt(f),
Self::NoSamples => "no samples written to encoder".fmt(f),
Self::SampleCountMismatch => "samples written to stream differ from expected".fmt(f),
Self::ResidualOverflow => "residual value too large".fmt(f),
Self::SamplesNotDivisibleByChannels => {
"number of samples not divisible number number of channels".fmt(f)
}
Self::InvalidTotalBytes => "invalid total byte count".fmt(f),
Self::InvalidTotalSamples => "invalid total samples count".fmt(f),
Self::ChannelCountMismatch => {
"number of written channels differs from encoder's channel count".fmt(f)
}
Self::ChannelLengthMismatch => "number of written channels are not consistent".fmt(f),
}
}
}
impl From<Error> for std::io::Error {
fn from(err: Error) -> Self {
match err {
Error::Io(io) => io,
Error::Utf8(e) => std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()),
other => std::io::Error::new(std::io::ErrorKind::InvalidData, other.to_string()),
}
}
}
struct Counter<F> {
stream: F,
count: u64,
}
impl<F> Counter<F> {
fn new(stream: F) -> Self {
Self { stream, count: 0 }
}
fn stream(&mut self) -> &mut F {
&mut self.stream
}
}
impl<F: std::io::Read> std::io::Read for Counter<F> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.stream.read(buf).inspect(|bytes| {
self.count += u64::try_from(*bytes).unwrap();
})
}
}
impl<F: std::io::Write> std::io::Write for Counter<F> {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.stream.write(buf).inspect(|bytes| {
self.count += u64::try_from(*bytes).unwrap();
})
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
self.stream.flush()
}
}