cauldron 0.0.1

Pure Rust Audio Decoder
Documentation
use crate::io::{ReadBuffer, Sample};
use crate::{audio, errors, Result};

use super::crc::{Crc8Reader};

#[derive(Clone, Copy)]
enum BlockStrategy {
    Fixed,
    Variable,
}

#[derive(Clone, Copy)]
enum BlockTime {
    FrameNumber(u32),
    SampleNumber(u64),
}

#[derive(Clone, Copy, Debug)]
enum ChannelType {
    /// The `n: u8` channels are coded as-is.
    Independent(u8),
    /// Channel 0 is the left channel, channel 1 is the side channel.
    LeftSideStereo,
    /// Channel 0 is the side channel, channel 1 is the right channel.
    RightSideStereo,
    /// Channel 0 is the mid channel, channel 1 is the side channel.
    MidSideStereo,
}

#[derive(Clone, Copy)]
struct FrameHeader {
    pub block_time: BlockTime,
    pub block_size: u16,
    pub sample_rate: u32,
    pub channel_type: ChannelType,
    pub bits_per_sample: u32,
}

/// represent a block of decoded samples from a frame
pub struct Block<S: Sample> {
    /// index of the first sample of this block w.r.t total samples
    first_sample_index: u64,
    /// number of samples in this block
    block_size: u32,
    /// number of channels in this block
    no_channels: u32,
    /// decoded samples with channels interleaved
    buffer: Vec<S>,
}

impl<S: Sample> Block<S> {
    fn new(sample_index: u64, block_size: u32, buffer: Vec<S>) -> Block<S> {
        Block {
            first_sample_index: sample_index,
            block_size: block_size,
            no_channels: buffer.len() as u32 / block_size,
            buffer: buffer,
        }
    }

    pub fn empty() -> Block<S> {
        Block {
            first_sample_index: 0,
            block_size: 0,
            no_channels: 0,
            buffer: Vec::with_capacity(0),
        }
    }

    #[inline(always)]
    pub fn total_samples(&self) -> u32 {
        self.block_size
    }

    #[inline(always)]
    pub fn len(&self) -> u32 {
        self.block_size * self.no_channels
    }

    /// returns the underlying buffer which stores sample
    #[inline(always)]
    pub fn into_buffer(self) -> Vec<S> {
        self.buffer
    }

    /// return the decoded sample from the buffer
    #[inline(always)]
    pub fn get_sample(&self, samples_read: u32) -> S {
        self.buffer[samples_read as usize]
    }
}

fn read_frame_header<R: ReadBuffer>(input: &mut R, audio_info: &audio::AudioInfo) -> Option<Result<FrameHeader>> {
    // will keep track of crc state
    let mut crc_reader = Crc8Reader::new();

    // See https://xiph.org/flac/format.html#frame_header for header info
    let sync_code = match input.read_be_u16() {
        Ok(sync_code) => sync_code,
        Err(_) => return None
    };
    crc_reader.process_bytes(&sync_code.to_be_bytes());

    // check sync code
    // The first 14 bits must be 11111111111110.
    if sync_code & 0b1111_1111_1111_1100 != 0b1111_1111_1111_1000 {
        return Some(errors::parse_error("frame sync code incorrect"));
    }

    // According to format spec, next value must be 0, 1 is reserved for future use
    // when format will get changed, hence throwing unsupported when encountering it
    if sync_code & 0b0000_0000_0000_0010 != 0 {
        return Some(errors::unsupported_error("invalid frame header, encountered reserved value"));
    }

    // The final bit determines the blocking strategy.
    let blocking_strategy = if sync_code & 0b0000_0000_0000_0001 == 0 {
        BlockStrategy::Fixed
    } else {
        BlockStrategy::Variable
    };

    // next 4 bytes determine block size and next 4 determine sample rate
    let bs_sr = input.read_u8().unwrap();
    crc_reader.process_byte(bs_sr);

    let mut block_size = 0u16;
    let mut read_bs_last = 0u8;

    match bs_sr >> 4 {
        0b0000 => return Some(errors::unsupported_error("invalid frame header, encountered reserved value")),
        0b0001 => block_size = 192,
        n if 0b0010 <= n && n <= 0b0101 => block_size = 576 * (1 << (n - 2) as usize),
        0b0110 => read_bs_last = 1, // read 8 bit at end of header
        0b0111 => read_bs_last = 2, // read 16 bit at end of header
        n => block_size = 256 * (1 << (n-8) as usize),
    }

    let mut sample_rate = 0;
    let mut read_sr_last = 0u8;

    // matching sample rate
    match bs_sr & 0b00001111 {
        0b0000 => sample_rate = audio_info.sample_rate, // get from streaminfo block'.
        0b0001 => sample_rate = 88_200,
        0b0010 => sample_rate = 176400,
        0b0011 => sample_rate = 192000,
        0b0100 => sample_rate = 8000,
        0b0101 => sample_rate = 16000,
        0b0110 => sample_rate = 22050,
        0b0111 => sample_rate = 24000,
        0b1000 => sample_rate = 32000,
        0b1001 => sample_rate = 44100,
        0b1010 => sample_rate = 48000,
        0b1011 => sample_rate = 96000,
        0b1100 => read_sr_last = 1, // Read 8bit sample rate from end of header.
        0b1101 => read_sr_last = 2, // Read 16bit sample rate from end of header.
        0b1110 => read_sr_last = 3, // Read 16bit sample rate in tens from end of header.
        _ => return Some(errors::parse_error("invalid frame header")),
    }

    // Next 4 bytes is for no of channels, then bits per sample and then reserved bit
    let ch_bps_r = input.read_u8().unwrap();
    crc_reader.process_byte(bs_sr);

    let channel_type = match ch_bps_r >> 4 {
        n if n < 8 => ChannelType::Independent(n + 1),
        0b1000 => ChannelType::LeftSideStereo,
        0b1001 => ChannelType::RightSideStereo,
        0b1010 => ChannelType::MidSideStereo,
        _ => return Some(errors::unsupported_error("Invalid frame header, encountered reserved value")),
    };

    Some(Ok(FrameHeader {
        block_time: BlockTime::FrameNumber(0),
        block_size: block_size,
        sample_rate: sample_rate,
        channel_type: channel_type,
        bits_per_sample: 0,
    }))
}

pub fn decode_next_frame<R: ReadBuffer, S: Sample>(
    input: &mut R,
    mut block_buffer: Vec<S>,
    audio_info: &audio::AudioInfo,
) -> Option<Result<Block<S>>> {
    let frame_header = match read_frame_header(input, audio_info) {
        None => return None,
        Some(h) => h,
    };
    None
}