1use alloc::vec;
14use alloc::vec::Vec;
15
16use super::bands::encode::quant_all_bands_enc;
17use super::bands::haar1;
18use super::decoder::{COMB_GAINS, TF_SELECT_TABLE};
19use super::energy::EnergyState;
20use super::laplace::ec_laplace_encode;
21use super::mdct::MdctLookup;
22use super::modes::{BETA_COEF, BETA_INTRA, E_MEANS, E_PROB_MODEL, EBANDS, LOG_N, MAX_FINE_BITS, NB_EBANDS, PRED_COEF};
23use super::pitch::{COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, pitch_downsample, pitch_search, remove_doubling};
24use super::rate::{AllocEc, BITRES, compute_allocation, init_caps};
25use super::tables::WINDOW120;
26use super::vq::Spread;
27use crate::range::RangeEncoder;
28
29const SHORT_MDCT_SIZE: usize = 120;
31const OVERLAP: usize = 120;
33const PREEMPH_COEF: f32 = 0.850_006_1;
35const SPREAD_ICDF: [u8; 4] = [25, 23, 2, 0];
37const TRIM_ICDF: [u8; 11] = [126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0];
39const TAPSET_ICDF: [u8; 3] = [2, 1, 0];
41const INTENSITY_THRESHOLDS: [f32; 21] = [
43 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 16.0, 24.0, 36.0, 44.0, 50.0, 56.0, 62.0, 67.0, 72.0, 79.0, 88.0, 106.0,
44 134.0,
45];
46const INTENSITY_HYSTERESIS: [f32; 21] = [
47 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 4.0, 5.0, 6.0, 8.0, 8.0,
48];
49
50pub struct CeltEncoder {
52 channels: usize,
54 preemph_mem: [f32; 2],
56 in_mem: [[f32; OVERLAP]; 2],
58 energy: EnergyState,
61 energy_error: [[f32; NB_EBANDS]; 2],
64 frames: u64,
66 consec_transient: u32,
69 last_transient: bool,
71 tonal_average: i32,
74 spread_decision: i32,
76 intensity: usize,
79 target_bitrate: Option<u32>,
81 last_coded_bands: usize,
84 prefilter_mem: [Vec<f32>; 2],
87 prefilter_period: usize,
90 prefilter_gain: f32,
91 prefilter_tapset: usize,
92 last_pitch: usize,
95 last_pitch_gain: f32,
96 final_range: u32,
98 mdct: MdctLookup,
99 scratch_inputs: Vec<f32>,
103 scratch_freq: Vec<f32>,
104 scratch_pre: [Vec<f32>; 2],
106 complexity: u8,
110}
111
112impl Default for CeltEncoder {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118impl CeltEncoder {
119 #[must_use]
121 pub fn new() -> Self {
122 Self::with_channels(1)
123 }
124
125 #[must_use]
131 pub fn with_channels(channels: usize) -> Self {
132 assert!(channels == 1 || channels == 2, "channels must be 1 or 2");
133 CeltEncoder {
134 channels,
135 preemph_mem: [0.0; 2],
136 in_mem: [[0.0; OVERLAP]; 2],
137 energy: EnergyState::default(),
138 energy_error: [[0.0; NB_EBANDS]; 2],
139 frames: 0,
140 consec_transient: 0,
141 last_transient: false,
142 tonal_average: 256,
143 spread_decision: Spread::Normal as i32,
144 intensity: 0,
145 target_bitrate: None,
146 last_coded_bands: 0,
147 prefilter_mem: [vec![0.0; COMBFILTER_MAXPERIOD], vec![0.0; COMBFILTER_MAXPERIOD]],
148 prefilter_period: COMBFILTER_MINPERIOD,
149 prefilter_gain: 0.0,
150 prefilter_tapset: 0,
151 last_pitch: COMBFILTER_MINPERIOD,
152 last_pitch_gain: 0.0,
153 final_range: 0,
154 mdct: MdctLookup::new(1920),
155 scratch_inputs: Vec::new(),
156 scratch_freq: Vec::new(),
157 scratch_pre: [Vec::new(), Vec::new()],
158 complexity: 10,
159 }
160 }
161
162 pub const fn set_complexity(&mut self, complexity: u8) {
164 self.complexity = if complexity > 10 { 10 } else { complexity };
165 }
166
167 pub fn encode_frame(&mut self, pcm: &[f32], nb_bytes: usize) -> Vec<u8> {
174 self.encode_frame_bw(pcm, nb_bytes, NB_EBANDS)
175 }
176
177 pub fn encode_frame_bw(&mut self, pcm: &[f32], nb_bytes: usize, end: usize) -> Vec<u8> {
187 let mut enc = RangeEncoder::new(nb_bytes);
188 let vbr = self.target_bitrate.is_some();
189 self.encode_core(&mut enc, pcm, 0, end, nb_bytes, vbr);
190 self.final_range = enc.range_size();
191 enc.finalize().expect("budget enforced by construction")
192 }
193
194 pub(crate) fn encode_hybrid_into(&mut self, enc: &mut RangeEncoder, pcm: &[f32], nb_bytes: usize, end: usize) {
199 self.encode_core(enc, pcm, 17, end, nb_bytes, false);
200 }
201
202 #[allow(clippy::too_many_arguments, reason = "shared CELT-only/hybrid core")]
211 fn encode_core(
212 &mut self,
213 enc: &mut RangeEncoder,
214 pcm: &[f32],
215 start: usize,
216 end: usize,
217 nb_bytes: usize,
218 vbr: bool,
219 ) {
220 let channels = self.channels;
221 assert!(pcm.len() % channels == 0, "interleaved frame length");
222 assert!((1..=NB_EBANDS).contains(&end), "end must be 1..=21");
223 let n = pcm.len() / channels;
224 let lm = (0..=3)
225 .find(|&lm| SHORT_MDCT_SIZE << lm == n)
226 .expect("frame size must be 120/240/480/960 per channel");
227 assert!((2..=1275).contains(&nb_bytes));
228 let m = 1usize << lm;
229
230 let total_bits = (nb_bytes * 8) as u32;
231
232 let in_len = OVERLAP + n;
235 let mut inputs = core::mem::take(&mut self.scratch_inputs);
238 inputs.resize(in_len * channels, 0.0);
239 for c in 0..channels {
240 let input = &mut inputs[c * in_len..(c + 1) * in_len];
241 input[..OVERLAP].copy_from_slice(&self.in_mem[c]);
242 let mut mem = self.preemph_mem[c];
243 for (dst, &s) in input[OVERLAP..].iter_mut().zip(pcm.iter().skip(c).step_by(channels)) {
244 let s = s * 32768.0;
245 *dst = s - mem;
246 mem = PREEMPH_COEF * s;
247 }
248 self.preemph_mem[c] = mem;
249 }
250
251 let (pf_on, pitch_index, qg) = { self.prefilter_analysis(&mut inputs, in_len, n, channels, nb_bytes) };
256
257 for c in 0..channels {
259 let input = &inputs[c * in_len..(c + 1) * in_len];
260 self.in_mem[c].copy_from_slice(&input[n..n + OVERLAP]);
261 }
262
263 let (is_transient, tf_estimate, tf_chan) = if lm > 0 && enc.tell() + 3 <= total_bits {
265 transient_analysis(&inputs, in_len, channels)
266 } else {
267 (false, 0.0, 0)
268 };
269
270 let mut x = vec![0.0f32; n * channels];
276 let mut band_e = [[0.0f32; NB_EBANDS]; 2];
277 let mut band_log_e = [[0.0f32; NB_EBANDS]; 2];
278 let mut band_log_e2 = [[0.0f32; NB_EBANDS]; 2];
279 let mut freq = core::mem::take(&mut self.scratch_freq);
280 freq.resize(n, 0.0);
281 for c in 0..channels {
282 let input = &inputs[c * in_len..(c + 1) * in_len];
283 if is_transient {
284 let sub = n / m;
286 for b in 0..m {
287 self.mdct.forward(
288 &input[b * sub..b * sub + sub + OVERLAP],
289 &mut freq[b..],
290 &WINDOW120,
291 OVERLAP,
292 3,
293 m,
294 );
295 }
296 let mut freq2 = vec![0.0f32; n];
298 self.mdct.forward(input, &mut freq2, &WINDOW120, OVERLAP, 3 - lm, 1);
299 for i in 0..end {
300 let lo = m * EBANDS[i] as usize;
301 let hi = m * EBANDS[i + 1] as usize;
302 let sum = 1e-27f32 + crate::simd::dot(&freq2[lo..hi], &freq2[lo..hi]);
303 band_log_e2[c][i] = sum.sqrt().log2() - E_MEANS[i] + 0.5 * lm as f32;
304 }
305 } else {
306 self.mdct.forward(input, &mut freq, &WINDOW120, OVERLAP, 3 - lm, 1);
307 }
308
309 let xc = &mut x[c * n..(c + 1) * n];
310 for i in 0..end {
311 let lo = m * EBANDS[i] as usize;
312 let hi = m * EBANDS[i + 1] as usize;
313 let sum = 1e-27f32 + crate::simd::dot(&freq[lo..hi], &freq[lo..hi]);
314 band_e[c][i] = sum.sqrt();
315 band_log_e[c][i] = band_e[c][i].log2() - E_MEANS[i];
316 if !is_transient {
317 band_log_e2[c][i] = band_log_e[c][i];
318 }
319 let g = 1.0 / (1e-27 + band_e[c][i]);
320 for (xv, &f) in xc[lo..hi].iter_mut().zip(freq[lo..hi].iter()) {
321 *xv = f * g;
322 }
323 }
324 }
325
326 let dyn_an = {
330 dynalloc_analysis(
331 &band_log_e,
332 &band_log_e2,
333 &self.energy.old_ebands,
334 start,
335 end,
336 channels,
337 lm,
338 nb_bytes,
339 is_transient,
340 )
341 };
342 let boost_targets = dyn_an.offsets;
343
344 let n0 = n;
347 let (mut tf_res, tf_select) = if nb_bytes >= 15 * channels && lm > 0 && self.complexity >= 2 {
348 let lambda = 80.max(20480 / nb_bytes as i32 + 2);
349 tf_analysis(
350 end,
351 is_transient,
352 lambda,
353 &x,
354 n0,
355 lm,
356 tf_estimate,
357 tf_chan,
358 &dyn_an.importance,
359 )
360 } else {
361 ([i32::from(is_transient); NB_EBANDS], usize::from(is_transient))
362 };
363
364 let equiv_rate =
366 (nb_bytes as i32) * 8 * 50 * (1 << (3 - lm)) - (40 * channels as i32 + 20) * ((400 >> lm) - 50);
367
368 if enc.tell() == 1 {
372 enc.encode_bit_logp(false, 15);
373 }
374 if start == 0 {
379 if pf_on {
380 enc.encode_bit_logp(true, 1);
381 let p = (pitch_index + 1) as u32;
382 let octave = (32 - p.leading_zeros()) as i32 - 5;
384 enc.encode_uint(octave as u32, 6);
385 enc.encode_raw_bits(p - (16 << octave), (4 + octave) as u32);
386 enc.encode_raw_bits(qg as u32, 3);
387 if enc.tell() + 2 <= total_bits {
388 enc.encode_icdf(self.prefilter_tapset, &TAPSET_ICDF, 2);
389 }
390 } else if enc.tell() + 16 <= total_bits {
391 enc.encode_bit_logp(false, 1);
392 }
393 }
394 if lm > 0 && enc.tell() + 3 <= total_bits {
396 enc.encode_bit_logp(is_transient, 3);
397 }
398 let intra = self.frames == 0;
400 if enc.tell() + 3 <= total_bits {
401 enc.encode_bit_logp(intra, 3);
402 }
403
404 #[allow(clippy::needless_range_loop, reason = "indices address three per-band arrays")]
409 for c in 0..channels {
410 for i in start..end {
411 if (band_log_e[c][i] - self.energy.old_ebands[c][i]).abs() < 2.0 {
412 band_log_e[c][i] -= 0.25 * self.energy_error[c][i];
413 }
414 }
415 }
416
417 let mut error = [[0.0f32; NB_EBANDS]; 2];
419 {
420 self.quant_coarse_energy(enc, start, end, &band_log_e, &mut error, intra, lm, total_bits);
421 }
422
423 {
427 let mut budget = total_bits;
428 let mut tell = enc.tell();
429 let mut logp: u32 = if is_transient { 2 } else { 4 };
430 let tf_select_rsv = lm > 0 && tell + logp < budget;
431 budget -= u32::from(tf_select_rsv);
432 let mut tf_changed = false;
433 let mut curr = 0i32;
434 for r in tf_res.iter_mut().take(end).skip(start) {
435 if tell + logp <= budget {
436 enc.encode_bit_logp(*r != curr, logp);
437 tell = enc.tell();
438 curr = *r;
439 tf_changed |= curr != 0;
440 } else {
441 *r = curr;
442 }
443 logp = if is_transient { 4 } else { 5 };
444 }
445 let base = 4 * usize::from(is_transient);
446 let tf_select = if tf_select_rsv
448 && TF_SELECT_TABLE[lm][base + usize::from(tf_changed)]
449 != TF_SELECT_TABLE[lm][base + 2 + usize::from(tf_changed)]
450 {
451 enc.encode_bit_logp(tf_select != 0, 1);
452 tf_select
453 } else {
454 0
455 };
456 for r in tf_res.iter_mut().take(end).skip(start) {
457 *r = TF_SELECT_TABLE[lm][base + 2 * tf_select + *r as usize];
458 }
459 }
460
461 let mut spread = Spread::Normal;
464 if enc.tell() + 4 <= total_bits {
465 let s = if self.complexity == 0 {
466 Spread::None as i32
467 } else {
468 spreading_decision(
469 &x,
470 n0,
471 &mut self.tonal_average,
472 self.spread_decision,
473 end,
474 channels,
475 m,
476 &dyn_an.spread_weight,
477 )
478 };
479 self.spread_decision = s;
480 spread = Spread::from_raw(s as u32);
481 enc.encode_icdf(s as usize, &SPREAD_ICDF, 5);
482 }
483
484 let caps = init_caps(lm, channels);
488 let mut offsets = [0i32; NB_EBANDS];
489 let total_bits_frac = (total_bits << 3) as i64;
490 let mut total_boost = 0i64;
491 {
492 let mut dynalloc_logp = 6u32;
493 let mut tell_frac = i64::from(enc.tell_frac());
494 for i in start..end {
495 let width = (channels as i32 * i32::from(EBANDS[i + 1] - EBANDS[i])) << lm;
496 let quanta = (width << BITRES).min((6 << BITRES).max(width));
498 let mut dynalloc_loop_logp = dynalloc_logp;
499 let mut boost = 0i32;
500 let mut j = 0i32;
501 while tell_frac + (i64::from(dynalloc_loop_logp) << BITRES) < total_bits_frac - total_boost
502 && boost < caps[i]
503 {
504 let flag = j < boost_targets[i];
505 enc.encode_bit_logp(flag, dynalloc_loop_logp);
506 tell_frac = i64::from(enc.tell_frac());
507 if !flag {
508 break;
509 }
510 boost += quanta;
511 total_boost += i64::from(quanta);
512 dynalloc_loop_logp = 1;
513 j += 1;
514 }
515 if j > 0 {
516 dynalloc_logp = 2.max(dynalloc_logp - 1);
517 }
518 offsets[i] = boost;
519 }
520 }
521
522 let trim = if i64::from(enc.tell_frac()) + (6 << 3) <= total_bits_frac - total_boost {
526 let trim = alloc_trim_analysis(&band_log_e, end, channels, tf_estimate, equiv_rate);
527 enc.encode_icdf(trim as usize, &TRIM_ICDF, 7);
528 trim
529 } else {
530 5
531 };
532
533 let (intensity, dual_stereo) = if channels == 2 {
537 let dual = lm != 0 && stereo_analysis(&x, n, lm);
538 self.intensity = hysteresis_decision(
539 (equiv_rate / 1000) as f32,
540 &INTENSITY_THRESHOLDS,
541 &INTENSITY_HYSTERESIS,
542 self.intensity,
543 )
544 .clamp(start, end);
545 (self.intensity, dual)
546 } else {
547 (end, false)
548 };
549
550 let mut nb_bytes = nb_bytes;
556 if let Some(bitrate) = self.target_bitrate.filter(|_| vbr) {
557 let bitrate = bitrate as i32;
558 nb_bytes = nb_bytes.min(1275 >> (3 - lm));
560 let vbr_rate = ((i64::from(bitrate) * n as i64) / 6000) as i32; let base_target = vbr_rate - ((40 * channels as i32 + 20) << BITRES);
562 let mut target = i64::from(compute_vbr(
563 base_target,
564 lm,
565 channels,
566 bitrate,
567 self.last_coded_bands,
568 intensity,
569 0.0,
570 dyn_an.tot_boost,
571 tf_estimate,
572 dyn_an.max_depth,
573 0.0,
574 ));
575 let tell = i64::from(enc.tell_frac());
576 target += tell;
577 let min_allowed = ((tell + total_boost + ((1 << (BITRES + 3)) - 1)) >> (BITRES + 3)) + 2;
578 let nb_avail = ((target + (1 << (BITRES + 2))) >> (BITRES + 3)).clamp(min_allowed, nb_bytes as i64);
579 nb_bytes = nb_avail as usize;
580 enc.shrink(nb_bytes);
581 }
582
583 let mut bits = (((nb_bytes * 8) << 3) as i32) - enc.tell_frac() as i32 - 1;
585 let anti_collapse_rsv = if is_transient && lm >= 2 && bits >= ((lm as i32 + 2) << 3) {
586 1 << 3
587 } else {
588 0
589 };
590 bits -= anti_collapse_rsv;
591 let alloc = compute_allocation(
592 &mut AllocEc::Enc {
593 enc: &mut *enc,
594 signal_bandwidth: end - 1,
595 intensity,
596 dual_stereo,
597 },
598 start,
599 end,
600 &offsets,
601 &caps,
602 trim,
603 bits,
604 channels,
605 lm,
606 );
607 self.last_coded_bands = alloc.coded_bands;
608
609 self.quant_fine_energy(enc, start, end, &mut error, &alloc.fine_quant);
611
612 let total = ((nb_bytes * 8) << 3) as i32 - anti_collapse_rsv;
614 let (xs, ys) = x.split_at_mut(n);
615 quant_all_bands_enc(
616 enc,
617 start,
618 end,
619 xs,
620 if channels == 2 { Some(ys) } else { None },
621 &alloc.shape_bits,
622 is_transient,
623 spread,
624 alloc.dual_stereo,
625 alloc.intensity,
626 &tf_res,
627 total,
628 alloc.balance,
629 lm,
630 alloc.coded_bands,
631 &band_e,
632 );
633
634 if anti_collapse_rsv > 0 {
636 enc.encode_raw_bits(u32::from(self.consec_transient < 2), 1);
637 }
638
639 let bits_left = nb_bytes as i32 * 8 - enc.tell() as i32;
641 self.quant_energy_finalise(
642 enc,
643 start,
644 end,
645 &mut error,
646 &alloc.fine_quant,
647 &alloc.fine_priority,
648 bits_left,
649 );
650
651 #[allow(clippy::needless_range_loop, reason = "indices address two per-band arrays")]
654 for c in 0..channels {
655 for i in start..end {
656 self.energy_error[c][i] = error[c][i].clamp(-0.5, 0.5);
657 }
658 }
659
660 if is_transient {
661 self.consec_transient += 1;
662 } else {
663 self.consec_transient = 0;
664 }
665 self.last_transient = is_transient;
666 self.frames += 1;
667
668 self.scratch_inputs = inputs;
670 self.scratch_freq = freq;
671 }
672
673 #[must_use]
676 pub const fn final_range(&self) -> u32 {
677 self.final_range
678 }
679
680 pub const fn set_target_bitrate(&mut self, bitrate: Option<u32>) {
685 self.target_bitrate = bitrate;
686 }
687
688 #[must_use]
691 pub const fn last_transient(&self) -> bool {
692 self.last_transient
693 }
694
695 #[must_use]
699 pub const fn last_pitch(&self) -> (usize, f32) {
700 (self.last_pitch, self.last_pitch_gain)
701 }
702
703 #[allow(
710 clippy::needless_range_loop,
711 reason = "channel index also addresses prefilter_mem/inputs"
712 )]
713 fn prefilter_analysis(
714 &mut self,
715 inputs: &mut [f32],
716 in_len: usize,
717 n: usize,
718 channels: usize,
719 nb_bytes: usize,
720 ) -> (bool, usize, i32) {
721 let pre_len = COMBFILTER_MAXPERIOD + n;
723 let mut pre = core::mem::take(&mut self.scratch_pre);
725 for c in 0..channels {
726 pre[c].resize(pre_len, 0.0);
727 pre[c][..COMBFILTER_MAXPERIOD].copy_from_slice(&self.prefilter_mem[c]);
728 pre[c][COMBFILTER_MAXPERIOD..].copy_from_slice(&inputs[c * in_len + OVERLAP..c * in_len + OVERLAP + n]);
729 }
730
731 let enabled = nb_bytes > 12 * channels && self.complexity >= 5;
732 let (pitch_index, mut gain1) = if enabled {
733 let refs: Vec<&[f32]> = pre[..channels].iter().map(Vec::as_slice).collect();
734 let x_lp = pitch_downsample(&refs, pre_len);
735 let max_pitch = COMBFILTER_MAXPERIOD - 3 * COMBFILTER_MINPERIOD;
736 let coarse = pitch_search(&x_lp[COMBFILTER_MAXPERIOD >> 1..], &x_lp, n, max_pitch);
737 let mut pitch_index = COMBFILTER_MAXPERIOD - coarse;
738 let (gain, refined) = remove_doubling(
739 &x_lp,
740 COMBFILTER_MAXPERIOD,
741 COMBFILTER_MINPERIOD,
742 n,
743 pitch_index,
744 self.prefilter_period,
745 self.prefilter_gain,
746 );
747 pitch_index = refined.min(COMBFILTER_MAXPERIOD - 2);
748 (pitch_index, 0.7 * gain)
749 } else {
750 (COMBFILTER_MINPERIOD, 0.0)
751 };
752
753 let mut pf_threshold = 0.2f32;
756 if (pitch_index as i32 - self.prefilter_period as i32).abs() * 10 > pitch_index as i32 {
757 pf_threshold += 0.2;
758 }
759 if nb_bytes < 25 {
760 pf_threshold += 0.1;
761 }
762 if nb_bytes < 35 {
763 pf_threshold += 0.1;
764 }
765 if self.prefilter_gain > 0.4 {
766 pf_threshold -= 0.1;
767 }
768 if self.prefilter_gain > 0.55 {
769 pf_threshold -= 0.1;
770 }
771 pf_threshold = pf_threshold.max(0.2);
772 let mut pf_on = false;
773 let mut qg = 0i32;
774 if gain1 < pf_threshold {
775 gain1 = 0.0;
776 } else {
777 if (gain1 - self.prefilter_gain).abs() < 0.1 {
780 gain1 = self.prefilter_gain;
781 }
782 qg = ((0.5 + gain1 * 32.0 / 3.0).floor() as i32 - 1).clamp(0, 7);
783 gain1 = 0.093_75 * (qg + 1) as f32;
784 pf_on = true;
785 }
786
787 let old_period = self.prefilter_period.max(COMBFILTER_MINPERIOD);
792 let old_tapset = self.prefilter_tapset;
793 let new_tapset = self.prefilter_tapset;
794 for c in 0..channels {
795 let dst = &mut inputs[c * in_len + OVERLAP..c * in_len + OVERLAP + n];
796 comb_filter_prefilter(
797 dst,
798 &pre[c],
799 COMBFILTER_MAXPERIOD,
800 old_period,
801 pitch_index.max(COMBFILTER_MINPERIOD),
802 n,
803 -self.prefilter_gain,
804 -gain1,
805 old_tapset,
806 new_tapset,
807 );
808 }
809
810 for c in 0..channels {
812 self.prefilter_mem[c].copy_from_slice(&pre[c][n..n + COMBFILTER_MAXPERIOD]);
813 }
814 self.prefilter_period = pitch_index.max(COMBFILTER_MINPERIOD);
815 self.prefilter_gain = gain1;
816 self.last_pitch = pitch_index;
817 self.last_pitch_gain = gain1;
818 self.scratch_pre = pre;
819 (pf_on, pitch_index, qg)
820 }
821
822 #[allow(clippy::too_many_arguments, reason = "mirrors quant_coarse_energy_impl")]
825 fn quant_coarse_energy(
826 &mut self,
827 enc: &mut RangeEncoder,
828 start: usize,
829 end: usize,
830 band_log_e: &[[f32; NB_EBANDS]; 2],
831 error: &mut [[f32; NB_EBANDS]; 2],
832 intra: bool,
833 lm: usize,
834 budget: u32,
835 ) {
836 let channels = self.channels;
837 let prob = &E_PROB_MODEL[lm][usize::from(intra)];
838 let (coef, beta) = if intra {
839 (0.0, BETA_INTRA)
840 } else {
841 (PRED_COEF[lm], BETA_COEF[lm])
842 };
843 let max_decay = 16.0f32.min((budget as f32 / 3.0).max(0.0));
844
845 let mut prev = [0.0f32; 2];
846 for i in start..end {
847 for c in 0..channels {
848 let x = band_log_e[c][i];
849 let old_e = self.energy.old_ebands[c][i].max(-9.0);
850 let f = x - coef * old_e - prev[c];
851 let mut qi = (0.5 + f).floor() as i32;
852 let decay_bound = self.energy.old_ebands[c][i].max(-28.0) - max_decay;
853 if qi < 0 && x < decay_bound {
855 qi += (decay_bound - x) as i32;
856 if qi > 0 {
857 qi = 0;
858 }
859 }
860 let tell = enc.tell();
861 let bits_left = budget as i32 - tell as i32 - 3 * channels as i32 * (end - i) as i32;
862 if i != start && bits_left < 30 {
863 if bits_left < 24 {
864 qi = qi.min(1);
865 }
866 if bits_left < 16 {
867 qi = qi.max(-1);
868 }
869 }
870 let avail = i64::from(budget) - i64::from(tell);
874 let qi = if avail >= 15 {
875 let pi = 2 * i.min(20);
876 ec_laplace_encode(enc, qi, u32::from(prob[pi]) << 7, u32::from(prob[pi + 1]) << 6)
877 } else if avail >= 2 {
878 let qi = qi.clamp(-1, 1);
879 const SMALL_ENERGY_ICDF: [u8; 3] = [2, 1, 0];
880 enc.encode_icdf(((2 * qi) ^ -i32::from(qi < 0)) as usize, &SMALL_ENERGY_ICDF, 2);
881 qi
882 } else if avail >= 1 {
883 let qi = qi.min(0);
884 enc.encode_bit_logp(qi != 0, 1);
885 qi
886 } else {
887 -1
888 };
889 error[c][i] = f - qi as f32;
890 let q = qi as f32;
891 self.energy.old_ebands[c][i] = coef * old_e + prev[c] + q;
892 prev[c] = prev[c] + q - beta * q;
893 }
894 }
895 if channels == 1 {
896 self.energy.old_ebands[1] = self.energy.old_ebands[0];
897 }
898 }
899
900 #[allow(
901 clippy::needless_range_loop,
902 reason = "channel indices mirror the reference's c loop"
903 )]
904 fn quant_fine_energy(
905 &mut self,
906 enc: &mut RangeEncoder,
907 start: usize,
908 end: usize,
909 error: &mut [[f32; NB_EBANDS]; 2],
910 fine_quant: &[i32; NB_EBANDS],
911 ) {
912 let channels = self.channels;
913 for i in start..end {
914 if fine_quant[i] <= 0 {
915 continue;
916 }
917 let frac = 1 << fine_quant[i];
918 for c in 0..channels {
919 let q2 = (((error[c][i] + 0.5) * frac as f32).floor() as i32).clamp(0, frac - 1);
920 enc.encode_raw_bits(q2 as u32, fine_quant[i] as u32);
921 let offset = (q2 as f32 + 0.5) * (1 << (14 - fine_quant[i])) as f32 / 16384.0 - 0.5;
922 self.energy.old_ebands[c][i] += offset;
923 error[c][i] -= offset;
924 }
925 }
926 if channels == 1 {
927 self.energy.old_ebands[1] = self.energy.old_ebands[0];
928 }
929 }
930
931 #[allow(clippy::too_many_arguments, reason = "mirrors quant_energy_finalise")]
932 #[allow(
933 clippy::needless_range_loop,
934 reason = "channel indices mirror the reference's c loop"
935 )]
936 fn quant_energy_finalise(
937 &mut self,
938 enc: &mut RangeEncoder,
939 start: usize,
940 end: usize,
941 error: &mut [[f32; NB_EBANDS]; 2],
942 fine_quant: &[i32; NB_EBANDS],
943 fine_priority: &[bool; NB_EBANDS],
944 mut bits_left: i32,
945 ) {
946 let channels = self.channels;
947 for prio in [false, true] {
948 let mut i = start;
949 while i < end && bits_left >= channels as i32 {
950 if fine_quant[i] >= MAX_FINE_BITS || fine_priority[i] != prio {
951 i += 1;
952 continue;
953 }
954 for c in 0..channels {
955 let q2 = i32::from(error[c][i] >= 0.0);
956 enc.encode_raw_bits(q2 as u32, 1);
957 let offset = (q2 as f32 - 0.5) * (1 << (14 - fine_quant[i] - 1)) as f32 / 16384.0;
958 self.energy.old_ebands[c][i] += offset;
959 error[c][i] -= offset;
960 bits_left -= 1;
961 }
962 i += 1;
963 }
964 }
965 if channels == 1 {
966 self.energy.old_ebands[1] = self.energy.old_ebands[0];
967 }
968 }
969}
970
971fn transient_analysis(inputs: &[f32], len: usize, channels: usize) -> (bool, f32, usize) {
980 const INV_TABLE: [u8; 128] = [
982 255, 255, 156, 110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25, 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15,
983 14, 13, 13, 12, 12, 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6,
984 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
985 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
986 ];
987 const EPSILON: f32 = 1e-15;
988 const FORWARD_DECAY: f32 = 0.0625;
990
991 let len2 = len / 2;
992 let mut mask_metric = 0i32;
993 let mut tf_chan = 0usize;
994 let mut tmp = vec![0.0f32; len];
995 for c in 0..channels {
996 let input = &inputs[c * len..(c + 1) * len];
997
998 let (mut mem0, mut mem1) = (0.0f32, 0.0f32);
1000 for (t, &x) in tmp.iter_mut().zip(input.iter()) {
1001 let y = mem0 + x;
1002 let mem00 = mem0;
1003 mem0 = mem0 - x + 0.5 * mem1;
1004 mem1 = x - mem00;
1005 *t = y;
1006 }
1007 tmp[..12].fill(0.0);
1009
1010 let mut mean = 0.0f32;
1012 let mut mem = 0.0f32;
1013 for i in 0..len2 {
1014 let x2 = tmp[2 * i] * tmp[2 * i] + tmp[2 * i + 1] * tmp[2 * i + 1];
1015 mean += x2;
1016 mem = x2 + (1.0 - FORWARD_DECAY) * mem;
1017 tmp[i] = FORWARD_DECAY * mem;
1018 }
1019
1020 let mut mem = 0.0f32;
1022 let mut max_e = 0.0f32;
1023 for i in (0..len2).rev() {
1024 mem = tmp[i] + 0.875 * mem;
1025 tmp[i] = 0.125 * mem;
1026 max_e = max_e.max(0.125 * mem);
1027 }
1028
1029 let mean = (mean * max_e * 0.5 * len2 as f32).sqrt();
1031 let norm = len2 as f32 / (EPSILON + mean);
1032 let mut unmask = 0i32;
1034 let mut i = 12;
1035 while i + 5 < len2 {
1036 let id = (64.0 * norm * (tmp[i] + EPSILON)).floor().clamp(0.0, 127.0) as usize;
1037 unmask += i32::from(INV_TABLE[id]);
1038 i += 4;
1039 }
1040 let unmask = 64 * unmask * 4 / (6 * (len2 as i32 - 17));
1042 if unmask > mask_metric {
1043 tf_chan = c;
1044 mask_metric = unmask;
1045 }
1046 }
1047 let is_transient = mask_metric > 200;
1048 let tf_max = 0.0f32.max((27.0 * mask_metric as f32).sqrt() - 42.0);
1050 let tf_estimate = 0.0f32.max(0.0069 * 163.0f32.min(tf_max) - 0.139).sqrt();
1051 (is_transient, tf_estimate, tf_chan)
1052}
1053
1054#[allow(clippy::too_many_arguments, reason = "mirrors the reference comb-filter signature")]
1061fn comb_filter_prefilter(
1062 dst: &mut [f32],
1063 src: &[f32],
1064 base: usize,
1065 t0: usize,
1066 t1: usize,
1067 n: usize,
1068 g0: f32,
1069 g1: f32,
1070 tapset0: usize,
1071 tapset1: usize,
1072) {
1073 if g0 == 0.0 && g1 == 0.0 {
1074 dst[..n].copy_from_slice(&src[base..base + n]);
1075 return;
1076 }
1077 let t0 = t0.max(COMBFILTER_MINPERIOD);
1078 let t1 = t1.max(COMBFILTER_MINPERIOD);
1079 let g00 = g0 * COMB_GAINS[tapset0][0];
1080 let g01 = g0 * COMB_GAINS[tapset0][1];
1081 let g02 = g0 * COMB_GAINS[tapset0][2];
1082 let g10 = g1 * COMB_GAINS[tapset1][0];
1083 let g11 = g1 * COMB_GAINS[tapset1][1];
1084 let g12 = g1 * COMB_GAINS[tapset1][2];
1085
1086 let overlap = if g0 == g1 && t0 == t1 && tapset0 == tapset1 {
1088 0
1089 } else {
1090 OVERLAP.min(n)
1091 };
1092 let mut x1 = src[base + 1 - t1];
1093 let mut x2 = src[base - t1];
1094 let mut x3 = src[base - t1 - 1];
1095 let mut x4 = src[base - t1 - 2];
1096
1097 let mut i = 0usize;
1098 while i < overlap {
1099 let x0 = src[base + i + 2 - t1];
1100 let f = WINDOW120[i] * WINDOW120[i];
1101 dst[i] = src[base + i]
1102 + (1.0 - f) * g00 * src[base + i - t0]
1103 + (1.0 - f) * g01 * (src[base + i + 1 - t0] + src[base + i - 1 - t0])
1104 + (1.0 - f) * g02 * (src[base + i + 2 - t0] + src[base + i - 2 - t0])
1105 + f * g10 * x2
1106 + f * g11 * (x1 + x3)
1107 + f * g12 * (x0 + x4);
1108 x4 = x3;
1109 x3 = x2;
1110 x2 = x1;
1111 x1 = x0;
1112 i += 1;
1113 }
1114 if g1 == 0.0 {
1115 dst[overlap..n].copy_from_slice(&src[base + overlap..base + n]);
1116 return;
1117 }
1118 while i < n {
1119 dst[i] = src[base + i]
1120 + g10 * src[base + i - t1]
1121 + g11 * (src[base + i + 1 - t1] + src[base + i - 1 - t1])
1122 + g12 * (src[base + i + 2 - t1] + src[base + i - 2 - t1]);
1123 i += 1;
1124 }
1125}
1126
1127#[allow(clippy::too_many_arguments, reason = "mirrors the reference signature")]
1140fn compute_vbr(
1141 base_target: i32,
1142 lm: usize,
1143 channels: usize,
1144 bitrate: i32,
1145 last_coded_bands: usize,
1146 intensity: usize,
1147 stereo_saving: f32,
1148 tot_boost: i32,
1149 tf_estimate: f32,
1150 max_depth: f32,
1151 temporal_vbr: f32,
1152) -> i32 {
1153 let coded_bands = if last_coded_bands == 0 {
1154 NB_EBANDS
1155 } else {
1156 last_coded_bands
1157 };
1158 let mut coded_bins = i64::from(i32::from(EBANDS[coded_bands]) << lm);
1159 if channels == 2 {
1160 coded_bins += i64::from(i32::from(EBANDS[intensity.min(coded_bands)]) << lm);
1161 }
1162 let mut target = i64::from(base_target);
1163
1164 if channels == 2 {
1166 let coded_stereo_bands = intensity.min(coded_bands);
1167 let coded_stereo_dof = i64::from(i32::from(EBANDS[coded_stereo_bands]) << lm) - coded_stereo_bands as i64;
1168 let max_frac = 0.8 * coded_stereo_dof as f32 / coded_bins as f32;
1169 let stereo_saving = stereo_saving.min(1.0);
1170 let reduce = (max_frac * target as f32).min((stereo_saving - 0.1) * (coded_stereo_dof << BITRES) as f32);
1171 target -= reduce as i64;
1172 }
1173
1174 target += i64::from(tot_boost - (19 << lm));
1176 let tf_calibration = 0.044f32;
1177 target += (2.0 * (tf_estimate - tf_calibration) * target as f32) as i64;
1178
1179 let bins = i64::from(i32::from(EBANDS[NB_EBANDS - 2]) << lm);
1181 let mut floor_depth = (((channels as i64 * bins) << BITRES) as f32 * max_depth) as i64;
1182 floor_depth = floor_depth.max(target >> 2);
1183 target = target.min(floor_depth);
1184
1185 if tf_estimate < 0.2 {
1187 let amount = 0.000_003_1 * (96_000 - bitrate).clamp(0, 32_000) as f32;
1188 target += (temporal_vbr * amount * target as f32) as i64;
1189 }
1190
1191 target.min(2 * i64::from(base_target)) as i32
1193}
1194
1195struct Dynalloc {
1198 offsets: [i32; NB_EBANDS],
1200 importance: [i32; NB_EBANDS],
1202 spread_weight: [i32; NB_EBANDS],
1204 tot_boost: i32,
1206 max_depth: f32,
1209}
1210
1211#[allow(clippy::too_many_arguments, reason = "mirrors the reference signature")]
1212#[allow(clippy::needless_range_loop, reason = "band indices mirror the reference loops")]
1213fn dynalloc_analysis(
1214 band_log_e: &[[f32; NB_EBANDS]; 2],
1215 band_log_e2: &[[f32; NB_EBANDS]; 2],
1216 old_ebands: &[[f32; NB_EBANDS]; 2],
1217 start: usize,
1218 end: usize,
1219 channels: usize,
1220 lm: usize,
1221 effective_bytes: usize,
1222 is_transient: bool,
1223) -> Dynalloc {
1224 const LSB_DEPTH: f32 = 24.0;
1226 let mut offsets = [0i32; NB_EBANDS];
1227 let mut importance = [13i32; NB_EBANDS];
1228 let mut spread_weight = [32i32; NB_EBANDS];
1229
1230 let mut noise_floor = [0.0f32; NB_EBANDS];
1232 for (i, nf) in noise_floor.iter_mut().enumerate().take(end) {
1233 *nf = 0.0625 * f32::from(LOG_N[i]) + 0.5 + (9.0 - LSB_DEPTH) - E_MEANS[i] + 0.0062 * ((i + 5) * (i + 5)) as f32;
1234 }
1235
1236 let mut max_depth = -31.9f32;
1238 for c in 0..channels {
1239 for i in 0..end {
1240 max_depth = max_depth.max(band_log_e[c][i] - noise_floor[i]);
1241 }
1242 }
1243
1244 {
1247 let mut mask = [0.0f32; NB_EBANDS];
1248 let mut sig = [0.0f32; NB_EBANDS];
1249 for i in 0..end {
1250 mask[i] = band_log_e[0][i] - noise_floor[i];
1251 if channels == 2 {
1252 mask[i] = mask[i].max(band_log_e[1][i] - noise_floor[i]);
1253 }
1254 sig[i] = mask[i];
1255 }
1256 for i in 1..end {
1257 mask[i] = mask[i].max(mask[i - 1] - 2.0);
1258 }
1259 for i in (0..end - 1).rev() {
1260 mask[i] = mask[i].max(mask[i + 1] - 3.0);
1261 }
1262 for i in 0..end {
1263 let smr = sig[i] - 0.0f32.max(max_depth - 12.0).max(mask[i]);
1265 let shift = (-(0.5 + smr).floor() as i32).clamp(0, 5);
1266 spread_weight[i] = 32 >> shift;
1267 }
1268 }
1269
1270 if effective_bytes < 30 + 5 * lm {
1272 return Dynalloc {
1273 offsets,
1274 importance,
1275 spread_weight,
1276 tot_boost: 0,
1277 max_depth,
1278 };
1279 }
1280
1281 let mut follower = [[0.0f32; NB_EBANDS]; 2];
1282 for c in 0..channels {
1283 let mut e3 = [0.0f32; NB_EBANDS];
1284 e3[..end].copy_from_slice(&band_log_e2[c][..end]);
1285 if lm == 0 {
1286 for i in 0..end.min(8) {
1289 e3[i] = band_log_e2[c][i].max(old_ebands[c][i]);
1290 }
1291 }
1292 let f = &mut follower[c];
1293 f[0] = e3[0];
1294 let mut last = 0usize;
1295 for i in 1..end {
1296 if e3[i] > e3[i - 1] + 0.5 {
1299 last = i;
1300 }
1301 f[i] = (f[i - 1] + 1.5).min(e3[i]);
1302 }
1303 for i in (0..last).rev() {
1304 f[i] = f[i].min((f[i + 1] + 2.0).min(e3[i]));
1305 }
1306 const OFFSET: f32 = 1.0;
1308 for i in 2..end.saturating_sub(2) {
1309 f[i] = f[i].max(median_of_5(&e3[i - 2..i + 3]) - OFFSET);
1310 }
1311 let tmp = median_of_3(&e3[0..3]) - OFFSET;
1312 f[0] = f[0].max(tmp);
1313 f[1] = f[1].max(tmp);
1314 let tmp = median_of_3(&e3[end - 3..end]) - OFFSET;
1315 f[end - 2] = f[end - 2].max(tmp);
1316 f[end - 1] = f[end - 1].max(tmp);
1317 for i in 0..end {
1318 f[i] = f[i].max(noise_floor[i]);
1319 }
1320 }
1321
1322 if channels == 2 {
1323 for i in start..end {
1324 let (l, r) = (follower[0][i], follower[1][i]);
1326 follower[1][i] = r.max(l - 4.0);
1327 follower[0][i] = l.max(r - 4.0);
1328 follower[0][i] =
1329 0.5 * (0.0f32.max(band_log_e[0][i] - follower[0][i]) + 0.0f32.max(band_log_e[1][i] - follower[1][i]));
1330 }
1331 } else {
1332 for i in start..end {
1333 follower[0][i] = 0.0f32.max(band_log_e[0][i] - follower[0][i]);
1334 }
1335 }
1336
1337 for i in start..end {
1339 importance[i] = (0.5 + 13.0 * celt_exp2(follower[0][i].min(4.0))).floor() as i32;
1340 }
1341
1342 if !is_transient {
1344 for i in start..end {
1345 follower[0][i] *= 0.5;
1346 }
1347 }
1348 for i in start..end {
1349 if i < 8 {
1350 follower[0][i] *= 2.0;
1351 }
1352 if i >= 12 {
1353 follower[0][i] *= 0.5;
1354 }
1355 }
1356
1357 let mut tot_boost = 0i32;
1358 let caps = init_caps(lm, channels);
1359 for i in start..end {
1360 follower[0][i] = follower[0][i].min(4.0);
1361 let width = (channels as i32 * i32::from(EBANDS[i + 1] - EBANDS[i])) << lm;
1362 let (boost, boost_bits) = if width < 6 {
1363 let boost = follower[0][i] as i32;
1364 (boost, (boost * width) << BITRES)
1365 } else if width > 48 {
1366 let boost = (follower[0][i] * 8.0) as i32;
1367 (boost, ((boost * width) << BITRES) / 8)
1368 } else {
1369 let boost = (follower[0][i] * width as f32 / 6.0) as i32;
1370 (boost, (boost * 6) << BITRES)
1371 };
1372 if (tot_boost + boost_bits) >> BITRES >> 3 > 2 * effective_bytes as i32 / 3 {
1374 let cap = (2 * effective_bytes as i32 / 3) << BITRES << 3;
1375 offsets[i] = cap - tot_boost;
1376 break;
1377 }
1378 offsets[i] = boost.min(caps[i]);
1379 tot_boost += boost_bits;
1380 }
1381 Dynalloc {
1382 offsets,
1383 importance,
1384 spread_weight,
1385 tot_boost,
1386 max_depth,
1387 }
1388}
1389
1390#[allow(clippy::excessive_precision, reason = "verbatim reference polynomial constants")]
1393fn celt_exp2(x: f32) -> f32 {
1394 let integer = x.floor();
1395 if integer < -50.0 {
1396 return 0.0;
1397 }
1398 let frac = x - integer;
1399 let res = 0.999_925_22 + frac * (0.695_833_54 + frac * (0.226_067_16 + 0.078_024_52 * frac));
1400 let bits = (res.to_bits() as i32 + ((integer as i32) << 23)) & 0x7fff_ffff;
1402 f32::from_bits(bits as u32)
1403}
1404
1405fn median_of_5(x: &[f32]) -> f32 {
1407 let (t0, t1) = if x[0] > x[1] { (x[1], x[0]) } else { (x[0], x[1]) };
1408 let (t3, t4) = if x[3] > x[4] { (x[4], x[3]) } else { (x[3], x[4]) };
1409 let (_t0, t1, t3, t4) = if t0 > t3 { (t3, t4, t0, t1) } else { (t0, t1, t3, t4) };
1410 let t2 = x[2];
1411 if t2 > t1 {
1412 if t1 < t3 { t2.min(t3) } else { t4.min(t1) }
1413 } else if t2 < t3 {
1414 t1.min(t3)
1415 } else {
1416 t2.min(t4)
1417 }
1418}
1419
1420fn median_of_3(x: &[f32]) -> f32 {
1422 let (t0, t1) = if x[0] > x[1] { (x[1], x[0]) } else { (x[0], x[1]) };
1423 let t2 = x[2];
1424 if t1 < t2 {
1425 t1
1426 } else if t0 < t2 {
1427 t2
1428 } else {
1429 t0
1430 }
1431}
1432
1433#[allow(clippy::needless_range_loop, reason = "band indices mirror the reference loop")]
1437fn alloc_trim_analysis(
1438 band_log_e: &[[f32; NB_EBANDS]; 2],
1439 end: usize,
1440 channels: usize,
1441 tf_estimate: f32,
1442 equiv_rate: i32,
1443) -> i32 {
1444 let mut trim: f32 = if equiv_rate < 64_000 {
1446 4.0
1447 } else if equiv_rate < 80_000 {
1448 4.0 + (1.0 / 16.0) * ((equiv_rate - 64_000) >> 10) as f32
1449 } else {
1450 5.0
1451 };
1452
1453 let mut diff = 0.0f32;
1455 for c in 0..channels {
1456 for i in 0..end - 1 {
1457 diff += band_log_e[c][i] * (2 + 2 * i as i32 - end as i32) as f32;
1458 }
1459 }
1460 diff /= (channels * (end - 1)) as f32;
1461 trim -= (-2.0f32).max(2.0f32.min((diff + 1.0) / 6.0));
1462 trim -= 2.0 * tf_estimate;
1463
1464 (trim + 0.5).floor().clamp(0.0, 10.0) as i32
1465}
1466
1467fn hysteresis_decision(val: f32, thresholds: &[f32], hysteresis: &[f32], prev: usize) -> usize {
1470 let n = thresholds.len();
1471 let mut i = n;
1472 for (k, &t) in thresholds.iter().enumerate() {
1473 if val < t {
1474 i = k;
1475 break;
1476 }
1477 }
1478 if i > prev && val < thresholds[prev] + hysteresis[prev] {
1479 i = prev;
1480 }
1481 if i < prev && val > thresholds[prev - 1] - hysteresis[prev - 1] {
1482 i = prev;
1483 }
1484 i
1485}
1486
1487#[allow(
1490 clippy::approx_constant,
1491 reason = "verbatim reference constant 0.707107, not 1/sqrt(2)"
1492)]
1493fn stereo_analysis(x: &[f32], n0: usize, lm: usize) -> bool {
1494 const EPSILON: f32 = 1e-15;
1495 let mut sum_lr = EPSILON;
1496 let mut sum_ms = EPSILON;
1497 for i in 0..13 {
1498 for j in (EBANDS[i] as usize) << lm..(EBANDS[i + 1] as usize) << lm {
1499 let l = x[j];
1500 let r = x[n0 + j];
1501 sum_lr += l.abs() + r.abs();
1502 sum_ms += (l + r).abs() + (l - r).abs();
1503 }
1504 }
1505 sum_ms *= 0.707_107;
1506 let mut thetas = 13i32;
1507 if lm <= 1 {
1508 thetas -= 8;
1509 }
1510 let w = (i32::from(EBANDS[13]) << (lm + 1)) as f32;
1511 (w + thetas as f32) * sum_ms > w * sum_lr
1512}
1513
1514#[allow(clippy::too_many_arguments, reason = "mirrors the reference signature")]
1520fn spreading_decision(
1521 x: &[f32],
1522 n0: usize,
1523 tonal_average: &mut i32,
1524 last_decision: i32,
1525 end: usize,
1526 channels: usize,
1527 m: usize,
1528 spread_weight: &[i32; NB_EBANDS],
1529) -> i32 {
1530 if m * (EBANDS[end] - EBANDS[end - 1]) as usize <= 8 {
1531 return Spread::None as i32;
1532 }
1533 let mut sum = 0i32;
1534 let mut nb_bands = 0i32;
1535 for c in 0..channels {
1536 for i in 0..end {
1537 let lo = c * n0 + m * EBANDS[i] as usize;
1538 let n = m * (EBANDS[i + 1] - EBANDS[i]) as usize;
1539 if n <= 8 {
1540 continue;
1541 }
1542 let band = &x[lo..lo + n];
1543 let mut tcount = [0i32; 3];
1545 for &v in band {
1546 let x2n = v * v * n as f32;
1547 tcount[0] += i32::from(x2n < 0.25);
1548 tcount[1] += i32::from(x2n < 0.0625);
1549 tcount[2] += i32::from(x2n < 0.015_625);
1550 }
1551 let nn = n as i32;
1552 let tmp = i32::from(2 * tcount[2] >= nn) + i32::from(2 * tcount[1] >= nn) + i32::from(2 * tcount[0] >= nn);
1553 sum += tmp * spread_weight[i];
1554 nb_bands += spread_weight[i];
1555 }
1556 }
1557 let nb_bands = nb_bands.max(1);
1558 let mut sum = (sum << 8) / nb_bands;
1559 sum = (sum + *tonal_average) >> 1;
1561 *tonal_average = sum;
1562 sum = (3 * sum + (((3 - last_decision) << 7) + 64) + 2) >> 2;
1563 if sum < 80 {
1564 Spread::Aggressive as i32
1565 } else if sum < 256 {
1566 Spread::Normal as i32
1567 } else if sum < 384 {
1568 Spread::Light as i32
1569 } else {
1570 Spread::None as i32
1571 }
1572}
1573
1574fn l1_metric(tmp: &[f32], lm: i32, bias: f32) -> f32 {
1576 let l1: f32 = tmp.iter().map(|v| v.abs()).sum();
1577 l1 + l1 * (lm as f32 * bias)
1578}
1579
1580#[allow(clippy::too_many_arguments, reason = "mirrors the reference signature")]
1586#[allow(clippy::needless_range_loop, reason = "band indices mirror the reference loops")]
1587fn tf_analysis(
1588 end: usize,
1589 is_transient: bool,
1590 lambda: i32,
1591 x: &[f32],
1592 n0: usize,
1593 lm: usize,
1594 tf_estimate: f32,
1595 tf_chan: usize,
1596 importance: &[i32; NB_EBANDS],
1597) -> ([i32; NB_EBANDS], usize) {
1598 let bias = 0.04 * (-0.25f32).max(0.5 - tf_estimate);
1599 let mut metric = [0i32; NB_EBANDS];
1600 let mut path0 = [0i32; NB_EBANDS];
1601 let mut path1 = [0i32; NB_EBANDS];
1602
1603 for i in 0..end {
1604 let n = (EBANDS[i + 1] - EBANDS[i]) as usize * (1 << lm);
1605 let narrow = (EBANDS[i + 1] - EBANDS[i]) == 1;
1606 let lo = tf_chan * n0 + (EBANDS[i] as usize) * (1 << lm);
1607 let mut tmp = x[lo..lo + n].to_vec();
1608 let mut best_l1 = l1_metric(&tmp, if is_transient { lm as i32 } else { 0 }, bias);
1609 let mut best_level = 0i32;
1610 if is_transient && !narrow {
1612 let mut tmp1 = tmp.clone();
1613 haar1(&mut tmp1, n >> lm, 1 << lm);
1614 let l1 = l1_metric(&tmp1, lm as i32 + 1, bias);
1615 if l1 < best_l1 {
1616 best_l1 = l1;
1617 best_level = -1;
1618 }
1619 }
1620 let levels = lm + usize::from(!(is_transient || narrow));
1621 for k in 0..levels {
1622 let b = if is_transient {
1623 lm as i32 - k as i32 - 1
1624 } else {
1625 k as i32 + 1
1626 };
1627 haar1(&mut tmp, n >> k, 1 << k);
1628 let l1 = l1_metric(&tmp, b, bias);
1629 if l1 < best_l1 {
1630 best_l1 = l1;
1631 best_level = k as i32 + 1;
1632 }
1633 }
1634 metric[i] = if is_transient { 2 * best_level } else { -2 * best_level };
1636 if narrow && (metric[i] == 0 || metric[i] == -2 * lm as i32) {
1637 metric[i] -= 1;
1638 }
1639 }
1640
1641 let tf_tab = &TF_SELECT_TABLE[lm];
1642 let base = 4 * usize::from(is_transient);
1643 let cost = |sel: usize, flag: usize, i: usize| -> i32 {
1644 importance[i] * (metric[i] - 2 * tf_tab[base + 2 * sel + flag]).abs()
1645 };
1646
1647 let mut selcost = [0i32; 2];
1649 for sel in 0..2 {
1650 let mut cost0 = cost(sel, 0, 0);
1651 let mut cost1 = cost(sel, 1, 0) + if is_transient { 0 } else { lambda };
1652 for i in 1..end {
1653 let curr0 = cost0.min(cost1 + lambda);
1654 let curr1 = (cost0 + lambda).min(cost1);
1655 cost0 = curr0 + cost(sel, 0, i);
1656 cost1 = curr1 + cost(sel, 1, i);
1657 }
1658 selcost[sel] = cost0.min(cost1);
1659 }
1660 let tf_select = usize::from(selcost[1] < selcost[0] && is_transient);
1662
1663 let mut cost0 = cost(tf_select, 0, 0);
1665 let mut cost1 = cost(tf_select, 1, 0) + if is_transient { 0 } else { lambda };
1666 for i in 1..end {
1667 let (curr0, p0) = if cost0 < cost1 + lambda {
1668 (cost0, 0)
1669 } else {
1670 (cost1 + lambda, 1)
1671 };
1672 let (curr1, p1) = if cost0 + lambda < cost1 {
1673 (cost0 + lambda, 0)
1674 } else {
1675 (cost1, 1)
1676 };
1677 path0[i] = p0;
1678 path1[i] = p1;
1679 cost0 = curr0 + cost(tf_select, 0, i);
1680 cost1 = curr1 + cost(tf_select, 1, i);
1681 }
1682 let mut tf_res = [0i32; NB_EBANDS];
1683 tf_res[end - 1] = i32::from(cost0 >= cost1);
1684 for i in (0..end - 1).rev() {
1685 tf_res[i] = if tf_res[i + 1] == 1 { path1[i + 1] } else { path0[i + 1] };
1686 }
1687 (tf_res, tf_select)
1688}