///|
/// Audio frame headers: the 14-bit sync code, block size / sample rate /
/// channel / sample size codes, the UTF-8 coded frame number and the CRC-8
/// that protects the header.
/// Decoded frame header. `frame_number` is the frame number for fixed-size
/// blocks and the starting sample number for variable-size blocks.
pub struct FrameHeader {
blocking_strategy : Int
block_size : Int
sample_rate : Int
channels : Int
channel_assignment : Int
bits_per_sample : Int
frame_number : Int64
}
/// Build a `FrameHeader` from already-decoded fields.
pub fn FrameHeader::new(
blocking_strategy : Int,
block_size : Int,
sample_rate : Int,
channels : Int,
channel_assignment : Int,
bits_per_sample : Int,
frame_number : Int64
) -> FrameHeader {
{
blocking_strategy: blocking_strategy,
block_size: block_size,
sample_rate: sample_rate,
channels: channels,
channel_assignment: channel_assignment,
bits_per_sample: bits_per_sample,
frame_number: frame_number,
}
}
/// The absolute sample index at which this frame's audio starts.
pub fn FrameHeader::starting_sample(self : FrameHeader) -> Int64 {
if self.blocking_strategy == 0 {
self.frame_number * Int64::from_int(self.block_size)
} else {
self.frame_number
}
}
/// The fixed block size for block-size codes 1..=5 and 8..=15, or `-1` for a
/// reserved / special code.
fn fixed_block_size(code : Int) -> Int {
match code {
1 => 192
2 => 576
3 => 1152
4 => 2304
5 => 4608
8 => 256
9 => 512
10 => 1024
11 => 2048
12 => 4096
13 => 8192
14 => 16384
15 => 32768
_ => -1
}
}
/// The fixed sample rate for sample-rate codes 1..=11, or `-1` for a reserved /
/// special code.
fn fixed_sample_rate(code : Int) -> Int {
match code {
1 => 88200
2 => 176400
3 => 192000
4 => 8000
5 => 16000
6 => 22050
7 => 24000
8 => 32000
9 => 44100
10 => 48000
11 => 96000
_ => -1
}
}
/// Channel count and channel-assignment code for a 4-bit channel code.
fn channel_info(code : Int) -> (Int, Int) raise DecodeError {
if code <= 7 {
(code + 1, code)
} else if code == 8 || code == 9 || code == 10 {
(2, code)
} else {
raise InvalidFrameHeader
}
}
/// Bits per sample for a 3-bit sample-size code (excluding `0` = from stream).
fn fixed_sample_size(code : Int) -> Int raise DecodeError {
match code {
1 => 8
2 => 12
4 => 16
5 => 20
6 => 24
7 => 32
_ => raise InvalidFrameHeader
}
}
/// Parse a frame header from a byte-aligned reader, verify its CRC-8, and
/// return the decoded header plus the reader positioned at the first subframe.
pub fn BitReader::read_frame_header(self : BitReader, info : StreamInfo) -> (FrameHeader, BitReader) raise DecodeError {
let start_byte = self.pos() / 8
let (sync, r1) = self.read_bits(14)
if sync != 0x3FFE {
raise InvalidFrameSync
}
let (_, r2) = r1.read_bit()
let (blocking, r3) = r2.read_bit()
let (bs_code, r4) = r3.read_bits(4)
let (sr_code, r5) = r4.read_bits(4)
let (ch_code, r6) = r5.read_bits(4)
let (bps_code, r7) = r6.read_bits(3)
let (_, r8) = r7.read_bit()
let (frame_number, r9) = r8.read_utf8_number()
let (block_size, r10) = if bs_code == 6 {
let (v, rr) = r9.read_byte()
(v + 1, rr)
} else if bs_code == 7 {
let (v, rr) = r9.read_u16()
(v + 1, rr)
} else {
let v = fixed_block_size(bs_code)
if v < 0 {
raise InvalidFrameHeader
}
(v, r9)
}
let (sample_rate, r11) = if sr_code == 0 {
(info.sample_rate, r10)
} else if sr_code == 12 {
let (v, rr) = r10.read_byte()
(v * 1000, rr)
} else if sr_code == 13 {
let (v, rr) = r10.read_u16()
(v, rr)
} else if sr_code == 14 {
let (v, rr) = r10.read_u16()
(v * 10, rr)
} else {
let v = fixed_sample_rate(sr_code)
if v < 0 {
raise InvalidFrameHeader
}
(v, r10)
}
let (channels, channel_assignment) = channel_info(ch_code)
let bits_per_sample = if bps_code == 0 {
info.bits_per_sample
} else {
fixed_sample_size(bps_code)
}
let crc_byte = r11.pos() / 8
let (stored_crc, r12) = r11.read_byte()
let expected = crc8_range(self.data(), start_byte, crc_byte, 0x07, 0)
if expected != stored_crc {
raise HeaderCrcMismatch
}
(
FrameHeader::new(blocking, block_size, sample_rate, channels, channel_assignment, bits_per_sample, frame_number),
r12,
)
}