cauldron 0.0.1

Pure Rust Audio Decoder
Documentation
mod read;
mod write;

use std::fs;
use std::io;

use super::{audio, errors, utils, Result};

pub use read::ReadBuffer;
pub use write::WriteBuffer;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SampleFormat {
    /// Unsigned 8-bit integer.
    U8,
    /// Unsigned 16-bit integer.
    U16,
    /// Unsigned 24-bit integer.
    U24,
    /// Unsigned 32-bit integer.
    U32,
    /// Signed 8-bit integer.
    S8,
    /// Signed 16-bit integer.
    S16,
    /// Signed 24-bit integer.
    S24,
    /// Signed 32-bit integer.
    S32,
    /// Single prevision (32-bit) floating point.
    F32,
}

/// A type that can be used to represent audio samples.
///
/// It makes decoding can be generic over `i8`, `i16`, `i32` and `f32`.
///
/// All integer formats with bit depths up to 32 bits per sample can be decoded
/// into `i32`, but it takes up more memory. If you know beforehand that you
/// will be reading a file with 16 bits per sample, then decoding into an `i16`
/// will be sufficient.
pub trait Sample: Sized + Copy {
    /// Reads the audio sample from the data buffer
    fn read<R: ReadBuffer>(reader: &mut R, sample_format: SampleFormat, bits: u16) -> Result<Self>;

    /// Writes the audio sample to the data buffer
    fn write<W: WriteBuffer>(self, writer: &mut W, bits: u16) -> Result<()>;
}

impl Sample for i8 {
    fn read<R: ReadBuffer>(reader: &mut R, sample_format: SampleFormat, bits: u16) -> Result<i8> {
        if sample_format == SampleFormat::F32 {
            return errors::unsupported_error::<i8>("Invalid sample format");
        }
        match bits {
            8 => Ok(reader.read_u8().map(utils::signed_from_u8)?),
            _ => errors::unsupported_error::<i8>(""),
        }
    }

    fn write<W: WriteBuffer>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            8 => Ok(writer.write_u8(utils::u8_from_signed(self))?),
            16 => Ok(writer.write_le_i16(self as i16)?),
            24 => Ok(writer.write_le_i24(self as i32)?),
            32 => Ok(writer.write_le_i32(self as i32)?),
            _ => errors::unsupported_error::<()>(""),
        }
    }
}

impl Sample for i16 {
    fn read<R: ReadBuffer>(reader: &mut R, sample_format: SampleFormat, bits: u16) -> Result<i16> {
        if sample_format == SampleFormat::F32 {
            return errors::unsupported_error::<i16>("Invalid sample format");
        }
        match bits {
            8 => Ok(reader
                .read_u8()
                .map(utils::signed_from_u8)
                .map(|x| x as i16)?),
            16 => Ok(reader.read_le_i16()?),
            _ => errors::unsupported_error::<i16>(""),
        }
    }

    fn write<W: WriteBuffer>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            8 => Ok(writer.write_u8(utils::u8_from_signed(utils::narrow_to_i8(self as i32)?))?),
            16 => Ok(writer.write_le_i16(self)?),
            24 => Ok(writer.write_le_i24(self as i32)?),
            32 => Ok(writer.write_le_i32(self as i32)?),
            _ => errors::unsupported_error::<()>(""),
        }
    }
}

impl Sample for i32 {
    fn read<R: ReadBuffer>(reader: &mut R, sample_format: SampleFormat, bits: u16) -> Result<i32> {
        if sample_format == SampleFormat::F32 {
            return errors::unsupported_error::<i32>("Invalid sample format");
        }
        match bits {
            8 => Ok(reader
                .read_u8()
                .map(utils::signed_from_u8)
                .map(|x| x as i32)?),
            16 => Ok(reader.read_le_i16().map(|x| x as i32)?),
            24 => Ok(reader.read_le_i24()?),
            32 => Ok(reader.read_le_i32()?),
            _ => errors::unsupported_error::<i32>(""),
        }
    }

    fn write<W: WriteBuffer>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            8 => Ok(writer.write_u8(utils::u8_from_signed(utils::narrow_to_i8(self as i32)?))?),
            16 => Ok(writer.write_le_i16(utils::narrow_to_i16(self)?)?),
            24 => Ok(writer.write_le_i24(utils::narrow_to_i24(self)?)?),
            32 => Ok(writer.write_le_i32(self as i32)?),
            _ => errors::unsupported_error::<()>(""),
        }
    }
}

impl Sample for f32 {
    fn read<R: ReadBuffer>(reader: &mut R, sample_format: SampleFormat, bits: u16) -> Result<f32> {
        if sample_format == SampleFormat::F32 {
            match bits {
                32 => Ok(reader.read_le_f32()?),
                _ => errors::unsupported_error::<f32>(""),
            }
        } else {
            match bits {
                8 => Ok(reader
                    .read_u8()
                    .map(utils::signed_from_u8)
                    .map(|x| x as f32)?),
                16 => Ok(reader.read_le_i16().map(|x| x as f32)?),
                24 => Ok(reader.read_le_i24()? as f32),
                _ => errors::unsupported_error::<f32>(""),
            }
        }
    }

    fn write<W: WriteBuffer>(self, writer: &mut W, bits: u16) -> Result<()> {
        match bits {
            32 => Ok(writer.write_le_f32(self)?),
            _ => errors::unsupported_error::<()>(""),
        }
    }
}

pub type MediaSource = io::BufReader<fs::File>;

/// A `AudioReader` is a container demuxer. It provides methods to probe a media container for
/// information and access the streams encapsulated in the container.
pub trait AudioReader {
    /// Reads the header and initializes audio info
    fn read_header(&mut self) -> Result<audio::AudioInfo>;

    /// Returns the buffer for the iterator
    fn buffer(&mut self) -> &mut MediaSource;
}

/// Returns a lazy iterator on audio samples
pub trait AudioSamplesIterator<S: Sample> {
    fn next(&mut self) -> Option<Result<S>>;
}

impl<'r, S: Sample> Iterator for dyn AudioSamplesIterator<S> + 'r {
    type Item = Result<S>;

    fn next(&mut self) -> Option<Result<S>> {
        self.next()
    }
}