use super::audio_constants::{f32_to_i32, i32_to_f32, I16_MAX_F64};
use alloc::vec::Vec;
pub fn estimate_rice_parameter(residuals: &[f32]) -> u8 {
if residuals.is_empty() {
return 10; }
let mean_abs: f64 = residuals
.iter()
.map(|&r| (r * I16_MAX_F64 as f32).abs() as f64)
.sum::<f64>()
/ residuals.len() as f64;
if mean_abs > 1.0 {
(libm::round(libm::log2(mean_abs)) as u8).clamp(4, 14)
} else {
4
}
}
pub fn estimate_rice_parameter_i32(residuals: &[i32]) -> u8 {
if residuals.is_empty() {
return 4;
}
let max_abs = residuals
.iter()
.map(|&r| r.unsigned_abs())
.max()
.unwrap_or(0) as u64;
if max_abs == 0 {
return 0;
}
let max_unsigned = 2 * max_abs;
let min_k = if max_unsigned > 255 {
let bits_needed = 64 - max_unsigned.leading_zeros();
bits_needed.saturating_sub(8) as u8
} else {
0
};
let sum: u64 = residuals.iter().map(|&r| r.unsigned_abs() as u64).sum();
let mean = (sum / residuals.len() as u64) as u32;
let mean_k = if mean > 0 {
(32 - mean.leading_zeros()) as u8
} else {
0
};
min_k.max(mean_k).clamp(0, 15)
}
pub fn encode(residuals: &[f32], k: u8) -> Vec<u8> {
let samples: Vec<i32> = residuals.iter().map(|&r| f32_to_i32(r)).collect();
encode_i32(&samples, k)
}
pub fn encode_i32(residuals: &[i32], k: u8) -> Vec<u8> {
let mut bits = BitWriter::new();
for &sample in residuals {
encode_sample(&mut bits, sample, k);
}
bits.into_bytes()
}
fn encode_sample(bits: &mut BitWriter, sample: i32, k: u8) {
let unsigned = ((sample << 1) ^ (sample >> 31)) as u32;
let quotient = unsigned >> k;
let remainder = unsigned & ((1 << k) - 1);
assert!(
quotient <= 255,
"rice quotient {quotient} exceeds 255 (k={k}): residuals exceed the k range, re-encode with a larger k"
);
for _ in 0..quotient {
bits.write_bit(1);
}
bits.write_bit(0);
for i in (0..k).rev() {
bits.write_bit((remainder >> i) & 1);
}
}
pub fn decode(encoded: &[u8], k: u8, target_len: usize) -> Vec<f32> {
let decoded_i32 = decode_i32(encoded, k, target_len);
decoded_i32.iter().map(|&s| i32_to_f32(s)).collect()
}
pub fn decode_i32(encoded: &[u8], k: u8, target_len: usize) -> Vec<i32> {
let mut bits = BitReader::new(encoded);
let mut residuals = Vec::with_capacity(target_len);
for _ in 0..target_len {
if bits.is_exhausted() {
residuals.push(0);
continue;
}
let mut quotient = 0u32;
while !bits.is_exhausted() && bits.read_bit() == 1 {
quotient += 1;
if quotient > 255 {
break;
}
}
let mut remainder = 0u32;
for _ in 0..k {
remainder = (remainder << 1) | bits.read_bit();
}
let unsigned = (quotient << k) | remainder;
let signed = ((unsigned >> 1) as i32) ^ (-((unsigned & 1) as i32));
residuals.push(signed);
}
residuals
}
pub struct BitWriter {
bytes: Vec<u8>,
current_byte: u8,
bit_pos: u8,
}
impl BitWriter {
pub fn new() -> Self {
BitWriter {
bytes: Vec::new(),
current_byte: 0,
bit_pos: 0,
}
}
pub fn write_bit(&mut self, bit: u32) {
if bit != 0 {
self.current_byte |= 1 << (7 - self.bit_pos);
}
self.bit_pos += 1;
if self.bit_pos == 8 {
self.bytes.push(self.current_byte);
self.current_byte = 0;
self.bit_pos = 0;
}
}
#[allow(dead_code)]
pub fn write_bits(&mut self, value: u32, num_bits: u8) {
for i in (0..num_bits).rev() {
self.write_bit((value >> i) & 1);
}
}
pub fn into_bytes(mut self) -> Vec<u8> {
if self.bit_pos > 0 {
self.bytes.push(self.current_byte);
}
self.bytes
}
#[allow(dead_code)]
pub fn byte_count(&self) -> usize {
self.bytes.len() + if self.bit_pos > 0 { 1 } else { 0 }
}
}
impl Default for BitWriter {
fn default() -> Self {
Self::new()
}
}
pub struct BitReader<'a> {
bytes: &'a [u8],
byte_pos: usize,
bit_pos: u8,
}
impl<'a> BitReader<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
BitReader {
bytes,
byte_pos: 0,
bit_pos: 0,
}
}
pub fn read_bit(&mut self) -> u32 {
if self.byte_pos >= self.bytes.len() {
return 0;
}
let bit = (self.bytes[self.byte_pos] >> (7 - self.bit_pos)) & 1;
self.bit_pos += 1;
if self.bit_pos == 8 {
self.bit_pos = 0;
self.byte_pos += 1;
}
bit as u32
}
#[allow(dead_code)]
pub fn read_bits(&mut self, num_bits: u8) -> u32 {
let mut value = 0u32;
for _ in 0..num_bits {
value = (value << 1) | self.read_bit();
}
value
}
pub fn is_exhausted(&self) -> bool {
self.byte_pos >= self.bytes.len()
}
#[allow(dead_code)]
pub fn remaining_bytes(&self) -> usize {
if self.byte_pos >= self.bytes.len() {
0
} else {
self.bytes.len() - self.byte_pos
}
}
}