use crate::core_types::{
NUM_LSF, SUPERFRAME_BITS_600, SUPERFRAME_BYTES_600,
LSF_BITS_600, PITCH_BITS_600, GAIN_BITS_600,
VOICING_BITS_600, JITTER_BITS_600, SPARE_BITS_600,
SuperFrameQuantized,
};
pub const BIT_ALLOC_600: &[(&str, usize)] = &[
("lsf0", 3), ("lsf1", 3), ("lsf2", 3), ("lsf3", 3),
("lsf4", 2), ("lsf5", 2), ("lsf6", 2), ("lsf7", 2),
("lsf8", 2), ("lsf9", 2),
("pitch", 6),
("gain", 5),
("voicing", 4),
("jitter", 1),
("spare", 1),
];
struct BitWriter<'a> {
buf: &'a mut [u8],
byte_pos: usize,
bit_pos: u8, }
impl<'a> BitWriter<'a> {
fn new(buf: &'a mut [u8]) -> Self {
for b in buf.iter_mut() {
*b = 0;
}
Self {
buf,
byte_pos: 0,
bit_pos: 0,
}
}
fn write(&mut self, value: u8, n_bits: usize) {
debug_assert!(n_bits >= 1 && n_bits <= 8);
for i in (0..n_bits).rev() {
let bit = (value >> i) & 1;
if bit == 1 {
self.buf[self.byte_pos] |= 1 << (7 - self.bit_pos);
}
self.bit_pos += 1;
if self.bit_pos >= 8 {
self.bit_pos = 0;
self.byte_pos += 1;
}
}
}
fn bits_written(&self) -> usize {
self.byte_pos * 8 + self.bit_pos as usize
}
}
struct BitReader<'a> {
buf: &'a [u8],
byte_pos: usize,
bit_pos: u8,
}
impl<'a> BitReader<'a> {
fn new(buf: &'a [u8]) -> Self {
Self {
buf,
byte_pos: 0,
bit_pos: 0,
}
}
fn read(&mut self, n_bits: usize) -> u8 {
debug_assert!(n_bits >= 1 && n_bits <= 8);
let mut value: u8 = 0;
for _ in 0..n_bits {
value <<= 1;
if self.byte_pos < self.buf.len() {
let bit = (self.buf[self.byte_pos] >> (7 - self.bit_pos)) & 1;
value |= bit;
}
self.bit_pos += 1;
if self.bit_pos >= 8 {
self.bit_pos = 0;
self.byte_pos += 1;
}
}
value
}
fn bits_read(&self) -> usize {
self.byte_pos * 8 + self.bit_pos as usize
}
}
pub fn pack_superframe(sq: &SuperFrameQuantized, out: &mut [u8; SUPERFRAME_BYTES_600]) -> usize {
let mut w = BitWriter::new(out);
for i in 0..NUM_LSF {
w.write(sq.lsf_indices[i], LSF_BITS_600[i]);
}
w.write(sq.pitch_index, PITCH_BITS_600);
w.write(sq.gain_index, GAIN_BITS_600);
w.write(sq.voicing_bits, VOICING_BITS_600);
w.write(sq.jitter_bit, JITTER_BITS_600);
w.write(0, SPARE_BITS_600);
w.bits_written()
}
pub fn unpack_superframe(data: &[u8; SUPERFRAME_BYTES_600]) -> (SuperFrameQuantized, usize) {
let mut r = BitReader::new(data);
let mut sq = SuperFrameQuantized::default();
for i in 0..NUM_LSF {
sq.lsf_indices[i] = r.read(LSF_BITS_600[i]);
}
sq.pitch_index = r.read(PITCH_BITS_600);
sq.gain_index = r.read(GAIN_BITS_600);
sq.voicing_bits = r.read(VOICING_BITS_600);
sq.jitter_bit = r.read(JITTER_BITS_600);
let _spare = r.read(SPARE_BITS_600);
(sq, r.bits_read())
}
pub fn verify_bit_budget() -> bool {
let total: usize = BIT_ALLOC_600.iter().map(|(_, bits)| *bits).sum();
total == SUPERFRAME_BITS_600
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bitwriter_single_bits() {
let mut buf = [0u8; 2];
let bits_written;
{
let mut w = BitWriter::new(&mut buf);
w.write(1, 1); w.write(0, 1); w.write(1, 1); w.write(1, 1); w.write(0, 1); w.write(0, 1); w.write(1, 1); w.write(0, 1); bits_written = w.bits_written();
}
assert_eq!(buf[0], 0xB2);
assert_eq!(bits_written, 8);
}
#[test]
fn test_bitwriter_multi_bit() {
let mut buf = [0u8; 2];
let bits_written;
{
let mut w = BitWriter::new(&mut buf);
w.write(0b101, 3); w.write(0b11010, 5); bits_written = w.bits_written();
}
assert_eq!(buf[0], 0xBA);
assert_eq!(bits_written, 8);
}
#[test]
fn test_bitwriter_crosses_byte() {
let mut buf = [0u8; 2];
let bits_written;
{
let mut w = BitWriter::new(&mut buf);
w.write(0b111, 3); w.write(0b101010, 6); bits_written = w.bits_written();
}
assert_eq!(buf[0], 0xF5);
assert_eq!(buf[1], 0x00);
assert_eq!(bits_written, 9);
}
#[test]
fn test_bitreader_single_bits() {
let buf = [0xB2u8, 0x00]; let mut r = BitReader::new(&buf);
assert_eq!(r.read(1), 1);
assert_eq!(r.read(1), 0);
assert_eq!(r.read(1), 1);
assert_eq!(r.read(1), 1);
assert_eq!(r.read(1), 0);
assert_eq!(r.read(1), 0);
assert_eq!(r.read(1), 1);
assert_eq!(r.read(1), 0);
assert_eq!(r.bits_read(), 8);
}
#[test]
fn test_bitreader_multi_bit() {
let buf = [0xBA]; let mut r = BitReader::new(&buf);
assert_eq!(r.read(3), 0b101); assert_eq!(r.read(5), 0b11010); }
#[test]
fn test_writer_reader_roundtrip() {
let mut buf = [0u8; 4];
let mut w = BitWriter::new(&mut buf);
w.write(0b110, 3);
w.write(0b01011, 5);
w.write(0b1111, 4);
w.write(0b00, 2);
w.write(0b101101, 6);
let mut r = BitReader::new(&buf);
assert_eq!(r.read(3), 0b110);
assert_eq!(r.read(5), 0b01011);
assert_eq!(r.read(4), 0b1111);
assert_eq!(r.read(2), 0b00);
assert_eq!(r.read(6), 0b101101);
}
#[test]
fn test_bit_budget_table() {
assert!(verify_bit_budget(), "Bit allocation table doesn't sum to {}", SUPERFRAME_BITS_600);
}
#[test]
fn test_bit_alloc_field_count() {
assert_eq!(BIT_ALLOC_600.len(), 15);
}
#[test]
fn test_pack_unpack_zeros() {
let sq = SuperFrameQuantized::default();
let mut buf = [0u8; SUPERFRAME_BYTES_600];
let bits = pack_superframe(&sq, &mut buf);
assert_eq!(bits, SUPERFRAME_BITS_600);
let (recovered, bits_read) = unpack_superframe(&buf);
assert_eq!(bits_read, SUPERFRAME_BITS_600);
assert_eq!(recovered, sq);
}
#[test]
fn test_pack_unpack_max_values() {
let sq = SuperFrameQuantized {
lsf_indices: [
(1 << LSF_BITS_600[0]) - 1,
(1 << LSF_BITS_600[1]) - 1,
(1 << LSF_BITS_600[2]) - 1,
(1 << LSF_BITS_600[3]) - 1,
(1 << LSF_BITS_600[4]) - 1,
(1 << LSF_BITS_600[5]) - 1,
(1 << LSF_BITS_600[6]) - 1,
(1 << LSF_BITS_600[7]) - 1,
(1 << LSF_BITS_600[8]) - 1,
(1 << LSF_BITS_600[9]) - 1,
],
pitch_index: (1 << PITCH_BITS_600) - 1,
gain_index: (1 << GAIN_BITS_600) - 1,
voicing_bits: (1 << VOICING_BITS_600) - 1,
jitter_bit: 1,
};
let mut buf = [0u8; SUPERFRAME_BYTES_600];
pack_superframe(&sq, &mut buf);
let (recovered, _) = unpack_superframe(&buf);
assert_eq!(recovered, sq);
}
#[test]
fn test_pack_unpack_mixed_values() {
let sq = SuperFrameQuantized {
lsf_indices: [5, 3, 7, 1, 2, 0, 3, 1, 2, 3],
pitch_index: 42,
gain_index: 17,
voicing_bits: 0b1011,
jitter_bit: 1,
};
let mut buf = [0u8; SUPERFRAME_BYTES_600];
pack_superframe(&sq, &mut buf);
let (recovered, _) = unpack_superframe(&buf);
assert_eq!(recovered.lsf_indices, sq.lsf_indices);
assert_eq!(recovered.pitch_index, sq.pitch_index);
assert_eq!(recovered.gain_index, sq.gain_index);
assert_eq!(recovered.voicing_bits, sq.voicing_bits);
assert_eq!(recovered.jitter_bit, sq.jitter_bit);
}
#[test]
fn test_pack_unpack_exhaustive_lsf() {
for i0 in 0..8u8 {
for i1 in 0..8u8 {
let sq = SuperFrameQuantized {
lsf_indices: [i0, i1, 4, 2, 1, 3, 0, 2, 1, 3],
pitch_index: 30,
gain_index: 15,
voicing_bits: 5,
jitter_bit: 0,
};
let mut buf = [0u8; SUPERFRAME_BYTES_600];
pack_superframe(&sq, &mut buf);
let (recovered, _) = unpack_superframe(&buf);
assert_eq!(recovered, sq, "Failed for lsf[0]={}, lsf[1]={}", i0, i1);
}
}
}
#[test]
fn test_pack_bit_count() {
let sq = SuperFrameQuantized::default();
let mut buf = [0u8; SUPERFRAME_BYTES_600];
let bits = pack_superframe(&sq, &mut buf);
assert_eq!(bits, 41);
}
#[test]
fn test_buffer_size() {
assert_eq!(SUPERFRAME_BYTES_600, 6);
assert_eq!((SUPERFRAME_BITS_600 + 7) / 8, 6);
}
#[test]
fn test_spare_bits_zero() {
let sq = SuperFrameQuantized {
lsf_indices: [7, 7, 7, 7, 3, 3, 3, 3, 3, 3],
pitch_index: 63,
gain_index: 31,
voicing_bits: 15,
jitter_bit: 1,
};
let mut buf = [0u8; SUPERFRAME_BYTES_600];
pack_superframe(&sq, &mut buf);
let mut r = BitReader::new(&buf);
for _ in 0..40 {
r.read(1);
}
let spare = r.read(1);
assert_eq!(spare, 0, "Spare bit should be 0");
}
#[test]
fn test_pack_deterministic() {
let sq = SuperFrameQuantized {
lsf_indices: [2, 5, 1, 6, 3, 0, 2, 1, 3, 1],
pitch_index: 33,
gain_index: 20,
voicing_bits: 0b0110,
jitter_bit: 0,
};
let mut buf1 = [0u8; SUPERFRAME_BYTES_600];
let mut buf2 = [0u8; SUPERFRAME_BYTES_600];
pack_superframe(&sq, &mut buf1);
pack_superframe(&sq, &mut buf2);
assert_eq!(buf1, buf2, "Packing must be deterministic");
}
}