Skip to main content

libflo_audio/core/
rice.rs

1// Rice coding implementation for residual compression
2
3use super::audio_constants::{f32_to_i32, i32_to_f32, I16_MAX_F64};
4use alloc::vec::Vec;
5
6/// Estimate optimal Rice parameter from float residuals
7/// Residuals are expected to be in -1.0 to 1.0 range and will be scaled to 16-bit
8pub fn estimate_rice_parameter(residuals: &[f32]) -> u8 {
9    if residuals.is_empty() {
10        return 10; // Good default for 16-bit audio
11    }
12
13    // Scale to 16-bit range and calculate mean absolute value
14    let mean_abs: f64 = residuals
15        .iter()
16        .map(|&r| (r * I16_MAX_F64 as f32).abs() as f64)
17        .sum::<f64>()
18        / residuals.len() as f64;
19
20    if mean_abs > 1.0 {
21        // Rice parameter k where 2^k approximates mean_abs
22        (libm::round(libm::log2(mean_abs)) as u8).clamp(4, 14)
23    } else {
24        4
25    }
26}
27
28/// Estimate Rice parameter from integer residuals
29/// Ensures k is large enough that no quotient exceeds 255 during encoding
30pub fn estimate_rice_parameter_i32(residuals: &[i32]) -> u8 {
31    if residuals.is_empty() {
32        return 4;
33    }
34
35    // Find maximum absolute value to ensure no overflow
36    let max_abs = residuals
37        .iter()
38        .map(|&r| r.unsigned_abs())
39        .max()
40        .unwrap_or(0) as u64;
41
42    if max_abs == 0 {
43        return 0;
44    }
45
46    // Zigzag encoding doubles positive values: max_unsigned = 2 * max_abs
47    let max_unsigned = 2 * max_abs;
48
49    // quotient = unsigned >> k
50    // We need quotient <= 255, so unsigned <= 255 << k
51    // Therefore k >= log2(unsigned / 255)
52    let min_k = if max_unsigned > 255 {
53        let bits_needed = 64 - max_unsigned.leading_zeros();
54        bits_needed.saturating_sub(8) as u8
55    } else {
56        0
57    };
58
59    // Also consider mean for efficiency
60    let sum: u64 = residuals.iter().map(|&r| r.unsigned_abs() as u64).sum();
61    let mean = (sum / residuals.len() as u64) as u32;
62    let mean_k = if mean > 0 {
63        (32 - mean.leading_zeros()) as u8
64    } else {
65        0
66    };
67
68    // Use the larger of min_k (for correctness) and mean_k (for efficiency)
69    min_k.max(mean_k).clamp(0, 15)
70}
71
72/// Rice encode float residuals (quantizes to 16-bit)
73pub fn encode(residuals: &[f32], k: u8) -> Vec<u8> {
74    let samples: Vec<i32> = residuals.iter().map(|&r| f32_to_i32(r)).collect();
75    encode_i32(&samples, k)
76}
77
78/// Rice encode integer residuals directly
79pub fn encode_i32(residuals: &[i32], k: u8) -> Vec<u8> {
80    let mut bits = BitWriter::new();
81
82    for &sample in residuals {
83        encode_sample(&mut bits, sample, k);
84    }
85
86    bits.into_bytes()
87}
88
89fn encode_sample(bits: &mut BitWriter, sample: i32, k: u8) {
90    // Zigzag encode: map signed to unsigned
91    // 0 -> 0, -1 -> 1, 1 -> 2, -2 -> 3, 2 -> 4, ...
92    let unsigned = ((sample << 1) ^ (sample >> 31)) as u32;
93
94    // Rice coding: quotient and remainder
95    let quotient = unsigned >> k;
96    let remainder = unsigned & ((1 << k) - 1);
97
98    // Unary code for quotient.
99    assert!(
100        quotient <= 255,
101        "rice quotient {quotient} exceeds 255 (k={k}): residuals exceed the k range, re-encode with a larger k"
102    );
103    for _ in 0..quotient {
104        bits.write_bit(1);
105    }
106    bits.write_bit(0);
107
108    // Binary code for remainder
109    for i in (0..k).rev() {
110        bits.write_bit((remainder >> i) & 1);
111    }
112}
113
114/// Rice decode to float residuals
115pub fn decode(encoded: &[u8], k: u8, target_len: usize) -> Vec<f32> {
116    let decoded_i32 = decode_i32(encoded, k, target_len);
117    decoded_i32.iter().map(|&s| i32_to_f32(s)).collect()
118}
119
120/// Rice decode to integer residuals
121pub fn decode_i32(encoded: &[u8], k: u8, target_len: usize) -> Vec<i32> {
122    let mut bits = BitReader::new(encoded);
123    let mut residuals = Vec::with_capacity(target_len);
124
125    for _ in 0..target_len {
126        if bits.is_exhausted() {
127            residuals.push(0);
128            continue;
129        }
130
131        // Read unary quotient
132        let mut quotient = 0u32;
133        while !bits.is_exhausted() && bits.read_bit() == 1 {
134            quotient += 1;
135            if quotient > 255 {
136                break;
137            }
138        }
139
140        // Read binary remainder
141        let mut remainder = 0u32;
142        for _ in 0..k {
143            remainder = (remainder << 1) | bits.read_bit();
144        }
145
146        // Reconstruct unsigned value
147        let unsigned = (quotient << k) | remainder;
148
149        // Zigzag decode
150        // 0 -> 0, 1 -> -1, 2 -> 1, 3 -> -2, 4 -> 2, ...
151        let signed = ((unsigned >> 1) as i32) ^ (-((unsigned & 1) as i32));
152
153        residuals.push(signed);
154    }
155
156    residuals
157}
158
159/// Bit-level writer
160pub struct BitWriter {
161    bytes: Vec<u8>,
162    current_byte: u8,
163    bit_pos: u8,
164}
165
166impl BitWriter {
167    pub fn new() -> Self {
168        BitWriter {
169            bytes: Vec::new(),
170            current_byte: 0,
171            bit_pos: 0,
172        }
173    }
174
175    pub fn write_bit(&mut self, bit: u32) {
176        if bit != 0 {
177            self.current_byte |= 1 << (7 - self.bit_pos);
178        }
179
180        self.bit_pos += 1;
181        if self.bit_pos == 8 {
182            self.bytes.push(self.current_byte);
183            self.current_byte = 0;
184            self.bit_pos = 0;
185        }
186    }
187
188    #[allow(dead_code)]
189    pub fn write_bits(&mut self, value: u32, num_bits: u8) {
190        for i in (0..num_bits).rev() {
191            self.write_bit((value >> i) & 1);
192        }
193    }
194
195    pub fn into_bytes(mut self) -> Vec<u8> {
196        if self.bit_pos > 0 {
197            self.bytes.push(self.current_byte);
198        }
199        self.bytes
200    }
201
202    #[allow(dead_code)]
203    pub fn byte_count(&self) -> usize {
204        self.bytes.len() + if self.bit_pos > 0 { 1 } else { 0 }
205    }
206}
207
208impl Default for BitWriter {
209    fn default() -> Self {
210        Self::new()
211    }
212}
213
214/// Bit-level reader
215pub struct BitReader<'a> {
216    bytes: &'a [u8],
217    byte_pos: usize,
218    bit_pos: u8,
219}
220
221impl<'a> BitReader<'a> {
222    pub fn new(bytes: &'a [u8]) -> Self {
223        BitReader {
224            bytes,
225            byte_pos: 0,
226            bit_pos: 0,
227        }
228    }
229
230    pub fn read_bit(&mut self) -> u32 {
231        if self.byte_pos >= self.bytes.len() {
232            return 0;
233        }
234
235        let bit = (self.bytes[self.byte_pos] >> (7 - self.bit_pos)) & 1;
236
237        self.bit_pos += 1;
238        if self.bit_pos == 8 {
239            self.bit_pos = 0;
240            self.byte_pos += 1;
241        }
242
243        bit as u32
244    }
245
246    #[allow(dead_code)]
247    pub fn read_bits(&mut self, num_bits: u8) -> u32 {
248        let mut value = 0u32;
249        for _ in 0..num_bits {
250            value = (value << 1) | self.read_bit();
251        }
252        value
253    }
254
255    pub fn is_exhausted(&self) -> bool {
256        self.byte_pos >= self.bytes.len()
257    }
258
259    #[allow(dead_code)]
260    pub fn remaining_bytes(&self) -> usize {
261        if self.byte_pos >= self.bytes.len() {
262            0
263        } else {
264            self.bytes.len() - self.byte_pos
265        }
266    }
267}