Skip to main content

audio_codec/
g722.rs

1use super::{CodecError, Decoder, Encoder, Sample};
2
3#[cfg(feature = "std")]
4use super::PcmBuf;
5
6pub enum Bitrate {
7    Mode1_64000,
8    Mode2_56000,
9    Mode3_48000,
10}
11
12// Quantization decision thresholds used in the encoder
13const QUANT_DECISION_LEVEL: [i32; 32] = [
14    0, 35, 72, 110, 150, 190, 233, 276, 323, 370, 422, 473, 530, 587, 650, 714, 786, 858, 940,
15    1023, 1121, 1219, 1339, 1458, 1612, 1765, 1980, 2195, 2557, 2919, 0, 0,
16];
17
18// Negative quantization interval indices
19const QUANT_INDEX_NEG: [i32; 32] = [
20    0, 63, 62, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11,
21    10, 9, 8, 7, 6, 5, 4, 0,
22];
23
24// Positive quantization interval indices
25const QUANT_INDEX_POS: [i32; 32] = [
26    0, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39,
27    38, 37, 36, 35, 34, 33, 32, 0,
28];
29
30// Scale factor adaptation table for low band
31const SCALE_FACTOR_ADJUST_LOW: [i32; 8] = [-60, -30, 58, 172, 334, 538, 1198, 3042];
32
33// Mapping from 4 bits of low band code to 3 bits of logarithmic scale factor
34const LOG_SCALE_FACTOR_MAP: [i32; 16] = [0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0];
35
36// Inverse logarithmic base for computing the scale factor
37const INV_LOG_BASE: [i32; 32] = [
38    2048, 2093, 2139, 2186, 2233, 2282, 2332, 2383, 2435, 2489, 2543, 2599, 2656, 2714, 2774, 2834,
39    2896, 2960, 3025, 3091, 3158, 3228, 3298, 3371, 3444, 3520, 3597, 3676, 3756, 3838, 3922, 4008,
40];
41
42// Quantizer multipliers for 4-bit low band
43const QUANT_MULT_LOW_4BIT: [i32; 16] = [
44    0, -20456, -12896, -8968, -6288, -4240, -2584, -1200, 20456, 12896, 8968, 6288, 4240, 2584,
45    1200, 0,
46];
47
48// Quantizer multipliers for 2-bit high band
49const QUANT_MULT_HIGH_2BIT: [i32; 4] = [-7408, -1616, 7408, 1616];
50
51// QMF filter coefficients for band splitting and reconstruction
52const QMF_FILTER_COEFS: [i32; 12] = [3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11];
53
54// Negative high band quantization indices
55const HIGH_QUANT_INDEX_NEG: [i32; 3] = [0, 1, 0];
56
57// Positive high band quantization indices
58const HIGH_QUANT_INDEX_POS: [i32; 3] = [0, 3, 2];
59
60// Scale factor adaptation table for high band
61const SCALE_FACTOR_ADJUST_HIGH: [i32; 3] = [0, -214, 798];
62
63// Mapping from 2 bits of high band code to 2 bits of logarithmic scale factor
64const HIGH_LOG_SCALE_MAP: [i32; 4] = [2, 1, 2, 1];
65
66// Quantizer multipliers for 5-bit quantization (56kbps mode)
67const QUANT_MULT_56K: [i32; 32] = [
68    -280, -280, -23352, -17560, -14120, -11664, -9752, -8184, -6864, -5712, -4696, -3784, -2960,
69    -2208, -1520, -880, 23352, 17560, 14120, 11664, 9752, 8184, 6864, 5712, 4696, 3784, 2960, 2208,
70    1520, 880, 280, -280,
71];
72
73// Quantizer multipliers for 6-bit quantization (64kbps mode)
74const QUANT_MULT_64K: [i32; 64] = [
75    -136, -136, -136, -136, -24808, -21904, -19008, -16704, -14984, -13512, -12280, -11192, -10232,
76    -9360, -8576, -7856, -7192, -6576, -6000, -5456, -4944, -4464, -4008, -3576, -3168, -2776,
77    -2400, -2032, -1688, -1360, -1040, -728, 24808, 21904, 19008, 16704, 14984, 13512, 12280,
78    11192, 10232, 9360, 8576, 7856, 7192, 6576, 6000, 5456, 4944, 4464, 4008, 3576, 3168, 2776,
79    2400, 2032, 1688, 1360, 1040, 728, 432, 136, -432, -136,
80];
81
82impl Bitrate {
83    fn bits_per_sample(&self) -> i32 {
84        match self {
85            Bitrate::Mode1_64000 => 8,
86            Bitrate::Mode2_56000 => 7,
87            Bitrate::Mode3_48000 => 6,
88        }
89    }
90}
91
92/// G.722 ADPCM band state structure used in the codec
93/// Each band (lower and upper) uses an independent state structure
94#[derive(Default)]
95struct G722Band {
96    /// Current signal prediction value (signal estimate)
97    signal_estimate: i32,
98    /// Pole filter output (result from IIR filter part)
99    pole_filter_output: i32,
100    /// Zero filter output (result from FIR filter part)
101    zero_filter_output: i32,
102    /// Reconstructed signal history [current, previous, previous-1]
103    reconstructed_signal: [i32; 3],
104    /// Pole filter coefficients [unused(0), a1, a2]
105    pole_coefficients: [i32; 3],
106    /// Temporary pole filter coefficients [unused(0), a1', a2']
107    pole_coefficients_temp: [i32; 3],
108    /// Partially reconstructed signal history [current, previous, previous-1]
109    partial_reconstructed: [i32; 3],
110    /// Difference signal history [current, previous, ..., previous-5]
111    difference_signal: [i32; 7],
112    /// Zero filter coefficients [unused(0), b1, b2, ..., b6]
113    zero_coefficients: [i32; 7],
114    /// Temporary zero filter coefficients [unused(0), b1', b2', ..., b6']
115    zero_coefficients_temp: [i32; 7],
116    /// Log scale factor (used for quantization and dequantization)
117    log_scale_factor: i32,
118    /// Quantizer step size (used for adaptive quantization)
119    quantizer_step_size: i32,
120}
121
122#[inline(always)]
123fn saturate(amp: i32) -> i32 {
124    amp.clamp(i16::MIN as i32, i16::MAX as i32)
125}
126
127/// Process Block 4 operations for G.722 ADPCM algorithm
128/// This function performs the predictor adaptation and reconstruction steps
129/// as defined in the G.722 standard
130#[inline]
131fn block4(band: &mut G722Band, d: i32) {
132    // Block 4, RECONS - Reconstruct the signal
133    band.difference_signal[0] = d;
134    band.reconstructed_signal[0] = saturate(band.signal_estimate + d);
135
136    // Block 4, PARREC - Partial reconstruction
137    let partial_rec0 = saturate(band.zero_filter_output + d);
138    band.partial_reconstructed[0] = partial_rec0;
139
140    // Block 4, UPPOL2 - Update second predictor coefficient
141    let s0 = partial_rec0 >> 15;
142    let s1 = band.partial_reconstructed[1] >> 15;
143    let s2 = band.partial_reconstructed[2] >> 15;
144
145    let a1_scaled = saturate(band.pole_coefficients[1] << 2);
146
147    let mut a2_update = if s0 == s1 { -a1_scaled } else { a1_scaled };
148    a2_update = a2_update.min(32767);
149
150    let mut a2_adj = a2_update >> 7;
151    a2_adj += if s0 == s2 { 128 } else { -128 };
152    a2_adj += (band.pole_coefficients[2] * 32512) >> 15;
153
154    band.pole_coefficients_temp[2] = a2_adj.clamp(-12288, 12288);
155
156    // Block 4, UPPOL1 - Update first predictor coefficient
157    let sign_factor = if s0 == s1 { 192 } else { -192 };
158    let leakage = (band.pole_coefficients[1] * 32640) >> 15;
159    band.pole_coefficients_temp[1] = saturate(sign_factor + leakage);
160
161    let limit = saturate(15360 - band.pole_coefficients_temp[2]);
162    band.pole_coefficients_temp[1] = band.pole_coefficients_temp[1].clamp(-limit, limit);
163
164    // Block 4, UPZERO - Update zero section (FIR) coefficients
165    let step_size = if d == 0 { 0 } else { 128 };
166    let sd = d >> 15;
167
168    {
169        macro_rules! update_zero {
170            ($i:expr) => {
171                let sz = band.difference_signal[$i] >> 15;
172                let adj = if sz == sd { step_size } else { -step_size };
173                let leakage = (band.zero_coefficients[$i] * 32640) >> 15;
174                band.zero_coefficients_temp[$i] = saturate(adj + leakage);
175            };
176        }
177        update_zero!(1);
178        update_zero!(2);
179        update_zero!(3);
180        update_zero!(4);
181        update_zero!(5);
182        update_zero!(6);
183    }
184
185    // Block 4, DELAYA - Delay updates for filter memory
186    band.difference_signal[6] = band.difference_signal[5];
187    band.difference_signal[5] = band.difference_signal[4];
188    band.difference_signal[4] = band.difference_signal[3];
189    band.difference_signal[3] = band.difference_signal[2];
190    band.difference_signal[2] = band.difference_signal[1];
191    band.difference_signal[1] = d;
192
193    band.zero_coefficients[1] = band.zero_coefficients_temp[1];
194    band.zero_coefficients[2] = band.zero_coefficients_temp[2];
195    band.zero_coefficients[3] = band.zero_coefficients_temp[3];
196    band.zero_coefficients[4] = band.zero_coefficients_temp[4];
197    band.zero_coefficients[5] = band.zero_coefficients_temp[5];
198    band.zero_coefficients[6] = band.zero_coefficients_temp[6];
199
200    band.reconstructed_signal[2] = band.reconstructed_signal[1];
201    band.reconstructed_signal[1] = band.reconstructed_signal[0];
202    band.partial_reconstructed[2] = band.partial_reconstructed[1];
203    band.partial_reconstructed[1] = partial_rec0;
204
205    band.pole_coefficients[1] = band.pole_coefficients_temp[1];
206    band.pole_coefficients[2] = band.pole_coefficients_temp[2];
207
208    // Block 4, FILTEP - Pole section (IIR) filtering
209    let r1_adj = saturate(band.reconstructed_signal[1] << 1);
210    let pole1 = (band.pole_coefficients[1] * r1_adj) >> 15;
211
212    let r2_adj = saturate(band.reconstructed_signal[2] << 1);
213    let pole2 = (band.pole_coefficients[2] * r2_adj) >> 15;
214
215    band.pole_filter_output = saturate(pole1 + pole2);
216
217    // Block 4, FILTEZ - Zero section (FIR) filtering
218    let mut zero_out = (band.zero_coefficients[1] * saturate(band.difference_signal[1] << 1)) >> 15;
219    zero_out += (band.zero_coefficients[2] * saturate(band.difference_signal[2] << 1)) >> 15;
220    zero_out += (band.zero_coefficients[3] * saturate(band.difference_signal[3] << 1)) >> 15;
221    zero_out += (band.zero_coefficients[4] * saturate(band.difference_signal[4] << 1)) >> 15;
222    zero_out += (band.zero_coefficients[5] * saturate(band.difference_signal[5] << 1)) >> 15;
223    zero_out += (band.zero_coefficients[6] * saturate(band.difference_signal[6] << 1)) >> 15;
224
225    band.zero_filter_output = saturate(zero_out);
226
227    // Block 4, PREDIC - Prediction
228    band.signal_estimate = saturate(band.pole_filter_output + band.zero_filter_output);
229}
230
231pub struct G722Encoder {
232    packed: bool,
233    eight_k: bool,
234    bits_per_sample: i32,
235    x: [i32; 24],
236    band: [G722Band; 2],
237    out_buffer: u32,
238    out_bits: i32,
239}
240
241pub struct G722Decoder {
242    packed: bool,
243    eight_k: bool,
244    bits_per_sample: i32,
245    x: [i32; 24],
246    band: [G722Band; 2],
247    in_buffer: u32,
248    in_bits: i32,
249}
250
251impl G722Encoder {
252    pub fn new() -> Self {
253        Self::with_options(Bitrate::Mode1_64000, false, false)
254    }
255
256    /// Creates an encoder with specified bitrate and options
257    pub fn with_options(rate: Bitrate, eight_k: bool, packed: bool) -> Self {
258        let mut encoder = Self {
259            packed,
260            eight_k,
261            bits_per_sample: rate.bits_per_sample(),
262            x: [0; 24],
263            band: [G722Band::default(), G722Band::default()],
264            out_buffer: 0,
265            out_bits: 0,
266        };
267
268        // Initialize band states with correct starting values
269        encoder.band[0].log_scale_factor = 32 << 2; // Initial det value for lower band
270        encoder.band[1].log_scale_factor = 8 << 2; // Initial det value for upper band
271
272        encoder
273    }
274
275    /// Encode 16-bit PCM samples into G.722 format
276    /// This function follows the G.722 standard algorithm exactly
277    fn g722_encode_into(
278        &mut self,
279        amp: &[i16],
280        out: &mut [u8],
281    ) -> Result<usize, CodecError> {
282        // Cursor over `out`. We track a byte position plus a sub-byte bit
283        // buffer used only in packed mode. The cursor returns an error if
284        // `out` cannot accept another byte.
285        struct OutCursor<'a> {
286            buf: &'a mut [u8],
287            byte_pos: usize,
288            bit_buffer: u32,
289            bit_count: i32,
290        }
291        impl<'a> OutCursor<'a> {
292            #[inline]
293            fn push_byte(&mut self, b: u8) -> Result<(), CodecError> {
294                if self.byte_pos >= self.buf.len() {
295                    return Err(CodecError::BufferTooSmall);
296                }
297                self.buf[self.byte_pos] = b;
298                self.byte_pos += 1;
299                Ok(())
300            }
301        }
302
303        let packed = self.packed;
304        let bits_per_sample = self.bits_per_sample;
305        let mut cursor = OutCursor {
306            buf: out,
307            byte_pos: 0,
308            bit_buffer: self.out_buffer,
309            bit_count: self.out_bits,
310        };
311
312        // Helper closure: write one `bits_per_sample`-bit code.
313        let output_code = |code: i32, cursor: &mut OutCursor<'_>| -> Result<(), CodecError> {
314            if packed {
315                cursor.bit_buffer |= (code as u32) << cursor.bit_count;
316                cursor.bit_count += bits_per_sample;
317                if cursor.bit_count >= 8 {
318                    cursor.push_byte((cursor.bit_buffer & 0xFF) as u8)?;
319                    cursor.bit_count -= 8;
320                    cursor.bit_buffer >>= 8;
321                }
322            } else {
323                cursor.push_byte(code as u8)?;
324            }
325            Ok(())
326        };
327
328        let mut input_idx = 0usize;
329
330        if self.eight_k {
331            while input_idx < amp.len() {
332                // 8kHz mode - Just use input directly with scaling
333                let xlow = amp[input_idx] as i32 >> 1;
334                input_idx += 1;
335
336                // 8kHz mode - only low band matters
337                let code = self.encode_low_band(xlow, true);
338                output_code(code, &mut cursor)?;
339            }
340        } else {
341            // Process all input samples in 16kHz mode
342            // Use chunks_exact(2) for better performance and to avoid bound checks
343            let chunks = amp.chunks_exact(2);
344            let rem = chunks.remainder();
345
346            for chunk in chunks {
347                // Shuffle buffer down to make room for new samples
348                self.x.copy_within(2..24, 0);
349
350                // Add new samples to buffer
351                self.x[22] = chunk[0] as i32;
352                self.x[23] = chunk[1] as i32;
353
354                // Apply QMF filter to split input into bands
355                // Unrolled loop for 12 coefficients
356                let mut sumodd = self.x[0] * QMF_FILTER_COEFS[0];
357                sumodd += self.x[2] * QMF_FILTER_COEFS[1];
358                sumodd += self.x[4] * QMF_FILTER_COEFS[2];
359                sumodd += self.x[6] * QMF_FILTER_COEFS[3];
360                sumodd += self.x[8] * QMF_FILTER_COEFS[4];
361                sumodd += self.x[10] * QMF_FILTER_COEFS[5];
362                sumodd += self.x[12] * QMF_FILTER_COEFS[6];
363                sumodd += self.x[14] * QMF_FILTER_COEFS[7];
364                sumodd += self.x[16] * QMF_FILTER_COEFS[8];
365                sumodd += self.x[18] * QMF_FILTER_COEFS[9];
366                sumodd += self.x[20] * QMF_FILTER_COEFS[10];
367                sumodd += self.x[22] * QMF_FILTER_COEFS[11];
368
369                let mut sumeven = self.x[1] * QMF_FILTER_COEFS[11];
370                sumeven += self.x[3] * QMF_FILTER_COEFS[10];
371                sumeven += self.x[5] * QMF_FILTER_COEFS[9];
372                sumeven += self.x[7] * QMF_FILTER_COEFS[8];
373                sumeven += self.x[9] * QMF_FILTER_COEFS[7];
374                sumeven += self.x[11] * QMF_FILTER_COEFS[6];
375                sumeven += self.x[13] * QMF_FILTER_COEFS[5];
376                sumeven += self.x[15] * QMF_FILTER_COEFS[4];
377                sumeven += self.x[17] * QMF_FILTER_COEFS[3];
378                sumeven += self.x[19] * QMF_FILTER_COEFS[2];
379                sumeven += self.x[21] * QMF_FILTER_COEFS[1];
380                sumeven += self.x[23] * QMF_FILTER_COEFS[0];
381
382                // Scale filter outputs to get low and high bands
383                let xlow = (sumeven + sumodd) >> 14;
384                let xhigh = (sumeven - sumodd) >> 14;
385
386                // 16kHz mode - encode both bands
387                let ilow = self.encode_low_band(xlow, false);
388                let ihigh = self.encode_high_band(xhigh);
389                let code = (ihigh << 6 | ilow) >> (8 - self.bits_per_sample);
390
391                // Output the encoded code
392                output_code(code, &mut cursor)?;
393            }
394
395            if !rem.is_empty() {
396                self.x.copy_within(2..24, 0);
397                self.x[22] = rem[0] as i32;
398                self.x[23] = 0;
399                let mut sumodd = self.x[0] * QMF_FILTER_COEFS[0];
400                sumodd += self.x[2] * QMF_FILTER_COEFS[1];
401                sumodd += self.x[4] * QMF_FILTER_COEFS[2];
402                sumodd += self.x[6] * QMF_FILTER_COEFS[3];
403                sumodd += self.x[8] * QMF_FILTER_COEFS[4];
404                sumodd += self.x[10] * QMF_FILTER_COEFS[5];
405                sumodd += self.x[12] * QMF_FILTER_COEFS[6];
406                sumodd += self.x[14] * QMF_FILTER_COEFS[7];
407                sumodd += self.x[16] * QMF_FILTER_COEFS[8];
408                sumodd += self.x[18] * QMF_FILTER_COEFS[9];
409                sumodd += self.x[20] * QMF_FILTER_COEFS[10];
410                sumodd += self.x[22] * QMF_FILTER_COEFS[11];
411
412                let mut sumeven = self.x[1] * QMF_FILTER_COEFS[11];
413                sumeven += self.x[3] * QMF_FILTER_COEFS[10];
414                sumeven += self.x[5] * QMF_FILTER_COEFS[9];
415                sumeven += self.x[7] * QMF_FILTER_COEFS[8];
416                sumeven += self.x[9] * QMF_FILTER_COEFS[7];
417                sumeven += self.x[11] * QMF_FILTER_COEFS[6];
418                sumeven += self.x[13] * QMF_FILTER_COEFS[5];
419                sumeven += self.x[15] * QMF_FILTER_COEFS[4];
420                sumeven += self.x[17] * QMF_FILTER_COEFS[3];
421                sumeven += self.x[19] * QMF_FILTER_COEFS[2];
422                sumeven += self.x[21] * QMF_FILTER_COEFS[1];
423                sumeven += self.x[23] * QMF_FILTER_COEFS[0];
424
425                let xlow = (sumeven + sumodd) >> 14;
426                let xhigh = (sumeven - sumodd) >> 14;
427                let ilow = self.encode_low_band(xlow, false);
428                let ihigh = self.encode_high_band(xhigh);
429                let code = (ihigh << 6 | ilow) >> (8 - self.bits_per_sample);
430                output_code(code, &mut cursor)?;
431            }
432        }
433
434        // Handle any remaining bits in the output buffer
435        if self.packed && cursor.bit_count > 0 {
436            cursor.push_byte((cursor.bit_buffer & 0xFF) as u8)?;
437        }
438
439        // Persist bit buffer state for streaming across calls.
440        self.out_buffer = cursor.bit_buffer;
441        self.out_bits = cursor.bit_count;
442
443        Ok(cursor.byte_pos)
444    }
445
446    /// Encode low band sample and update state
447    /// Returns the encoded low band bits
448    #[inline]
449    fn encode_low_band(&mut self, xlow: i32, is_eight_k: bool) -> i32 {
450        // Block 1L, SUBTRA - Calculate difference signal
451        let el = saturate(xlow - self.band[0].signal_estimate);
452
453        // Block 1L, QUANTL - Quantize difference signal
454        let wd = el.abs().wrapping_sub((el >> 31) & 1);
455
456        // Find quantization interval using linear search (more predictable for audio)
457        let lsf = self.band[0].log_scale_factor;
458        let mut quantization_idx = 1;
459        while quantization_idx < 30 {
460            let decision_level = (QUANT_DECISION_LEVEL[quantization_idx] * lsf) >> 12;
461            if wd < decision_level {
462                break;
463            }
464            quantization_idx += 1;
465        }
466
467        // Select output bits based on sign
468        let ilow = if el < 0 {
469            QUANT_INDEX_NEG[quantization_idx]
470        } else {
471            QUANT_INDEX_POS[quantization_idx]
472        };
473
474        // Block 2L, INVQAL - Inverse quantize for prediction
475        let ril = ilow >> 2;
476        let wd2 = QUANT_MULT_LOW_4BIT[ril as usize];
477        let dlow = (self.band[0].log_scale_factor * wd2) >> 15;
478
479        // Block 3L, LOGSCL - Update scale factor
480        let il4 = LOG_SCALE_FACTOR_MAP[ril as usize];
481        let mut nb = (self.band[0].quantizer_step_size * 127) >> 7;
482        nb += SCALE_FACTOR_ADJUST_LOW[il4 as usize];
483        self.band[0].quantizer_step_size = nb.clamp(0, 18432);
484
485        // Block 3L, SCALEL - Compute new quantizer scale factor
486        let wd1 = self.band[0].quantizer_step_size >> 6 & 31;
487        let wd2 = 8 - (self.band[0].quantizer_step_size >> 11);
488        let wd3 = if wd2 < 0 {
489            INV_LOG_BASE[wd1 as usize] << -wd2
490        } else {
491            INV_LOG_BASE[wd1 as usize] >> wd2
492        };
493        self.band[0].log_scale_factor = wd3 << 2;
494
495        // Apply predictor adaptation (ADPCM core algorithm)
496        block4(&mut self.band[0], dlow);
497
498        // Return appropriate value based on mode
499        if is_eight_k {
500            ((0xc0 | ilow) >> 8) - self.bits_per_sample
501        } else {
502            ilow
503        }
504    }
505
506    /// Encode high band sample and update state
507    /// Returns the encoded high band bits
508    #[inline]
509    fn encode_high_band(&mut self, xhigh: i32) -> i32 {
510        // Block 1H, SUBTRA - Calculate difference signal
511        let eh = saturate(xhigh - self.band[1].signal_estimate);
512
513        // Block 1H, QUANTH - Quantize difference signal
514        let wd = if eh >= 0 { eh } else { -(eh + 1) };
515        let decision_level = (564 * self.band[1].log_scale_factor) >> 12;
516
517        // Determine quantization level for high band (2-bit)
518        let mih = if wd >= decision_level { 2 } else { 1 };
519        let ihigh = if eh < 0 {
520            HIGH_QUANT_INDEX_NEG[mih as usize]
521        } else {
522            HIGH_QUANT_INDEX_POS[mih as usize]
523        };
524
525        // Block 2H, INVQAH - Inverse quantize for prediction
526        let wd2 = QUANT_MULT_HIGH_2BIT[ihigh as usize];
527        let dhigh = (self.band[1].log_scale_factor * wd2) >> 15;
528
529        // Block 3H, LOGSCH - Update scale factor
530        let ih2 = HIGH_LOG_SCALE_MAP[ihigh as usize];
531        let mut nb = (self.band[1].quantizer_step_size * 127) >> 7;
532        nb += SCALE_FACTOR_ADJUST_HIGH[ih2 as usize];
533        self.band[1].quantizer_step_size = nb.clamp(0, 22528);
534
535        // Block 3H, SCALEH - Compute quantizer scale factor
536        let wd1 = self.band[1].quantizer_step_size >> 6 & 31;
537        let wd2 = 10 - (self.band[1].quantizer_step_size >> 11);
538        let wd3 = if wd2 < 0 {
539            INV_LOG_BASE[wd1 as usize] << -wd2
540        } else {
541            INV_LOG_BASE[wd1 as usize] >> wd2
542        };
543        self.band[1].log_scale_factor = wd3 << 2;
544
545        // Apply predictor adaptation (ADPCM core algorithm)
546        block4(&mut self.band[1], dhigh);
547
548        ihigh
549    }
550
551}
552
553impl G722Decoder {
554    pub fn new() -> Self {
555        Self::with_options(Bitrate::Mode1_64000, false, false)
556    }
557
558    pub fn with_options(rate: Bitrate, packed: bool, eight_k: bool) -> Self {
559        Self {
560            packed,
561            eight_k,
562            bits_per_sample: rate.bits_per_sample(),
563            x: Default::default(),
564            band: Default::default(),
565            in_buffer: 0,
566            in_bits: 0,
567        }
568    }
569
570    /// Extracts the next G.722 code from the input data stream
571    #[inline]
572    fn extract_code(&mut self, data: &[u8], idx: &mut usize) -> i32 {
573        if self.packed {
574            // When packed, bits are combined across bytes
575            if self.in_bits < self.bits_per_sample {
576                self.in_buffer |= (data[*idx] as u32) << self.in_bits;
577                *idx += 1;
578                self.in_bits += 8;
579            }
580            let code = (self.in_buffer & ((1 << self.bits_per_sample) - 1) as u32) as i32;
581            self.in_buffer >>= self.bits_per_sample;
582            self.in_bits -= self.bits_per_sample;
583            code
584        } else {
585            // Direct byte-based access when not packed
586            let code = data[*idx] as i32;
587            *idx += 1;
588            code
589        }
590    }
591
592    /// Parses the G.722 code into low-band word and high-band index based on bit rate
593    #[inline]
594    fn parse_code(&self, code: i32) -> (i32, i32, i32) {
595        // Returns (wd1, ihigh, wd2) tuple: low-band word, high-band index, and scaled value
596        match self.bits_per_sample {
597            7 => {
598                // 56 kbit/s mode
599                let wd1 = code & 0x1f;
600                let ihigh = (code >> 5) & 0x3;
601                let wd2 = QUANT_MULT_56K[wd1 as usize];
602                (wd1 >> 1, ihigh, wd2)
603            }
604            6 => {
605                // 48 kbit/s mode
606                let wd1 = code & 0xf;
607                let ihigh = (code >> 4) & 0x3;
608                let wd2 = QUANT_MULT_LOW_4BIT[wd1 as usize];
609                (wd1, ihigh, wd2)
610            }
611            _ => {
612                // 64 kbit/s mode (default)
613                let wd1 = code & 0x3f;
614                let ihigh = (code >> 6) & 0x3;
615                let wd2 = QUANT_MULT_64K[wd1 as usize];
616                (wd1 >> 2, ihigh, wd2)
617            }
618        }
619    }
620
621    /// Process the low band component of the G.722 stream
622    #[inline]
623    fn process_low_band(&mut self, wd1: i32, wd2: i32) -> i32 {
624        // Block 5L, LOW BAND INVQBL - Inverse quantization for low band
625        let dequant = (self.band[0].log_scale_factor * wd2) >> 15;
626
627        // Block 5L, RECONS - Reconstruction of low band signal
628        let rlow = self.band[0].signal_estimate + dequant;
629
630        // Block 6L, LIMIT - Limiting to valid range
631        let rlow = rlow.clamp(-16384, 16383);
632
633        // Block 2L, INVQAL - Inverse adaptive quantizer for prediction
634        let wd2 = QUANT_MULT_LOW_4BIT[wd1 as usize];
635        let dlowt = (self.band[0].log_scale_factor * wd2) >> 15;
636
637        // Block 3L, LOGSCL - Compute log scale factor
638        let wd2 = LOG_SCALE_FACTOR_MAP[wd1 as usize];
639        let mut wd1 = (self.band[0].quantizer_step_size * 127) >> 7;
640        wd1 += SCALE_FACTOR_ADJUST_LOW[wd2 as usize];
641        self.band[0].quantizer_step_size = wd1.clamp(0, 18432);
642
643        // Block 3L, SCALEL - Compute quantizer scale factor
644        let wd1 = (self.band[0].quantizer_step_size >> 6) & 31;
645        let wd2 = 8 - (self.band[0].quantizer_step_size >> 11);
646        let wd3 = if wd2 < 0 {
647            INV_LOG_BASE[wd1 as usize] << -wd2
648        } else {
649            INV_LOG_BASE[wd1 as usize] >> wd2
650        };
651        self.band[0].log_scale_factor = wd3 << 2;
652
653        // Apply predictor adaptation
654        block4(&mut self.band[0], dlowt);
655
656        rlow
657    }
658
659    /// Process the high band component of the G.722 stream
660    #[inline]
661    fn process_high_band(&mut self, ihigh: i32) -> i32 {
662        // Block 2H, INVQAH - Inverse quantizer for high band
663        let wd2 = QUANT_MULT_HIGH_2BIT[ihigh as usize];
664        let dhigh = (self.band[1].log_scale_factor * wd2) >> 15;
665
666        // Block 5H, RECONS - Reconstruction of high band signal
667        let rhigh = dhigh + self.band[1].signal_estimate;
668
669        // Block 6H, LIMIT - Limiting to valid range
670        let rhigh = rhigh.clamp(-16384, 16383);
671
672        // Block 2H, INVQAH - Adaptation logic
673        let wd2 = HIGH_LOG_SCALE_MAP[ihigh as usize];
674        let mut wd1 = (self.band[1].quantizer_step_size * 127) >> 7;
675        wd1 += SCALE_FACTOR_ADJUST_HIGH[wd2 as usize];
676        self.band[1].quantizer_step_size = wd1.clamp(0, 22528);
677
678        // Block 3H, SCALEH - Compute quantizer scale factor
679        let wd1 = (self.band[1].quantizer_step_size >> 6) & 31;
680        let wd2 = 10 - (self.band[1].quantizer_step_size >> 11);
681        let wd3 = if wd2 < 0 {
682            INV_LOG_BASE[wd1 as usize] << -wd2
683        } else {
684            INV_LOG_BASE[wd1 as usize] >> wd2
685        };
686        self.band[1].log_scale_factor = wd3 << 2;
687
688        // Apply predictor adaptation
689        block4(&mut self.band[1], dhigh);
690
691        rhigh
692    }
693
694    /// Apply QMF synthesis filter to combine low and high band signals
695    #[inline]
696    fn apply_qmf_synthesis(&mut self, rlow: i32, rhigh: i32) -> [i16; 2] {
697        // Shift filter state
698        self.x.copy_within(2..24, 0);
699
700        // Set new filter state values
701        self.x[22] = rlow + rhigh;
702        self.x[23] = rlow - rhigh;
703
704        // Apply QMF synthesis filter (unrolled loop for 12 coefficients)
705        let mut xout2 = self.x[0] * QMF_FILTER_COEFS[0];
706        xout2 += self.x[2] * QMF_FILTER_COEFS[1];
707        xout2 += self.x[4] * QMF_FILTER_COEFS[2];
708        xout2 += self.x[6] * QMF_FILTER_COEFS[3];
709        xout2 += self.x[8] * QMF_FILTER_COEFS[4];
710        xout2 += self.x[10] * QMF_FILTER_COEFS[5];
711        xout2 += self.x[12] * QMF_FILTER_COEFS[6];
712        xout2 += self.x[14] * QMF_FILTER_COEFS[7];
713        xout2 += self.x[16] * QMF_FILTER_COEFS[8];
714        xout2 += self.x[18] * QMF_FILTER_COEFS[9];
715        xout2 += self.x[20] * QMF_FILTER_COEFS[10];
716        xout2 += self.x[22] * QMF_FILTER_COEFS[11];
717
718        let mut xout1 = self.x[1] * QMF_FILTER_COEFS[11];
719        xout1 += self.x[3] * QMF_FILTER_COEFS[10];
720        xout1 += self.x[5] * QMF_FILTER_COEFS[9];
721        xout1 += self.x[7] * QMF_FILTER_COEFS[8];
722        xout1 += self.x[9] * QMF_FILTER_COEFS[7];
723        xout1 += self.x[11] * QMF_FILTER_COEFS[6];
724        xout1 += self.x[13] * QMF_FILTER_COEFS[5];
725        xout1 += self.x[15] * QMF_FILTER_COEFS[4];
726        xout1 += self.x[17] * QMF_FILTER_COEFS[3];
727        xout1 += self.x[19] * QMF_FILTER_COEFS[2];
728        xout1 += self.x[21] * QMF_FILTER_COEFS[1];
729        xout1 += self.x[23] * QMF_FILTER_COEFS[0];
730
731        // Return reconstructed samples with proper scaling
732        [saturate(xout1 >> 11) as i16, saturate(xout2 >> 11) as i16]
733    }
734
735    /// Decodes a G.722 frame into the caller-provided buffer.
736    ///
737    /// Returns the number of samples written to `out`. Returns
738    /// [`CodecError::BufferTooSmall`] if `out` cannot accept all decoded
739    /// samples.
740    pub fn decode_frame_into(
741        &mut self,
742        data: &[u8],
743        out: &mut [Sample],
744    ) -> Result<usize, CodecError> {
745        let mut written = 0usize;
746        let mut idx = 0usize;
747
748        if self.eight_k {
749            while idx < data.len() {
750                let code = self.extract_code(data, &mut idx);
751                let (wd1, _, wd2) = self.parse_code(code);
752                let rlow = self.process_low_band(wd1, wd2);
753                if written >= out.len() {
754                    return Err(CodecError::BufferTooSmall);
755                }
756                out[written] = (rlow << 1) as i16;
757                written += 1;
758            }
759        } else {
760            while idx < data.len() {
761                let code = self.extract_code(data, &mut idx);
762                let (wd1, ihigh, wd2) = self.parse_code(code);
763                let rlow = self.process_low_band(wd1, wd2);
764                let rhigh = self.process_high_band(ihigh);
765                let pcm = self.apply_qmf_synthesis(rlow, rhigh);
766                if out.len() < written + 2 {
767                    return Err(CodecError::BufferTooSmall);
768                }
769                out[written] = pcm[0];
770                out[written + 1] = pcm[1];
771                written += 2;
772            }
773        }
774        Ok(written)
775    }
776
777    /// Decodes a G.722 frame into a freshly-allocated `Vec`.
778    ///
779    /// Only available with the `std` feature.
780    #[cfg(feature = "std")]
781    pub fn decode_frame(&mut self, data: &[u8]) -> PcmBuf {
782        let max = self.max_decode_samples(data.len());
783        let mut out = vec![0i16; max];
784        match self.decode_frame_into(data, &mut out) {
785            Ok(n) => {
786                out.truncate(n);
787                out
788            }
789            Err(_) => Vec::new(),
790        }
791    }
792}
793
794impl Default for G722Encoder {
795    fn default() -> Self {
796        Self::new()
797    }
798}
799
800impl Default for G722Decoder {
801    fn default() -> Self {
802        Self::new()
803    }
804}
805
806impl Encoder for G722Encoder {
807    fn encode_into(&mut self, samples: &[Sample], out: &mut [u8]) -> Result<usize, CodecError> {
808        self.g722_encode_into(samples, out)
809    }
810
811    fn max_encode_bytes(&self, n_samples: usize) -> usize {
812        // Non-packed: one byte per 16kHz code. 8kHz mode emits one byte per
813        // sample. Use the larger bound so the caller always allocates enough.
814        if self.eight_k {
815            n_samples + 1
816        } else {
817            n_samples / 2 + 1
818        }
819    }
820
821    fn sample_rate(&self) -> u32 {
822        16000 // G.722 encoding sample rate is 16kHz
823    }
824
825    fn channels(&self) -> u16 {
826        1 // G.722 is mono encoding
827    }
828}
829
830impl Decoder for G722Decoder {
831    fn decode_into(&mut self, data: &[u8], out: &mut [Sample]) -> Result<usize, CodecError> {
832        self.decode_frame_into(data, out)
833    }
834
835    fn max_decode_samples(&self, n_bytes: usize) -> usize {
836        // 16kHz mode: 2 samples per byte. 8kHz mode: 1 sample per byte.
837        // Use the larger bound so callers always size the buffer adequately.
838        if self.eight_k {
839            n_bytes
840        } else {
841            n_bytes * 2
842        }
843    }
844
845    fn sample_rate(&self) -> u32 {
846        16000
847    }
848
849    fn channels(&self) -> u16 {
850        1
851    }
852}