Skip to main content

shine_rs/
quantization.rs

1//! Quantization and rate control for MP3 encoding
2//!
3//! This module implements the quantization loop that controls the
4//! trade-off between audio quality and bitrate by adjusting quantization
5//! step sizes and managing the bit reservoir.
6//!
7//! The implementation strictly follows the shine reference implementation
8//! in ref/shine/src/lib/l3loop.c
9
10use crate::huffman::SHINE_HUFFMAN_TABLE;
11use crate::tables::{SHINE_SCALE_FACT_BAND_INDEX, SHINE_SLEN1_TAB, SHINE_SLEN2_TAB};
12use crate::types::{GrInfo, ShineGlobalConfig, ShinePsyXmin, GRANULE_SIZE};
13use std::f64::consts::LN_2;
14
15/// Constants from shine (matches l3loop.c exactly)
16#[allow(dead_code)] // May be used in future implementations
17const CBLIMIT: usize = 21;
18const SFB_LMAX: usize = 22;
19const EN_TOT_KRIT: i32 = 10;
20const EN_DIF_KRIT: i32 = 100;
21const EN_SCFSI_BAND_KRIT: i32 = 10;
22const XM_SCFSI_BAND_KRIT: i32 = 10;
23/// Multiplication macros matching shine's mult_noarch_gcc.h
24/// These implement fixed-point arithmetic operations
25///
26/// Multiply with rounding and 31-bit right shift (matches shine mulsr)
27#[inline]
28pub fn mulsr(a: i32, b: i32) -> i32 {
29    (((a as i64 * b as i64) + 0x40000000i64) >> 31) as i32
30}
31
32/// Multiply with rounding and 32-bit right shift (matches shine mulr)
33#[inline]
34pub fn mulr(a: i32, b: i32) -> i32 {
35    (((a as i64 * b as i64) + 0x80000000i64) >> 32) as i32
36}
37
38/// Absolute value function (matches shine labs)
39#[inline]
40pub fn labs(x: i32) -> i32 {
41    x.abs()
42}
43
44/// Inner loop: find optimal quantization step size for given scalefactors
45/// Corresponds to shine_inner_loop() in l3loop.c
46///
47/// The code selects the best quantizerStepSize for a particular set
48/// of scalefacs.
49pub fn shine_inner_loop(
50    ix: &mut [i32],
51    max_bits: i32,
52    gr: i32,
53    ch: i32,
54    config: &mut ShineGlobalConfig,
55) -> i32 {
56    let mut bits: i32;
57    let mut _c1bits: i32;
58    let mut bvbits: i32;
59
60    // Following shine's logic exactly:
61    // if (max_bits < 0) cod_info->quantizerStepSize--;
62    if max_bits < 0 {
63        let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
64        cod_info.quantizer_step_size -= 1;
65    }
66
67    // Main quantization loop - following shine's do-while structure exactly
68    loop {
69        // while (quantize(ix, ++cod_info->quantizerStepSize, config) > 8192)
70        //   ; /* within table range? */
71        let mut quantizer_step_size = {
72            let cod_info = &config.side_info.gr[gr as usize].ch[ch as usize].tt;
73            cod_info.quantizer_step_size
74        };
75
76        loop {
77            quantizer_step_size += 1;
78            if quantize(ix, quantizer_step_size, config) <= 8192 {
79                break;
80            }
81        }
82
83        // Update quantizer step size
84        {
85            let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
86            cod_info.quantizer_step_size = quantizer_step_size;
87        }
88
89        // Process with current step size
90        {
91            let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
92            calc_runlen(ix, cod_info); // rzero,count1,big_values
93            bits = count1_bitcount(ix, cod_info); // count1_table selection
94            _c1bits = bits;
95        }
96
97        // Subdivide and select tables - avoid borrowing conflicts by separating operations
98        {
99            let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
100            calc_runlen(ix, cod_info); // rzero,count1,big_values
101            bits = count1_bitcount(ix, cod_info); // count1_table selection
102            _c1bits = bits;
103        }
104
105        // Subdivide and select tables - use temporary variables to avoid borrowing conflicts
106        {
107            let samplerate = config.wave.samplerate;
108            let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
109            subdivide_with_samplerate(cod_info, samplerate);
110        }
111
112        {
113            let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
114            bigv_tab_select(ix, cod_info); // codebook selection
115            bvbits = bigv_bitcount(ix, cod_info); // bit count
116        }
117
118        bits += bvbits;
119
120        if bits <= max_bits {
121            break;
122        }
123    }
124
125    bits
126}
127/// Outer loop: controls masking conditions and computes best scalefac and global gain
128/// Corresponds to shine_outer_loop() in l3loop.c
129///
130/// The outer iteration loop controls the masking conditions
131/// of all scalefactorbands. It computes the best scalefac and
132/// global gain. This module calls the inner iteration loop.
133pub fn shine_outer_loop(
134    max_bits: i32,
135    _l3_xmin: &mut ShinePsyXmin, // the allowed distortion of the scalefactor
136    ix: &mut [i32],              // vector of quantized values ix(0..575)
137    gr: i32,
138    ch: i32,
139    config: &mut ShineGlobalConfig,
140) -> i32 {
141    // Extract samplerate to avoid borrowing conflicts
142    let samplerate = config.wave.samplerate;
143
144    // Direct access to cod_info without cloning - major performance improvement
145    let quantizer_step_size = bin_search_step_size_with_samplerate(
146        max_bits,
147        ix,
148        &mut config.side_info.gr[gr as usize].ch[ch as usize].tt,
149        samplerate,
150        &mut config.l3loop,
151    );
152
153    let part2_length = part2_length(gr, ch, config) as u32;
154    let huff_bits = max_bits - part2_length as i32;
155
156    // Update cod_info with extracted values
157    {
158        let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
159        cod_info.quantizer_step_size = quantizer_step_size;
160        cod_info.part2_length = part2_length;
161    }
162
163    let bits = shine_inner_loop(ix, huff_bits, gr, ch, config);
164
165    // Update final values
166    let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
167    cod_info.part2_3_length = cod_info.part2_length + bits as u32;
168
169    cod_info.part2_3_length as i32
170}
171
172/// Main iteration loop for encoding
173/// Corresponds to shine_iteration_loop() in l3loop.c
174pub fn shine_iteration_loop(config: &mut ShineGlobalConfig) {
175    #[cfg(feature = "diagnostics")]
176    let frame_num = crate::get_current_frame_number();
177
178    let mut l3_xmin = ShinePsyXmin::default();
179    let mut ix: *mut i32;
180
181    // Store xrmax for the first channel and granule for test data collection
182    #[cfg(feature = "diagnostics")]
183    let mut saved_xrmax = 0i32;
184
185    // Process each channel and granule
186    for ch in (0..config.wave.channels).rev() {
187        for gr in 0..config.mpeg.granules_per_frame {
188            // setup pointers
189            ix = config.l3_enc[ch as usize][gr as usize].as_mut_ptr();
190            config.l3loop.xr = config.mdct_freq[ch as usize][gr as usize].as_ptr() as *mut i32;
191
192            // Precalculate the square, abs, and maximum, for use later on.
193            config.l3loop.xrmax = 0;
194            for i in (0..GRANULE_SIZE).rev() {
195                let xr_val = unsafe { *config.l3loop.xr.add(i) };
196                config.l3loop.xrsq[i] = mulsr(xr_val, xr_val);
197                config.l3loop.xrabs[i] = labs(xr_val);
198                if config.l3loop.xrabs[i] > config.l3loop.xrmax {
199                    config.l3loop.xrmax = config.l3loop.xrabs[i];
200                }
201            }
202
203            // Set sfb_lmax and calculate xmin
204            {
205                let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
206                cod_info.sfb_lmax = (SFB_LMAX - 1) as u32; // gr_deco
207                calc_xmin(&config.ratio, cod_info, &mut l3_xmin, gr, ch);
208            }
209
210            if config.mpeg.version == 3 {
211                // MPEG_I = 3
212                // MPEG_I - handle borrowing carefully by cloning l3_xmin temporarily
213                calc_scfsi(&mut l3_xmin, ch, gr, config);
214            }
215
216            // calculation of number of available bit( per granule )
217            let pe_value = config.pe[ch as usize][gr as usize];
218            let max_bits = crate::reservoir::shine_max_reservoir_bits(&pe_value, config);
219
220            // Debug logging for algorithm verification
221            #[cfg(feature = "diagnostics")]
222            {
223                let debug_frames = std::env::var("RUST_MP3_DEBUG_FRAMES")
224                    .unwrap_or_else(|_| "6".to_string())
225                    .parse::<i32>()
226                    .unwrap_or(6);
227                if frame_num <= debug_frames && ch == 0 && gr == 0 {
228                    // Save xrmax for the first channel and granule
229                    saved_xrmax = config.l3loop.xrmax;
230                }
231            }
232
233            // reset of iteration variables
234            config.scalefactor.l[gr as usize][ch as usize].fill(0);
235            config.scalefactor.s[gr as usize][ch as usize]
236                .iter_mut()
237                .for_each(|row| row.fill(0));
238
239            // Reset cod_info values
240            {
241                let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
242                cod_info.slen = [0; 4];
243
244                cod_info.part2_3_length = 0;
245                cod_info.big_values = 0;
246                cod_info.count1 = 0;
247                cod_info.scalefac_compress = 0;
248                cod_info.table_select[0] = 0;
249                cod_info.table_select[1] = 0;
250                cod_info.table_select[2] = 0;
251                cod_info.region0_count = 0;
252                cod_info.region1_count = 0;
253                cod_info.part2_length = 0;
254                cod_info.preflag = 0;
255                cod_info.scalefac_scale = 0;
256                cod_info.count1table_select = 0;
257            }
258
259            // all spectral values zero ?
260            let _part2_3_length = if config.l3loop.xrmax != 0 {
261                let ix_slice = unsafe { std::slice::from_raw_parts_mut(ix, GRANULE_SIZE) };
262                let length =
263                    shine_outer_loop(max_bits, &mut l3_xmin, ix_slice, gr, ch, config) as u32;
264
265                // Update part2_3_length after outer loop
266                let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
267                cod_info.part2_3_length = length;
268                length
269            } else {
270                0u32
271            };
272
273            // Adjust reservoir and set global gain
274            {
275                let quantizer_step_size = {
276                    let cod_info = &config.side_info.gr[gr as usize].ch[ch as usize].tt;
277                    cod_info.quantizer_step_size
278                };
279
280                // Call reservoir adjust first (matches Shine order) - extract values to avoid borrowing conflicts
281                let part2_3_length = {
282                    let cod_info = &config.side_info.gr[gr as usize].ch[ch as usize].tt;
283                    cod_info.part2_3_length
284                };
285                let mean_bits = config.mean_bits;
286                let channels = config.wave.channels;
287
288                // Manual reservoir adjustment to avoid borrowing conflicts
289                config.resv_size += (mean_bits / channels) - part2_3_length as i32;
290
291                // Set global gain AFTER reservoir adjustment (matches Shine)
292                let cod_info = &mut config.side_info.gr[gr as usize].ch[ch as usize].tt;
293                cod_info.global_gain = (quantizer_step_size + 210) as u32;
294
295                // Debug output for verification (but don't record data here)
296                #[cfg(feature = "diagnostics")]
297                {
298                    let debug_frames = std::env::var("RUST_MP3_DEBUG_FRAMES")
299                        .unwrap_or_else(|_| "6".to_string())
300                        .parse::<i32>()
301                        .unwrap_or(6);
302                    if frame_num <= debug_frames && ch == 0 && gr == 0 {
303                        // Silent - no debug output
304                    }
305                }
306
307                // Suppress unused variable warning in release mode
308                #[cfg(not(any(debug_assertions, feature = "diagnostics")))]
309                let _ = _part2_3_length;
310            }
311        } // for gr
312    } // for ch
313
314    crate::reservoir::shine_resv_frame_end(config);
315
316    // Record quantization data AFTER shine_resv_frame_end (matches Shine final output)
317    #[cfg(feature = "diagnostics")]
318    {
319        let debug_frames = std::env::var("RUST_MP3_DEBUG_FRAMES")
320            .unwrap_or_else(|_| "6".to_string())
321            .parse::<i32>()
322            .unwrap_or(6);
323
324        if frame_num <= debug_frames {
325            // Record data for the first channel and granule (ch=0, gr=0) after all adjustments
326            let cod_info = &config.side_info.gr[0].ch[0].tt;
327            let max_bits = crate::reservoir::shine_max_reservoir_bits(&config.pe[0][0], config);
328
329            crate::diagnostics::record_quant_data(
330                saved_xrmax, // Use the saved xrmax from ch=0, gr=0
331                max_bits,
332                cod_info.part2_3_length, // Final value after all reservoir adjustments
333                cod_info.quantizer_step_size,
334                cod_info.global_gain,
335            );
336        }
337    }
338}
339/// Calculate scale factor selection information (scfsi)
340/// Corresponds to calc_scfsi() in l3loop.c
341fn calc_scfsi(l3_xmin: &mut ShinePsyXmin, ch: i32, gr: i32, config: &mut ShineGlobalConfig) {
342    let l3_side = &mut config.side_info;
343    // This is the scfsi_band table from 2.4.2.7 of the IS
344    const SCFSI_BAND_LONG: [i32; 5] = [0, 6, 11, 16, 21];
345
346    let mut condition = 0;
347    let mut _temp: i32;
348
349    let samplerate_index = match config.wave.samplerate {
350        44100 => 0,
351        48000 => 1,
352        32000 => 2,
353        22050 => 3,
354        24000 => 4,
355        16000 => 5,
356        11025 => 6,
357        12000 => 7,
358        8000 => 8,
359        _ => 0,
360    };
361
362    let scalefac_band_long = &SHINE_SCALE_FACT_BAND_INDEX[samplerate_index];
363
364    config.l3loop.xrmaxl[gr as usize] = config.l3loop.xrmax;
365
366    // the total energy of the granule
367    let temp = (0..GRANULE_SIZE)
368        .rev()
369        .fold(0, |acc, i| acc + (config.l3loop.xrsq[i] >> 10));
370
371    config.l3loop.en_tot[gr as usize] = if temp != 0 {
372        ((temp as f64 * 4.768371584e-7).ln() / LN_2) as i32 // 1024 / 0x7fffffff
373    } else {
374        0
375    };
376
377    // the energy of each scalefactor band, en
378    // the allowed distortion of each scalefactor band, xm
379    for sfb in (0..21).rev() {
380        let start = scalefac_band_long[sfb] as usize;
381        let end = scalefac_band_long[sfb + 1] as usize;
382
383        let temp = (start..end)
384            .filter(|&i| i < GRANULE_SIZE)
385            .fold(0, |acc, i| acc + (config.l3loop.xrsq[i] >> 10));
386
387        config.l3loop.en[gr as usize][sfb] = if temp != 0 {
388            ((temp as f64 * 4.768371584e-7).ln() / LN_2) as i32
389        } else {
390            0
391        };
392
393        if l3_xmin.l[gr as usize][ch as usize][sfb] != 0.0 {
394            config.l3loop.xm[gr as usize][sfb] =
395                (l3_xmin.l[gr as usize][ch as usize][sfb].ln() / LN_2) as i32;
396        } else {
397            config.l3loop.xm[gr as usize][sfb] = 0;
398        }
399    }
400
401    if gr == 1 {
402        for gr2 in (0..2).rev() {
403            // The spectral values are not all zero
404            if config.l3loop.xrmaxl[gr2] != 0 {
405                condition += 1;
406            }
407            condition += 1;
408        }
409        if (config.l3loop.en_tot[0] - config.l3loop.en_tot[1]).abs() < EN_TOT_KRIT {
410            condition += 1;
411        }
412        let mut tp = 0;
413        for sfb in (0..21).rev() {
414            tp += (config.l3loop.en[0][sfb] - config.l3loop.en[1][sfb]).abs();
415        }
416        if tp < EN_DIF_KRIT {
417            condition += 1;
418        }
419
420        if condition == 6 {
421            for scfsi_band in 0..4 {
422                let mut sum0 = 0;
423                let mut sum1 = 0;
424                l3_side.scfsi[ch as usize][scfsi_band] = 0;
425                let start = SCFSI_BAND_LONG[scfsi_band] as usize;
426                let end = SCFSI_BAND_LONG[scfsi_band + 1] as usize;
427                for sfb in start..end {
428                    sum0 += (config.l3loop.en[0][sfb] - config.l3loop.en[1][sfb]).abs();
429                    sum1 += (config.l3loop.xm[0][sfb] - config.l3loop.xm[1][sfb]).abs();
430                }
431
432                if sum0 < EN_SCFSI_BAND_KRIT && sum1 < XM_SCFSI_BAND_KRIT {
433                    l3_side.scfsi[ch as usize][scfsi_band] = 1;
434                } else {
435                    l3_side.scfsi[ch as usize][scfsi_band] = 0;
436                }
437            }
438        } else {
439            for scfsi_band in 0..4 {
440                l3_side.scfsi[ch as usize][scfsi_band] = 0;
441            }
442        }
443    }
444}
445
446/// Calculate part2 length (scalefactors)
447/// Corresponds to part2_length() in l3loop.c
448pub fn part2_length(gr: i32, ch: i32, config: &mut ShineGlobalConfig) -> i32 {
449    let mut bits = 0;
450    let gi = &config.side_info.gr[gr as usize].ch[ch as usize].tt;
451
452    let slen1 = SHINE_SLEN1_TAB[gi.scalefac_compress as usize % SHINE_SLEN1_TAB.len()];
453    let slen2 = SHINE_SLEN2_TAB[gi.scalefac_compress as usize % SHINE_SLEN2_TAB.len()];
454
455    if gr == 0 || config.side_info.scfsi[ch as usize][0] == 0 {
456        bits += 6 * slen1;
457    }
458
459    if gr == 0 || config.side_info.scfsi[ch as usize][1] == 0 {
460        bits += 5 * slen1;
461    }
462
463    if gr == 0 || config.side_info.scfsi[ch as usize][2] == 0 {
464        bits += 5 * slen2;
465    }
466
467    if gr == 0 || config.side_info.scfsi[ch as usize][3] == 0 {
468        bits += 5 * slen2;
469    }
470
471    bits
472}
473
474/// Calculate allowed distortion for each scalefactor band
475/// Corresponds to calc_xmin() in l3loop.c
476fn calc_xmin(
477    _ratio: &crate::types::ShinePsyRatio,
478    cod_info: &mut GrInfo,
479    l3_xmin: &mut ShinePsyXmin,
480    gr: i32,
481    ch: i32,
482) {
483    for sfb in (0..cod_info.sfb_lmax as usize).rev() {
484        // note. xmin will always be zero with no psychoacoustic model
485        l3_xmin.l[gr as usize][ch as usize][sfb] = 0.0;
486    }
487}
488
489/// Initialize quantization loop tables
490/// Corresponds to shine_loop_initialise() in l3loop.c
491pub fn shine_loop_initialise(config: &mut ShineGlobalConfig) {
492    // quantize: stepsize conversion, fourth root of 2 table.
493    // The table is inverted (negative power) from the equation given
494    // in the spec because it is quicker to do x*y than x/y.
495    // The 0.5 is for rounding.
496    (0..128).rev().for_each(|i| {
497        config.l3loop.steptab[i] = (2.0_f64).powf((127 - i as i32) as f64 / 4.0);
498        config.l3loop.steptabi[i] = if (config.l3loop.steptab[i] * 2.0) > 0x7fffffff as f64 {
499            0x7fffffff
500        } else {
501            // The table is multiplied by 2 to give an extra bit of accuracy.
502            // In quantize, the long multiply does not shift its result left one
503            // bit to compensate.
504            (config.l3loop.steptab[i] * 2.0 + 0.5) as i32
505        };
506    });
507
508    // quantize: vector conversion, three quarter power table.
509    // The 0.5 is for rounding, the .0946 comes from the spec.
510    (0..10000).rev().for_each(|i| {
511        config.l3loop.int2idx[i] =
512            ((i as f64).sqrt().sqrt() * (i as f64).sqrt() - 0.0946 + 0.5) as i32;
513    });
514}
515/// Quantize MDCT coefficients
516/// Corresponds to quantize() in l3loop.c
517pub fn quantize(ix: &mut [i32], stepsize: i32, config: &mut ShineGlobalConfig) -> i32 {
518    quantize_with_l3loop(ix, stepsize, &mut config.l3loop)
519}
520
521/// Helper function to avoid borrowing conflicts
522pub fn quantize_with_l3loop(
523    ix: &mut [i32],
524    stepsize: i32,
525    l3loop: &mut crate::types::L3Loop,
526) -> i32 {
527    let mut max = 0;
528    let mut scale: f64;
529    let mut dbl: f64;
530
531    let scalei = l3loop.steptabi[(stepsize + 127).clamp(0, 127) as usize]; // 2**(-stepsize/4)
532
533    // a quick check to see if ixmax will be less than 8192
534    // this speeds up the early calls to bin_search_StepSize
535    if mulr(l3loop.xrmax, scalei) > 165140 {
536        // 8192**(4/3)
537        max = 16384; // no point in continuing, stepsize not big enough
538    } else {
539        for (i, ix_val) in ix.iter_mut().enumerate().take(GRANULE_SIZE) {
540            // This calculation is very sensitive. The multiply must round its
541            // result or bad things happen to the quality.
542            let ln = mulr(labs(unsafe { *l3loop.xr.add(i) }), scalei);
543
544            if ln < 10000 {
545                // ln < 10000 catches most values
546                *ix_val = l3loop.int2idx[ln as usize]; // quick look up method
547            } else {
548                // outside table range so have to do it using floats
549                scale = l3loop.steptab[(stepsize + 127).clamp(0, 127) as usize]; // 2**(-stepsize/4)
550                dbl = (l3loop.xrabs[i] as f64) * scale * 4.656612875e-10; // 0x7fffffff
551                *ix_val = (dbl.sqrt().sqrt() * dbl.sqrt()) as i32; // dbl**(3/4)
552            }
553
554            // calculate ixmax while we're here
555            // note. ix cannot be negative
556            if max < *ix_val {
557                max = *ix_val;
558            }
559        }
560    }
561
562    max
563}
564
565/// Calculate maximum value in range
566#[inline]
567pub fn ix_max(ix: &[i32], begin: u32, end: u32) -> i32 {
568    let start = begin as usize;
569    let end = (end as usize).min(GRANULE_SIZE);
570
571    ix[start..end].iter().max().copied().unwrap_or(0)
572}
573
574/// Calculate run length encoding information
575/// Corresponds to calc_runlen() in l3loop.c
576pub fn calc_runlen(ix: &mut [i32], cod_info: &mut GrInfo) {
577    let mut i = GRANULE_SIZE;
578    let mut _rzero = 0;
579
580    // Count trailing zero pairs
581    while i > 1 {
582        i -= 2;
583        if ix[i] == 0 && ix[i + 1] == 0 {
584            _rzero += 1;
585        } else {
586            i += 2;
587            break;
588        }
589    }
590
591    cod_info.count1 = 0;
592    while i > 3 {
593        i -= 4;
594        if ix[i] <= 1 && ix[i + 1] <= 1 && ix[i + 2] <= 1 && ix[i + 3] <= 1 {
595            cod_info.count1 += 1;
596        } else {
597            i += 4;
598            break;
599        }
600    }
601
602    cod_info.big_values = (i >> 1) as u32;
603}
604
605/// Count bits for count1 region
606/// Corresponds to count1_bitcount() in l3loop.c
607pub fn count1_bitcount(ix: &[i32], cod_info: &mut GrInfo) -> i32 {
608    let mut sum0 = 0;
609    let mut sum1 = 0;
610
611    let mut i = (cod_info.big_values << 1) as usize;
612    for _k in 0..cod_info.count1 {
613        if i + 3 >= GRANULE_SIZE {
614            break;
615        }
616
617        let v = ix[i];
618        let w = ix[i + 1];
619        let x = ix[i + 2];
620        let y = ix[i + 3];
621
622        let p = (v + (w << 1) + (x << 2) + (y << 3)) as usize;
623
624        let mut signbits = 0;
625        if v != 0 {
626            signbits += 1;
627        }
628        if w != 0 {
629            signbits += 1;
630        }
631        if x != 0 {
632            signbits += 1;
633        }
634        if y != 0 {
635            signbits += 1;
636        }
637
638        sum0 += signbits;
639        sum1 += signbits;
640
641        // Use huffman tables 32 and 33 for count1 (matches shine exactly)
642        if let Some(hlen) = SHINE_HUFFMAN_TABLE[32].hlen {
643            if p < hlen.len() {
644                sum0 += hlen[p] as i32;
645            }
646        } else {
647            // WARNING: This branch doesn't exist in shine - added for safety
648            log::warn!("Missing hlen table for Huffman table 32");
649        }
650
651        if let Some(hlen) = SHINE_HUFFMAN_TABLE[33].hlen {
652            if p < hlen.len() {
653                sum1 += hlen[p] as i32;
654            }
655        } else {
656            // WARNING: This branch doesn't exist in shine - added for safety
657            log::warn!("Missing hlen table for Huffman table 33");
658        }
659
660        i += 4;
661    }
662
663    if sum0 < sum1 {
664        cod_info.count1table_select = 0;
665        sum0
666    } else {
667        cod_info.count1table_select = 1;
668        sum1
669    }
670}
671
672/// Subdivide big values region into regions for different Huffman tables
673/// Corresponds to subdivide() in l3loop.c
674pub fn subdivide(cod_info: &mut GrInfo, config: &mut ShineGlobalConfig) {
675    subdivide_with_samplerate(cod_info, config.wave.samplerate);
676}
677
678/// Helper function to subdivide without borrowing conflicts
679pub fn subdivide_with_samplerate(cod_info: &mut GrInfo, samplerate: i32) {
680    // Subdivision table from shine (matches exactly)
681    const SUBDV_TABLE: [(u32, u32); 23] = [
682        (0, 0), // 0 bands
683        (0, 0), // 1 bands
684        (0, 0), // 2 bands
685        (0, 0), // 3 bands
686        (0, 0), // 4 bands
687        (0, 1), // 5 bands
688        (1, 1), // 6 bands
689        (1, 1), // 7 bands
690        (1, 2), // 8 bands
691        (2, 2), // 9 bands
692        (2, 3), // 10 bands
693        (2, 3), // 11 bands
694        (3, 4), // 12 bands
695        (3, 4), // 13 bands
696        (3, 4), // 14 bands
697        (4, 5), // 15 bands
698        (4, 5), // 16 bands
699        (4, 6), // 17 bands
700        (5, 6), // 18 bands
701        (5, 6), // 19 bands
702        (5, 7), // 20 bands
703        (6, 7), // 21 bands
704        (6, 7), // 22 bands
705    ];
706
707    if cod_info.big_values == 0 {
708        // no big_values region
709        cod_info.region0_count = 0;
710        cod_info.region1_count = 0;
711    } else {
712        let samplerate_index = match samplerate {
713            44100 => 0,
714            48000 => 1,
715            32000 => 2,
716            22050 => 3,
717            24000 => 4,
718            16000 => 5,
719            11025 => 6,
720            12000 => 7,
721            8000 => 8,
722            _ => 0,
723        };
724        let scalefac_band_long = &SHINE_SCALE_FACT_BAND_INDEX[samplerate_index];
725
726        let bigvalues_region = 2 * cod_info.big_values;
727
728        // Calculate scfb_anz
729        let mut scfb_anz = 0;
730        while (scfb_anz < 22) && (scalefac_band_long[scfb_anz] < bigvalues_region as i32) {
731            scfb_anz += 1;
732        }
733
734        let mut thiscount = SUBDV_TABLE[scfb_anz].0;
735        while thiscount > 0 {
736            if scalefac_band_long[thiscount as usize + 1] <= bigvalues_region as i32 {
737                break;
738            }
739            thiscount -= 1;
740        }
741        cod_info.region0_count = thiscount;
742        cod_info.address1 = scalefac_band_long[thiscount as usize + 1] as u32;
743
744        let mut thiscount = SUBDV_TABLE[scfb_anz].1;
745        while thiscount > 0 {
746            let idx = (cod_info.region0_count + 1 + thiscount) as usize;
747            if idx < 22 && scalefac_band_long[idx + 1] <= bigvalues_region as i32 {
748                break;
749            }
750            thiscount -= 1;
751        }
752        cod_info.region1_count = thiscount;
753        let idx = (cod_info.region0_count + 1 + thiscount) as usize;
754        if idx + 1 < 22 {
755            cod_info.address2 = scalefac_band_long[idx + 1] as u32;
756        } else {
757            cod_info.address2 = bigvalues_region;
758        }
759
760        cod_info.address3 = bigvalues_region;
761    }
762}
763
764/// Select Huffman code tables for bigvalues regions
765/// Corresponds to bigv_tab_select() in l3loop.c
766pub fn bigv_tab_select(ix: &[i32], cod_info: &mut GrInfo) {
767    cod_info.table_select[0] = 0;
768    cod_info.table_select[1] = 0;
769    cod_info.table_select[2] = 0;
770
771    if cod_info.address1 > 0 {
772        cod_info.table_select[0] = new_choose_table(ix, 0, cod_info.address1);
773    }
774
775    if cod_info.address2 > cod_info.address1 {
776        cod_info.table_select[1] = new_choose_table(ix, cod_info.address1, cod_info.address2);
777    }
778
779    if (cod_info.big_values << 1) > cod_info.address2 {
780        cod_info.table_select[2] =
781            new_choose_table(ix, cod_info.address2, cod_info.big_values << 1);
782    }
783}
784
785/// Choose the Huffman table that will encode ix[begin..end] with the fewest bits
786/// Corresponds to new_choose_table() in l3loop.c
787fn new_choose_table(ix: &[i32], begin: u32, end: u32) -> u32 {
788    let max = ix_max(ix, begin, end);
789    if max == 0 {
790        return 0;
791    }
792
793    let mut choice = [0u32; 2];
794    let mut sum = [0i32; 2];
795
796    if max < 15 {
797        // try tables with no linbits
798        choice[0] = (0..14)
799            .rev()
800            .find(|&i| {
801                SHINE_HUFFMAN_TABLE
802                    .get(i)
803                    .is_some_and(|table| table.xlen > max as u32)
804            })
805            .unwrap_or(0) as u32;
806
807        sum[0] = count_bit(ix, begin, end, choice[0]);
808
809        match choice[0] {
810            2 => {
811                sum[1] = count_bit(ix, begin, end, 3);
812                if sum[1] <= sum[0] {
813                    choice[0] = 3;
814                }
815            }
816            5 => {
817                sum[1] = count_bit(ix, begin, end, 6);
818                if sum[1] <= sum[0] {
819                    choice[0] = 6;
820                }
821            }
822            7 => {
823                sum[1] = count_bit(ix, begin, end, 8);
824                if sum[1] <= sum[0] {
825                    choice[0] = 8;
826                    sum[0] = sum[1];
827                }
828                sum[1] = count_bit(ix, begin, end, 9);
829                if sum[1] <= sum[0] {
830                    choice[0] = 9;
831                }
832            }
833            10 => {
834                sum[1] = count_bit(ix, begin, end, 11);
835                if sum[1] <= sum[0] {
836                    choice[0] = 11;
837                    sum[0] = sum[1];
838                }
839                sum[1] = count_bit(ix, begin, end, 12);
840                if sum[1] <= sum[0] {
841                    choice[0] = 12;
842                }
843            }
844            13 => {
845                sum[1] = count_bit(ix, begin, end, 15);
846                if sum[1] <= sum[0] {
847                    choice[0] = 15;
848                }
849            }
850            _ => {}
851        }
852    } else {
853        // try tables with linbits
854        let max_linbits = max - 15;
855
856        choice[0] = (15..24)
857            .find(|&i| {
858                SHINE_HUFFMAN_TABLE
859                    .get(i)
860                    .is_some_and(|table| table.linmax >= max_linbits as u32)
861            })
862            .unwrap_or(15) as u32;
863
864        choice[1] = (24..32)
865            .find(|&i| {
866                SHINE_HUFFMAN_TABLE
867                    .get(i)
868                    .is_some_and(|table| table.linmax >= max_linbits as u32)
869            })
870            .unwrap_or(24) as u32;
871
872        sum[0] = count_bit(ix, begin, end, choice[0]);
873        sum[1] = count_bit(ix, begin, end, choice[1]);
874        if sum[1] < sum[0] {
875            choice[0] = choice[1];
876        }
877    }
878
879    choice[0]
880}
881
882/// Count the number of bits necessary to code the bigvalues region
883/// Corresponds to bigv_bitcount() in l3loop.c
884fn bigv_bitcount(ix: &[i32], gi: &GrInfo) -> i32 {
885    let mut bits = 0;
886
887    if gi.table_select[0] != 0 {
888        bits += count_bit(ix, 0, gi.address1, gi.table_select[0]);
889    }
890    if gi.table_select[1] != 0 {
891        bits += count_bit(ix, gi.address1, gi.address2, gi.table_select[1]);
892    }
893    if gi.table_select[2] != 0 {
894        bits += count_bit(ix, gi.address2, gi.address3, gi.table_select[2]);
895    }
896
897    bits
898}
899
900/// Count the number of bits necessary to code the subregion
901/// Corresponds to count_bit() in l3loop.c
902#[inline]
903pub fn count_bit(ix: &[i32], start: u32, end: u32, table: u32) -> i32 {
904    if table == 0 {
905        return 0;
906    }
907
908    let table_idx = table as usize;
909    if table_idx >= SHINE_HUFFMAN_TABLE.len() {
910        return 0;
911    }
912
913    let h = match SHINE_HUFFMAN_TABLE.get(table_idx) {
914        Some(table) => table,
915        None => return 0,
916    };
917
918    let mut sum = 0;
919    let ylen = h.ylen;
920    let linbits = h.linbits;
921
922    if table > 15 {
923        // ESC-table is used
924        let mut i = start as usize;
925        while i < end as usize && i + 1 < GRANULE_SIZE {
926            let mut x = ix[i];
927            let mut y = ix[i + 1];
928
929            if x > 14 {
930                x = 15;
931                sum += linbits as i32;
932            }
933            if y > 14 {
934                y = 15;
935                sum += linbits as i32;
936            }
937
938            let idx = (x as u32 * ylen + y as u32) as usize;
939            // WARNING: Added safety check - shine assumes hlen is always valid
940            if let Some(hlen) = h.hlen {
941                if idx < hlen.len() {
942                    sum += hlen[idx] as i32;
943                }
944            } else {
945                // WARNING: This branch doesn't exist in shine - added for safety
946                log::warn!("Missing hlen table for Huffman table {}", table_idx);
947            }
948
949            if x != 0 {
950                sum += 1;
951            }
952            if y != 0 {
953                sum += 1;
954            }
955
956            i += 2;
957        }
958    } else {
959        // No ESC-words
960        let mut i = start as usize;
961        while i < end as usize && i + 1 < GRANULE_SIZE {
962            let x = ix[i];
963            let y = ix[i + 1];
964
965            let idx = (x as u32 * ylen + y as u32) as usize;
966            // WARNING: Added safety check - shine assumes hlen is always valid
967            if let Some(hlen) = h.hlen {
968                if idx < hlen.len() {
969                    sum += hlen[idx] as i32;
970                }
971            } else {
972                // WARNING: This branch doesn't exist in shine - added for safety
973                log::warn!("Missing hlen table for Huffman table {}", table_idx);
974            }
975
976            if x != 0 {
977                sum += 1;
978            }
979            if y != 0 {
980                sum += 1;
981            }
982
983            i += 2;
984        }
985    }
986
987    sum
988}
989
990/// Binary search for optimal quantizer step size
991/// Corresponds to bin_search_StepSize() in l3loop.c
992fn bin_search_step_size_with_samplerate(
993    desired_rate: i32,
994    ix: &mut [i32],
995    cod_info: &mut GrInfo,
996    samplerate: i32,
997    l3loop: &mut crate::types::L3Loop,
998) -> i32 {
999    let mut next = -120;
1000    let mut count = 120;
1001
1002    loop {
1003        let half = count / 2;
1004
1005        let bit = if quantize_with_l3loop(ix, next + half, l3loop) > 8192 {
1006            100000 // fail
1007        } else {
1008            calc_runlen(ix, cod_info); // rzero,count1,big_values
1009            let mut bit = count1_bitcount(ix, cod_info); // count1_table selection
1010            subdivide_with_samplerate(cod_info, samplerate); // bigvalues sfb division
1011            bigv_tab_select(ix, cod_info); // codebook selection
1012            bit += bigv_bitcount(ix, cod_info); // bit count
1013            bit
1014        };
1015
1016        if bit < desired_rate {
1017            count = half;
1018        } else {
1019            next += half;
1020            count -= half;
1021        }
1022
1023        if count <= 1 {
1024            break;
1025        }
1026    }
1027
1028    next
1029}