ResidualPartition

Enum ResidualPartition 

Source
pub enum ResidualPartition<const RICE_MAX: u32, I> {
    Standard {
        rice: BitCount<RICE_MAX>,
        residuals: Vec<I>,
    },
    Escaped {
        escape_size: SignedBitCount<0b11111>,
        residuals: Vec<I>,
    },
    Constant {
        partition_len: usize,
    },
}
Expand description

An individual residual block partition

Each partition consists of a Rice parameter followed by an optional escape code and signed residual values. The number of bits to read for the Rice parameters depends on if we’re using coding method 0 or 1. If the Rice parameter equals the maximum, it means the partition is escaped in some way (this is an uncommon case).

BitsMeaning
4 or 5Rice parameter
(5)escape code if parameter is 1111 or 11111

The total number of residuals in the partition is:

block size ÷ partition count - predictor order

for the first partition, and:

block size ÷ partition count

for subsequent partitions.

If the partition is escaped, we read an additional 5 bit value to determine the size of each signed residual in the partition. If the escape code is 0, all the residuals in the partition are 0 (this is an even more uncommon case).

§Example

use flac_codec::stream::ResidualPartition;
use bitstream_io::{BitReader, BitRead, BigEndian, BitCount};

let data: &[u8] = &[
    0b0001_01_0_0,  // Rice code + residuals
    0b01_0_001_0_0,
    0b01_0_001_0_0,
    0b01_0_001_0_0,
    0b01_0_001_0_0,
    0b01_0_001_0_0,
    0b01_0_001_0_0,
    0b01_0_001_0_0,
    0b01_0_001_0_0,
    0b01_0_001_0_0,
];

let mut r = BitReader::endian(data, BigEndian);
assert_eq!(
    r.parse_using::<ResidualPartition<0b1111, i32>>(19).unwrap(),
    ResidualPartition::Standard {
        rice: BitCount::new::<0b0001>(),
        residuals: vec![
             1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
             2, 2, 2, 2, 2, 2, 2, 2, 2
        ],
    },
);

Each individual residual is a unary value with a stop bit of 1 for the most-significant bits, followed by “Rice” number of bits as the least significant bits, combined into a single unsigned value.

Unary-encoding is simply counting the number of 0 bits before the next 1 bit:

BitsValue
10
011
0012
00013
000014

Unlike regular twos-complement signed values, individual residuals are stored with the sign in the least significant bit position. They can be transformed from unsigned to signed like:

fn unsigned_to_signed(unsigned: u32) -> i32 {
    if (unsigned & 1) == 1 {
        // negative residual
        -((unsigned >> 1) as i32) - 1
    } else {
        // positive residual
        (unsigned >> 1) as i32
    }
}

In our example, above, the Rice parameter happens to be 1 and all the sign bits happen to be 0, so the value of each signed residual is simply its preceding unary value (which are all 01 or 001, meaning 1 and 2).

As one can see, the smaller the value each residual has, the smaller it can be when written to disk. And the key to making residual values small is to choose predictor coefficients which best match the input signal. The more accurate the prediction, the less difference there is between the predicted values and the actual values - which means smaller residuals - which means better compression.

Variants§

§

Standard

A standard residual partition

Fields

§rice: BitCount<RICE_MAX>

The partition’s Rice parameter

§residuals: Vec<I>

The partition’s residuals

§

Escaped

An escaped residual partition

Fields

§escape_size: SignedBitCount<0b11111>

The size of each residual in bits

§residuals: Vec<I>

The partition’s residuals

§

Constant

A partition in which all residuals are 0

Fields

§partition_len: usize

The length of the partition in samples

Trait Implementations§

Source§

impl<const RICE_MAX: u32, I: Debug> Debug for ResidualPartition<RICE_MAX, I>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<const RICE_MAX: u32, I: SignedInteger> FromBitStreamUsing for ResidualPartition<RICE_MAX, I>

Source§

type Context = usize

Some context to consume when parsing
Source§

type Error = Error

Error generated during parsing, such as io::Error
Source§

fn from_reader<R: BitRead + ?Sized>( r: &mut R, partition_len: usize, ) -> Result<Self, Error>

Parse Self from reader with the given context
Source§

impl<const RICE_MAX: u32, I: PartialEq> PartialEq for ResidualPartition<RICE_MAX, I>

Source§

fn eq(&self, other: &ResidualPartition<RICE_MAX, I>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<const RICE_MAX: u32, I: SignedInteger> ToBitStream for ResidualPartition<RICE_MAX, I>

Source§

type Error = Error

Error generated during building, such as io::Error
Source§

fn to_writer<W: BitWrite + ?Sized>(&self, w: &mut W) -> Result<(), Error>

Generate self to writer
Source§

fn bits<C>(&self) -> Result<C, Self::Error>
where C: Counter, Self: Sized,

Returns length of self in bits, if possible
Source§

fn bits_len<C, E>(&self) -> Result<C, Self::Error>
where C: Counter, E: Endianness, Self: Sized,

👎Deprecated since 4.0.0: use of bits() is preferred
Returns total length of self, if possible
Source§

impl<const RICE_MAX: u32, I: Eq> Eq for ResidualPartition<RICE_MAX, I>

Source§

impl<const RICE_MAX: u32, I> StructuralPartialEq for ResidualPartition<RICE_MAX, I>

Auto Trait Implementations§

§

impl<const RICE_MAX: u32, I> Freeze for ResidualPartition<RICE_MAX, I>

§

impl<const RICE_MAX: u32, I> RefUnwindSafe for ResidualPartition<RICE_MAX, I>
where I: RefUnwindSafe,

§

impl<const RICE_MAX: u32, I> Send for ResidualPartition<RICE_MAX, I>
where I: Send,

§

impl<const RICE_MAX: u32, I> Sync for ResidualPartition<RICE_MAX, I>
where I: Sync,

§

impl<const RICE_MAX: u32, I> Unpin for ResidualPartition<RICE_MAX, I>
where I: Unpin,

§

impl<const RICE_MAX: u32, I> UnwindSafe for ResidualPartition<RICE_MAX, I>
where I: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.