pub enum Subframe<I> {
Constant {
block_size: u16,
sample: I,
wasted_bps: u32,
},
Verbatim {
samples: Vec<I>,
wasted_bps: u32,
},
Fixed {
order: u8,
warm_up: Vec<I>,
residuals: Residuals<I>,
wasted_bps: u32,
},
Lpc {
order: NonZero<u8>,
warm_up: Vec<I>,
precision: SignedBitCount<15>,
shift: u32,
coefficients: Vec<i32>,
residuals: Residuals<I>,
wasted_bps: u32,
},
}Expand description
A FLAC’s frame’s subframe, one per channel
A subframe consists of a subframe header followed by subframe data.
Variants§
Constant
A CONSTANT subframe, in which all samples are identical
| Bits | Field |
|---|---|
| subframe’s bits-per-sample | sample |
This single sample is repeated for all the samples in the subframe.
This is typically for long stretches of silence, or for the difference channel when both channels are identical in a stereo stream (false stereo).
§Example
use flac_codec::stream::Subframe;
use bitstream_io::{BitReader, BitRead, BigEndian, SignedBitCount};
let data: &[u8] = &[
0b0_000000_0, // subframe header
0x00, 0x00, // subframe data
];
let mut r = BitReader::endian(data, BigEndian);
assert_eq!(
r.parse_using::<Subframe<i32>>((20, SignedBitCount::new::<16>())).unwrap(),
Subframe::Constant {
// taken from context
block_size: 20,
// constant subframes always have exactly one sample
// this sample's size is a signed 16-bit value
// taken from the subframe signed bit count
sample: 0x00_00,
// wasted bits-per-sample is taken from the subframe header
wasted_bps: 0,
},
);Fields
sample: IThe subframe’s sample
Verbatim
A VERBATIM subframe, in which all samples are stored uncompressed
| Bits | Field |
|---|---|
| subframe’s bps | samples₀ |
| subframe’s bps | samples₁ |
| subframe’s bps | samples₂ |
| ⋮ |
The number of samples equals the frame’s block size.
This is for random noise which does not compress well by any other method.
§Example
use flac_codec::stream::Subframe;
use bitstream_io::{BitReader, BitRead, BigEndian, SignedBitCount};
let data: &[u8] = &[
0b0_000001_0, // subframe header
// subframe data
0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09,
0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e,
0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13,
];
let mut r = BitReader::endian(data, BigEndian);
assert_eq!(
r.parse_using::<Subframe<i32>>((20, SignedBitCount::new::<16>())).unwrap(),
Subframe::Verbatim {
// the total number of samples equals the block size
// (20 in this case)
// each sample is a signed 16-bit value,
// taken from the subframe signed bit count
samples: vec![
0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13,
],
// wasted bits-per-sample is taken from the subframe header
wasted_bps: 0,
},
);Fixed
A FIXED subframe, encoded with a fixed set of parameters
| Bits | Field |
|---|---|
| subframe’s bps | warm_up₀ |
| subframe’s bps | warm_up₁ |
| subframe’s bps | warm_up₂ |
| ⋮ | |
Residuals |
The number of warm-up simples equals the subframe’s predictor order (from the subframe header).
FIXED subframes have predictor coefficients that are defined by their predictor order. Because those coefficients require no floating-point math to calculate, these subframes can be encoded by limited hardware with no floating-point capabilities.
§Example
use flac_codec::stream::{Subframe, Residuals, ResidualPartition};
use bitstream_io::{BitReader, BitRead, BigEndian, BitCount, SignedBitCount};
let data: &[u8] = &[
0b0_001100_0, // subframe header
// warm-up samples
0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
// residuals
0x00, 0x3f, 0xff, 0xc0,
];
let mut r = BitReader::endian(data, BigEndian);
assert_eq!(
r.parse_using::<Subframe<i32>>((20, SignedBitCount::new::<16>())).unwrap(),
Subframe::Fixed {
// predictor order is determined from subframe header
order: 4,
// the total number of warm-up samples equals the predictor order (4)
// each warm-up sample is a signed 16-bit value,
// taken from the subframe signed bit count
warm_up: vec![0x00, 0x01, 0x02, 0x03],
// the total number of residuals equals the block size
// minus the predictor order,
// which is 20 - 4 = 16 in this case
residuals: Residuals::Method0 {
partitions: vec![
ResidualPartition::Standard {
rice: BitCount::new::<0>(),
residuals: vec![0; 16],
}
],
},
// wasted bits-per-sample is taken from the subframe header
wasted_bps: 0,
},
);Fields
Lpc
An LPC subframe, encoded with a variable set of parameters
| Bits | Field |
|---|---|
| subframe’s bps | warm_up₀ |
| subframe’s bps | warm_up₁ |
| subframe’s bps | warm_up₂ |
| ⋮ | |
| 4 | precision (+1) |
| 5 | shift |
precision | coefficients₀ |
precision | coefficients₁ |
precision | coefficients₂ |
| ⋮ | |
Residuals |
The number of warm-up samples and number of predictor
coefficients is equal to the subframe’s predictor order
(from the subframe header). The precision value
is used to determine the size of the predictor coefficients.
The shift value is stored as a signed integer,
but negative shifts are not supported by the format
and should be considered an error.
§Example
use flac_codec::stream::{Subframe, Residuals, ResidualPartition};
use bitstream_io::{BitReader, BitRead, BigEndian, BitCount, SignedBitCount};
use std::num::NonZero;
let data: &[u8] = &[
0b0_100000_0, // subframe header
// warm-up sample
0x00, 0x00,
// precision + shift + coefficient
0b1011_0101, 0b1_0111110, 0b00101_000,
// residuals
0x02, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x80,
];
let mut r = BitReader::endian(data, BigEndian);
assert_eq!(
r.parse_using::<Subframe<i32>>((20, SignedBitCount::new::<16>())).unwrap(),
Subframe::Lpc {
// predictor order is determined from the subframe header
order: NonZero::new(1).unwrap(),
// the total number of warm-up samples equals the predictor order (1)
// each warm-up sample is a signed 16-bit value,
// taken from the subframe signed bit count
warm_up: vec![0x00],
// precision is a 4 bit value, plus one
precision: SignedBitCount::new::<{0b1011 + 1}>(), // 12 bits
// shift is a 5 bit value
shift: 0b0101_1, // 11
// the total number of coefficients equals the predictor order (1)
// size of each coefficient is a signed 12-bit value (from precision)
coefficients: vec![0b0111110_00101], // 1989
// the total number of residuals equals the block size
// minus the predictor order,
// which is 20 - 1 = 19 in this case
residuals: Residuals::Method0 {
partitions: vec![
ResidualPartition::Standard {
rice: BitCount::new::<1>(),
residuals: vec![
1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2
],
}
],
},
// wasted bits-per-sample is taken from the subframe header
wasted_bps: 0,
},
);Fields
precision: SignedBitCount<15>The subframe’s QLP precision
Implementations§
Source§impl<I> Subframe<I>
impl<I> Subframe<I>
Sourcepub fn subframe_type(&self) -> SubframeType
pub fn subframe_type(&self) -> SubframeType
Our subframe type
Source§impl<I: SignedInteger> Subframe<I>
impl<I: SignedInteger> Subframe<I>
Sourcepub fn decode(&self) -> Box<dyn Iterator<Item = I> + '_>
pub fn decode(&self) -> Box<dyn Iterator<Item = I> + '_>
Decodes subframe to samples
Note that decoding subframes to samples using this method
is intended for analysis purposes. The crate::decode
module’s decoders are preferred for general-purpose
decoding as they perform fewer temporary allocations.