1#![allow(clippy::excessive_precision, clippy::needless_range_loop)]
4use crate::acpl::{sb_to_pb, AcplHuffParam, AcplQuantMode};
76use crate::qmf::NUM_QMF_SUBBANDS;
77
78#[rustfmt::skip]
85pub const ALPHA_DQ_FINE: [f32; 33] = [
86 -2.000000, -1.809375, -1.637500, -1.484375, -1.350000, -1.234375,
87 -1.137500, -1.059375, -1.000000, -0.940625, -0.862500, -0.765625,
88 -0.650000, -0.515625, -0.362500, -0.190625, 0.000000, 0.190625,
89 0.362500, 0.515625, 0.650000, 0.765625, 0.862500, 0.940625,
90 1.000000, 1.059375, 1.137500, 1.234375, 1.350000, 1.484375,
91 1.637500, 1.809375, 2.000000,
92];
93
94#[rustfmt::skip]
98pub const IBETA_FINE: [u8; 33] = [
99 0, 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5,
100 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0,
101];
102
103#[rustfmt::skip]
105pub const ALPHA_DQ_COARSE: [f32; 17] = [
106 -2.000000, -1.637500, -1.350000, -1.137500, -1.000000, -0.862500,
107 -0.650000, -0.362500, 0.000000, 0.362500, 0.650000, 0.862500,
108 1.000000, 1.137500, 1.350000, 1.637500, 2.000000,
109];
110
111#[rustfmt::skip]
113pub const IBETA_COARSE: [u8; 17] = [
114 0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 0,
115];
116
117#[rustfmt::skip]
123pub const BETA_DQ_FINE: [[f32; 9]; 9] = [
124 [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
126 [0.2375000, 0.2035449, 0.1729297, 0.1456543, 0.1217188, 0.1011230, 0.0838672, 0.0699512, 0.0593750],
128 [0.5500000, 0.4713672, 0.4004688, 0.3373047, 0.2818750, 0.2341797, 0.1942188, 0.1619922, 0.1375000],
130 [0.9375000, 0.8034668, 0.6826172, 0.5749512, 0.4804688, 0.3991699, 0.3310547, 0.2761230, 0.2343750],
132 [1.4000000, 1.1998440, 1.0193750, 0.8585938, 0.7175000, 0.5960938, 0.4943750, 0.4123438, 0.3500000],
134 [1.9375000, 1.6604980, 1.4107420, 1.1882319, 0.9929688, 0.8249512, 0.6841797, 0.5706543, 0.4843750],
136 [2.5500000, 2.1854300, 1.8567190, 1.5638670, 1.3068750, 1.0857420, 0.9004688, 0.7510547, 0.6375000],
138 [3.2375000, 2.7746389, 2.3573050, 1.9854980, 1.6592190, 1.3784670, 1.1432420, 0.9535449, 0.8093750],
140 [4.0000000, 3.4281249, 2.9124999, 2.4531250, 2.0500000, 1.7031250, 1.4125000, 1.1781250, 1.0000000],
142];
143
144#[rustfmt::skip]
147pub const BETA_DQ_COARSE: [[f32; 5]; 5] = [
148 [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
150 [0.5500000, 0.4004688, 0.2818750, 0.1942188, 0.1375000],
152 [1.4000000, 1.0193750, 0.7175000, 0.4943750, 0.3500000],
154 [2.5500000, 1.8567190, 1.3068750, 0.9004688, 0.6375000],
156 [4.0000000, 2.9124999, 2.0500000, 1.4125000, 1.0000000],
158];
159
160pub fn beta3_delta(qm: AcplQuantMode) -> f32 {
163 match qm {
164 AcplQuantMode::Fine => 0.125,
165 AcplQuantMode::Coarse => 0.25,
166 }
167}
168
169pub fn gamma_delta(qm: AcplQuantMode) -> f32 {
172 match qm {
173 AcplQuantMode::Fine => 1638.0 / 16384.0,
174 AcplQuantMode::Coarse => 3276.0 / 16384.0,
175 }
176}
177
178pub fn dequantize_alpha_index(qm: AcplQuantMode, alpha_q: i32) -> (f32, u8) {
187 match qm {
188 AcplQuantMode::Fine => {
189 let lane = (alpha_q + 16).clamp(0, 32) as usize;
190 (ALPHA_DQ_FINE[lane], IBETA_FINE[lane])
191 }
192 AcplQuantMode::Coarse => {
193 let lane = (alpha_q + 8).clamp(0, 16) as usize;
194 (ALPHA_DQ_COARSE[lane], IBETA_COARSE[lane])
195 }
196 }
197}
198
199pub fn dequantize_beta_index(qm: AcplQuantMode, beta_q: i32, ibeta: u8) -> f32 {
206 let mag = beta_q.unsigned_abs() as usize;
207 let val = match qm {
208 AcplQuantMode::Fine => {
209 let row = mag.min(8);
210 let col = (ibeta as usize).min(8);
211 BETA_DQ_FINE[row][col]
212 }
213 AcplQuantMode::Coarse => {
214 let row = mag.min(4);
215 let col = (ibeta as usize).min(4);
216 BETA_DQ_COARSE[row][col]
217 }
218 };
219 if beta_q < 0 {
220 -val
221 } else {
222 val
223 }
224}
225
226#[derive(Debug, Clone)]
237pub struct AcplDiffState {
238 pub q_prev: Vec<i32>,
242}
243
244impl AcplDiffState {
245 pub fn new() -> Self {
246 Self { q_prev: Vec::new() }
247 }
248
249 pub fn carry(&mut self, row: &[i32]) {
251 self.q_prev.clear();
252 self.q_prev.extend_from_slice(row);
253 }
254}
255
256impl Default for AcplDiffState {
257 fn default() -> Self {
258 Self::new()
259 }
260}
261
262pub fn differential_decode(
271 params: &[AcplHuffParam],
272 num_bands: u32,
273 state: &mut AcplDiffState,
274) -> Vec<Vec<i32>> {
275 let nb = num_bands as usize;
276 if state.q_prev.len() != nb {
277 state.q_prev = vec![0; nb];
278 }
279 let mut out = Vec::with_capacity(params.len());
280 for p in params {
281 let mut row = vec![0i32; nb];
285 if !p.direction_time {
286 if !p.values.is_empty() {
288 row[0] = p.values[0];
289 for i in 1..nb {
290 let d = p.values.get(i).copied().unwrap_or(0);
291 row[i] = row[i - 1] + d;
292 }
293 }
294 } else {
295 for i in 0..nb {
297 let d = p.values.get(i).copied().unwrap_or(0);
298 row[i] = state.q_prev[i] + d;
299 }
300 }
301 state.q_prev = row.clone();
302 out.push(row);
303 }
304 out
305}
306
307pub fn dequantize_alpha_beta(
319 alpha_q: &[Vec<i32>],
320 beta_q: &[Vec<i32>],
321 qm: AcplQuantMode,
322) -> (Vec<Vec<f32>>, Vec<Vec<f32>>) {
323 debug_assert_eq!(alpha_q.len(), beta_q.len());
324 let mut alpha_dq = Vec::with_capacity(alpha_q.len());
325 let mut beta_dq = Vec::with_capacity(beta_q.len());
326 for ps in 0..alpha_q.len() {
327 let n = alpha_q[ps].len();
328 let mut a_row = vec![0.0f32; n];
329 let mut b_row = vec![0.0f32; n];
330 for i in 0..n {
331 let (a_val, ibeta) = dequantize_alpha_index(qm, alpha_q[ps][i]);
332 a_row[i] = a_val;
333 let bq = beta_q[ps].get(i).copied().unwrap_or(0);
334 b_row[i] = dequantize_beta_index(qm, bq, ibeta);
335 }
336 alpha_dq.push(a_row);
337 beta_dq.push(b_row);
338 }
339 (alpha_dq, beta_dq)
340}
341
342pub fn dequantize_beta3(beta3_q: &[Vec<i32>], qm: AcplQuantMode) -> Vec<Vec<f32>> {
344 let delta = beta3_delta(qm);
345 beta3_q
346 .iter()
347 .map(|row| row.iter().map(|&q| (q as f32) * delta).collect())
348 .collect()
349}
350
351pub fn dequantize_gamma(gamma_q: &[Vec<i32>], qm: AcplQuantMode) -> Vec<Vec<f32>> {
353 let delta = gamma_delta(qm);
354 gamma_q
355 .iter()
356 .map(|row| row.iter().map(|&q| (q as f32) * delta).collect())
357 .collect()
358}
359
360#[derive(Debug, Clone)]
371pub struct InterpInputs<'a> {
372 pub by_pset: &'a [Vec<f32>],
375 pub prev: &'a [f32],
377}
378
379#[allow(clippy::too_many_arguments)]
386pub fn interpolate(
387 inputs: &InterpInputs<'_>,
388 num_pset: u32,
389 sb: u32,
390 ts: u32,
391 num_ts: u32,
392 interp_steep: bool,
393 param_timeslots: &[u8],
394) -> f32 {
395 let sb_idx = sb as usize;
396 if !interp_steep {
397 if num_pset == 1 {
399 let p = inputs.by_pset[0].get(sb_idx).copied().unwrap_or(0.0);
400 let prev = inputs.prev.get(sb_idx).copied().unwrap_or(0.0);
401 let delta = p - prev;
402 prev + ((ts + 1) as f32) * delta / (num_ts as f32)
403 } else {
404 let ts_2 = num_ts / 2;
406 let p0 = inputs.by_pset[0].get(sb_idx).copied().unwrap_or(0.0);
407 let p1 = inputs.by_pset[1].get(sb_idx).copied().unwrap_or(0.0);
408 if ts < ts_2 {
409 let prev = inputs.prev.get(sb_idx).copied().unwrap_or(0.0);
410 let delta = p0 - prev;
411 prev + ((ts + 1) as f32) * delta / (ts_2 as f32)
412 } else {
413 let delta = p1 - p0;
414 p0 + ((ts - ts_2 + 1) as f32) * delta / ((num_ts - ts_2) as f32)
415 }
416 }
417 } else {
418 if num_pset == 1 {
420 let bound = param_timeslots.first().copied().unwrap_or(0) as u32;
421 if ts < bound {
422 inputs.prev.get(sb_idx).copied().unwrap_or(0.0)
423 } else {
424 inputs.by_pset[0].get(sb_idx).copied().unwrap_or(0.0)
425 }
426 } else {
427 let bound0 = param_timeslots.first().copied().unwrap_or(0) as u32;
428 let bound1 = param_timeslots.get(1).copied().unwrap_or(0) as u32;
429 if ts < bound0 {
430 inputs.prev.get(sb_idx).copied().unwrap_or(0.0)
431 } else if ts < bound1 {
432 inputs.by_pset[0].get(sb_idx).copied().unwrap_or(0.0)
433 } else {
434 inputs.by_pset[1].get(sb_idx).copied().unwrap_or(0.0)
435 }
436 }
437 }
438}
439
440pub fn expand_pb_to_sb(pb_vals: &[Vec<f32>], num_param_bands: u32) -> Vec<Vec<f32>> {
444 pb_vals
445 .iter()
446 .map(|row| {
447 let mut out = vec![0.0f32; NUM_QMF_SUBBANDS];
448 for sb in 0..NUM_QMF_SUBBANDS {
449 let pb = sb_to_pb(sb as u32, num_param_bands) as usize;
450 out[sb] = row.get(pb).copied().unwrap_or(0.0);
451 }
452 out
453 })
454 .collect()
455}
456
457pub fn update_param_prev(prev: &mut Vec<f32>, last_set_sb: &[f32]) {
460 prev.clear();
461 prev.extend_from_slice(last_set_sb);
462 prev.resize(NUM_QMF_SUBBANDS, 0.0);
465}
466
467pub fn region_delay(sb: u32) -> usize {
474 match sb {
475 0..=6 => 7,
476 7..=22 => 10,
477 _ => 12,
478 }
479}
480
481pub fn region_filter_length(sb: u32) -> usize {
483 match sb {
484 0..=6 => 7,
485 7..=22 => 4,
486 _ => 2,
487 }
488}
489
490#[derive(Debug, Clone, Copy)]
492pub enum DecorrelatorId {
493 D0,
494 D1,
495 D2,
496}
497
498#[rustfmt::skip]
501pub const A_K0: [[f64; 8]; 3] = [
502 [1.0000, 0.5306, -0.4533, -0.6248, 0.0424, 0.4237, 0.4311, 0.1688],
504 [1.0000, -0.4178, 0.1082, -0.2368, -0.1014, -0.1052, -0.3528, 0.4665],
506 [1.0000, 0.4007, 0.4747, 0.2611, -0.1211, -0.4248, -0.2989, -0.1932],
508];
509
510#[rustfmt::skip]
513pub const A_K1: [[f64; 5]; 3] = [
514 [1.0000, 0.5561, -0.3039, -0.5024, -0.1850],
515 [1.0000, 0.0425, 0.3235, -0.1556, 0.4958],
516 [1.0000, -0.4361, 0.0345, 0.5215, -0.4178],
517];
518
519#[rustfmt::skip]
522pub const A_K2: [[f64; 3]; 3] = [
523 [1.0000, 0.5773, 0.3321],
524 [1.0000, 0.2327, -0.3901],
525 [1.0000, -0.6057, 0.3804],
526];
527
528pub fn region_coeffs(d: DecorrelatorId, sb: u32) -> &'static [f64] {
532 let col = match d {
533 DecorrelatorId::D0 => 0,
534 DecorrelatorId::D1 => 1,
535 DecorrelatorId::D2 => 2,
536 };
537 match sb {
538 0..=6 => &A_K0[col][..],
539 7..=22 => &A_K1[col][..],
540 _ => &A_K2[col][..],
541 }
542}
543
544#[derive(Debug, Clone)]
550pub struct InputSignalModifier {
551 pub which: DecorrelatorId,
553 pub x_hist: Vec<Vec<(f32, f32)>>,
556 pub y_hist: Vec<Vec<(f32, f32)>>,
559}
560
561impl InputSignalModifier {
562 pub fn new(which: DecorrelatorId) -> Self {
563 let depth = 24usize;
564 Self {
565 which,
566 x_hist: vec![vec![(0.0, 0.0); depth]; NUM_QMF_SUBBANDS],
567 y_hist: vec![vec![(0.0, 0.0); depth]; NUM_QMF_SUBBANDS],
568 }
569 }
570
571 pub fn reset(&mut self) {
573 for h in &mut self.x_hist {
574 for v in h {
575 *v = (0.0, 0.0);
576 }
577 }
578 for h in &mut self.y_hist {
579 for v in h {
580 *v = (0.0, 0.0);
581 }
582 }
583 }
584
585 pub fn process_sample(&mut self, sb: u32, x_in: (f32, f32)) -> (f32, f32) {
589 let sb_idx = sb as usize;
590 let delay = region_delay(sb);
591 let filter_length = region_filter_length(sb);
592 let a = region_coeffs(self.which, sb);
593 let xh = &mut self.x_hist[sb_idx];
595 xh.rotate_right(1);
596 xh[0] = x_in;
597 let yh = &mut self.y_hist[sb_idx];
598
599 let b0 = a[filter_length];
601 let a0 = a[0];
602 let xd = if delay < xh.len() {
603 xh[delay]
604 } else {
605 (0.0, 0.0)
606 };
607 let mut y_re = (b0 / a0) * xd.0 as f64;
608 let mut y_im = (b0 / a0) * xd.1 as f64;
609 for i in 1..=filter_length {
610 let bi = a[filter_length - i];
611 let xi_idx = i + delay;
612 let xi = if xi_idx < xh.len() {
613 xh[xi_idx]
614 } else {
615 (0.0, 0.0)
616 };
617 let yi = if i - 1 < yh.len() {
620 yh[i - 1]
621 } else {
622 (0.0, 0.0)
623 };
624 let ai = a[i];
625 y_re += (bi * xi.0 as f64 - ai * yi.0 as f64) / a0;
626 y_im += (bi * xi.1 as f64 - ai * yi.1 as f64) / a0;
627 }
628 let y_out = (y_re as f32, y_im as f32);
629 yh.rotate_right(1);
631 yh[0] = y_out;
632 y_out
633 }
634}
635
636#[derive(Debug, Clone)]
639pub struct Decorrelator {
640 pub d0: InputSignalModifier,
641 pub d1: InputSignalModifier,
642 pub d2: InputSignalModifier,
643}
644
645impl Decorrelator {
646 pub fn new() -> Self {
647 Self {
648 d0: InputSignalModifier::new(DecorrelatorId::D0),
649 d1: InputSignalModifier::new(DecorrelatorId::D1),
650 d2: InputSignalModifier::new(DecorrelatorId::D2),
651 }
652 }
653}
654
655impl Default for Decorrelator {
656 fn default() -> Self {
657 Self::new()
658 }
659}
660
661pub const DUCKER_ALPHA: f32 = 0.76592833836465;
667pub const DUCKER_ALPHA_SMOOTH: f32 = 0.25;
668pub const DUCKER_GAMMA: f32 = 1.5;
669pub const DUCKER_EPSILON: f32 = 1.0e-9;
670
671pub const ACPL_MAX_NUM_PARAM_BANDS: usize = 15;
673
674#[derive(Debug, Clone)]
676pub struct TransientDucker {
677 pub p_peak_decay_prev: [f32; ACPL_MAX_NUM_PARAM_BANDS],
678 pub p_smooth_prev: [f32; ACPL_MAX_NUM_PARAM_BANDS],
679 pub smooth_peak_diff_prev: [f32; ACPL_MAX_NUM_PARAM_BANDS],
680}
681
682impl TransientDucker {
683 pub fn new() -> Self {
684 Self {
685 p_peak_decay_prev: [0.0; ACPL_MAX_NUM_PARAM_BANDS],
686 p_smooth_prev: [0.0; ACPL_MAX_NUM_PARAM_BANDS],
687 smooth_peak_diff_prev: [0.0; ACPL_MAX_NUM_PARAM_BANDS],
688 }
689 }
690
691 pub fn reset(&mut self) {
693 *self = Self::new();
694 }
695
696 pub fn update(
699 &mut self,
700 p_energy: &[f32; ACPL_MAX_NUM_PARAM_BANDS],
701 ) -> [f32; ACPL_MAX_NUM_PARAM_BANDS] {
702 let mut duck = [1.0f32; ACPL_MAX_NUM_PARAM_BANDS];
703 for pb in 0..ACPL_MAX_NUM_PARAM_BANDS {
704 let p_peak_decay = if DUCKER_ALPHA * self.p_peak_decay_prev[pb] < p_energy[pb] {
705 p_energy[pb]
706 } else {
707 DUCKER_ALPHA * self.p_peak_decay_prev[pb]
708 };
709 let smooth = (1.0 - DUCKER_ALPHA_SMOOTH) * self.p_smooth_prev[pb]
710 + DUCKER_ALPHA_SMOOTH * p_energy[pb];
711 let smooth_peak_diff = (1.0 - DUCKER_ALPHA_SMOOTH) * self.smooth_peak_diff_prev[pb]
712 + DUCKER_ALPHA_SMOOTH * (p_peak_decay - p_energy[pb]);
713 let g = if DUCKER_GAMMA * smooth_peak_diff > smooth {
714 smooth / (DUCKER_GAMMA * (smooth_peak_diff + DUCKER_EPSILON))
715 } else {
716 1.0
717 };
718 duck[pb] = g;
719 self.p_peak_decay_prev[pb] = p_peak_decay;
720 self.p_smooth_prev[pb] = smooth;
721 self.smooth_peak_diff_prev[pb] = smooth_peak_diff;
722 }
723 duck
724 }
725}
726
727impl Default for TransientDucker {
728 fn default() -> Self {
729 Self::new()
730 }
731}
732
733pub fn compute_p_energy(
737 x: &[(f32, f32); NUM_QMF_SUBBANDS],
738 num_param_bands: u32,
739) -> [f32; ACPL_MAX_NUM_PARAM_BANDS] {
740 let mut e = [0.0f32; ACPL_MAX_NUM_PARAM_BANDS];
741 for sb in 0..NUM_QMF_SUBBANDS as u32 {
742 let pb = sb_to_pb(sb, num_param_bands) as usize;
743 let (re, im) = x[sb as usize];
744 e[pb] += re * re + im * im;
745 }
746 e
747}
748
749pub fn apply_transient_ducker(
751 x: &[(f32, f32); NUM_QMF_SUBBANDS],
752 duck_gain: &[f32; ACPL_MAX_NUM_PARAM_BANDS],
753 num_param_bands: u32,
754) -> [(f32, f32); NUM_QMF_SUBBANDS] {
755 let mut out = *x;
756 for sb in 0..NUM_QMF_SUBBANDS as u32 {
757 let pb = sb_to_pb(sb, num_param_bands) as usize;
758 let g = duck_gain[pb];
759 out[sb as usize].0 *= g;
760 out[sb as usize].1 *= g;
761 }
762 out
763}
764
765#[derive(Debug, Clone)]
773pub struct AcplCpeState {
774 pub alpha_prev_sb: Vec<f32>,
775 pub beta_prev_sb: Vec<f32>,
776 pub decorrelator: InputSignalModifier,
777 pub ducker: TransientDucker,
778}
779
780impl AcplCpeState {
781 pub fn new(which: DecorrelatorId) -> Self {
782 Self {
783 alpha_prev_sb: vec![0.0; NUM_QMF_SUBBANDS],
784 beta_prev_sb: vec![0.0; NUM_QMF_SUBBANDS],
785 decorrelator: InputSignalModifier::new(which),
786 ducker: TransientDucker::new(),
787 }
788 }
789}
790
791pub struct AcplCpeFrame<'a> {
793 pub x0: &'a [[(f32, f32); NUM_QMF_SUBBANDS]],
797 pub x1: Option<&'a [[(f32, f32); NUM_QMF_SUBBANDS]]>,
800 pub alpha_dq: &'a [Vec<f32>],
802 pub beta_dq: &'a [Vec<f32>],
804 pub num_param_bands: u32,
806 pub acpl_qmf_band: u32,
810 pub steep: bool,
812 pub param_timeslots: &'a [u8],
814}
815
816pub struct AcplCpeOutput {
818 pub z0: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>,
819 pub z1: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>,
820}
821
822pub fn acpl_module(
829 frame: &AcplCpeFrame<'_>,
830 y: &[[(f32, f32); NUM_QMF_SUBBANDS]],
831) -> AcplCpeOutput {
832 let num_ts = frame.x0.len();
833 debug_assert_eq!(y.len(), num_ts);
834 let num_pset = frame.alpha_dq.len() as u32;
835 let alpha_sb = expand_pb_to_sb(frame.alpha_dq, frame.num_param_bands);
836 let beta_sb = expand_pb_to_sb(frame.beta_dq, frame.num_param_bands);
837 let prev_alpha = vec![0.0f32; NUM_QMF_SUBBANDS];
839 let prev_beta = vec![0.0f32; NUM_QMF_SUBBANDS];
840 let alpha_inp = InterpInputs {
841 by_pset: &alpha_sb,
842 prev: &prev_alpha,
843 };
844 let beta_inp = InterpInputs {
845 by_pset: &beta_sb,
846 prev: &prev_beta,
847 };
848
849 let zero_col = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
850 let mut z0_out = Vec::with_capacity(num_ts);
851 let mut z1_out = Vec::with_capacity(num_ts);
852 for ts in 0..num_ts {
853 let x0_col = frame.x0[ts];
854 let x1_col = match frame.x1 {
855 Some(matrix) => matrix[ts],
856 None => zero_col,
857 };
858 let y_col = y[ts];
859 let mut z0_col = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
860 let mut z1_col = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
861 for sb in 0..NUM_QMF_SUBBANDS as u32 {
862 let interp_a = interpolate(
863 &alpha_inp,
864 num_pset,
865 sb,
866 ts as u32,
867 num_ts as u32,
868 frame.steep,
869 frame.param_timeslots,
870 );
871 let interp_b = interpolate(
872 &beta_inp,
873 num_pset,
874 sb,
875 ts as u32,
876 num_ts as u32,
877 frame.steep,
878 frame.param_timeslots,
879 );
880 let sb_i = sb as usize;
881 if sb < frame.acpl_qmf_band {
882 let (x0r, x0i) = x0_col[sb_i];
883 let (x1r, x1i) = x1_col[sb_i];
884 z0_col[sb_i] = (0.5 * (x0r + x1r), 0.5 * (x0i + x1i));
885 z1_col[sb_i] = (0.5 * (x0r - x1r), 0.5 * (x0i - x1i));
886 } else {
887 let (x0r, x0i) = x0_col[sb_i];
888 let (yr, yi) = y_col[sb_i];
889 let plus_a = 1.0 + interp_a;
890 let minus_a = 1.0 - interp_a;
891 z0_col[sb_i] = (
892 0.5 * (x0r * plus_a + yr * interp_b),
893 0.5 * (x0i * plus_a + yi * interp_b),
894 );
895 z1_col[sb_i] = (
896 0.5 * (x0r * minus_a - yr * interp_b),
897 0.5 * (x0i * minus_a - yi * interp_b),
898 );
899 }
900 }
901 z0_out.push(z0_col);
902 z1_out.push(z1_col);
903 }
904 AcplCpeOutput {
905 z0: z0_out,
906 z1: z1_out,
907 }
908}
909
910pub fn run_pseudocode_115_pair(state: &mut AcplCpeState, frame: AcplCpeFrame<'_>) -> AcplCpeOutput {
917 let num_ts = frame.x0.len();
919 let mut x0in = Vec::with_capacity(num_ts);
920 for ts in 0..num_ts {
921 let mut col = frame.x0[ts];
922 for sb in 0..NUM_QMF_SUBBANDS {
923 col[sb].0 *= 2.0;
924 col[sb].1 *= 2.0;
925 }
926 x0in.push(col);
927 }
928 let mut u0 = Vec::with_capacity(num_ts);
930 for ts in 0..num_ts {
931 let mut col = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
932 for sb in 0..NUM_QMF_SUBBANDS as u32 {
933 col[sb as usize] = state.decorrelator.process_sample(sb, x0in[ts][sb as usize]);
934 }
935 u0.push(col);
936 }
937 let mut y0 = Vec::with_capacity(num_ts);
939 for ts in 0..num_ts {
940 let p_energy = compute_p_energy(&u0[ts], frame.num_param_bands);
941 let duck = state.ducker.update(&p_energy);
942 y0.push(apply_transient_ducker(
943 &u0[ts],
944 &duck,
945 frame.num_param_bands,
946 ));
947 }
948 let mut x1in_owned: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>;
951 let inner_x1: Option<&[[(f32, f32); NUM_QMF_SUBBANDS]]> = if let Some(x1) = frame.x1 {
952 x1in_owned = Vec::with_capacity(num_ts);
953 for ts in 0..num_ts {
954 let mut col = x1[ts];
955 for sb in 0..NUM_QMF_SUBBANDS {
956 col[sb].0 *= 2.0;
957 col[sb].1 *= 2.0;
958 }
959 x1in_owned.push(col);
960 }
961 Some(x1in_owned.as_slice())
962 } else {
963 None
964 };
965 let inner_frame = AcplCpeFrame {
966 x0: &x0in,
967 x1: inner_x1,
968 alpha_dq: frame.alpha_dq,
969 beta_dq: frame.beta_dq,
970 num_param_bands: frame.num_param_bands,
971 acpl_qmf_band: frame.acpl_qmf_band,
972 steep: frame.steep,
973 param_timeslots: frame.param_timeslots,
974 };
975 let out = acpl_module(&inner_frame, &y0);
976 if !frame.alpha_dq.is_empty() {
979 let last_idx = frame.alpha_dq.len() - 1;
980 let alpha_sb = expand_pb_to_sb(frame.alpha_dq, frame.num_param_bands);
981 let beta_sb = expand_pb_to_sb(frame.beta_dq, frame.num_param_bands);
982 update_param_prev(&mut state.alpha_prev_sb, &alpha_sb[last_idx]);
983 update_param_prev(&mut state.beta_prev_sb, &beta_sb[last_idx]);
984 }
985 out
986}
987
988pub type AcplQmfMatrix = Vec<[(f32, f32); NUM_QMF_SUBBANDS]>;
995
996#[allow(clippy::too_many_arguments)]
1015pub fn transform(
1016 x0: &[[(f32, f32); NUM_QMF_SUBBANDS]],
1017 x1: &[[(f32, f32); NUM_QMF_SUBBANDS]],
1018 g1_pb: &[Vec<f32>],
1019 g2_pb: &[Vec<f32>],
1020 num_param_bands: u32,
1021 prev_g1: &[f32],
1022 prev_g2: &[f32],
1023 steep: bool,
1024 param_timeslots: &[u8],
1025) -> Vec<[(f32, f32); NUM_QMF_SUBBANDS]> {
1026 let num_ts = x0.len();
1027 debug_assert_eq!(x1.len(), num_ts);
1028 let num_pset = g1_pb.len() as u32;
1029 let g1_sb = expand_pb_to_sb(g1_pb, num_param_bands);
1030 let g2_sb = expand_pb_to_sb(g2_pb, num_param_bands);
1031 let g1_inp = InterpInputs {
1032 by_pset: &g1_sb,
1033 prev: prev_g1,
1034 };
1035 let g2_inp = InterpInputs {
1036 by_pset: &g2_sb,
1037 prev: prev_g2,
1038 };
1039 let mut out = Vec::with_capacity(num_ts);
1040 for ts in 0..num_ts {
1041 let mut v_col = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
1042 for sb in 0..NUM_QMF_SUBBANDS as u32 {
1043 let g1 = interpolate(
1044 &g1_inp,
1045 num_pset,
1046 sb,
1047 ts as u32,
1048 num_ts as u32,
1049 steep,
1050 param_timeslots,
1051 );
1052 let g2 = interpolate(
1053 &g2_inp,
1054 num_pset,
1055 sb,
1056 ts as u32,
1057 num_ts as u32,
1058 steep,
1059 param_timeslots,
1060 );
1061 let (x0r, x0i) = x0[ts][sb as usize];
1062 let (x1r, x1i) = x1[ts][sb as usize];
1063 v_col[sb as usize] = (x0r * g1 + x1r * g2, x0i * g1 + x1i * g2);
1064 }
1065 out.push(v_col);
1066 }
1067 out
1068}
1069
1070#[allow(clippy::too_many_arguments)]
1091pub fn acpl_module2(
1092 x0: &[[(f32, f32); NUM_QMF_SUBBANDS]],
1093 x1: &[[(f32, f32); NUM_QMF_SUBBANDS]],
1094 y: &[[(f32, f32); NUM_QMF_SUBBANDS]],
1095 g1_pb: &[Vec<f32>],
1096 g2_pb: &[Vec<f32>],
1097 g1a_pb: &[Vec<f32>],
1098 g2a_pb: &[Vec<f32>],
1099 b_pb: &[Vec<f32>],
1100 num_param_bands: u32,
1101 steep: bool,
1102 param_timeslots: &[u8],
1103) -> (AcplQmfMatrix, AcplQmfMatrix) {
1104 let num_ts = x0.len();
1105 debug_assert_eq!(x1.len(), num_ts);
1106 debug_assert_eq!(y.len(), num_ts);
1107 let num_pset = g1_pb.len() as u32;
1108 let g1_sb = expand_pb_to_sb(g1_pb, num_param_bands);
1109 let g2_sb = expand_pb_to_sb(g2_pb, num_param_bands);
1110 let g1a_sb = expand_pb_to_sb(g1a_pb, num_param_bands);
1111 let g2a_sb = expand_pb_to_sb(g2a_pb, num_param_bands);
1112 let b_sb = expand_pb_to_sb(b_pb, num_param_bands);
1113 let zero_prev = vec![0.0f32; NUM_QMF_SUBBANDS];
1114 let g1_inp = InterpInputs {
1115 by_pset: &g1_sb,
1116 prev: &zero_prev,
1117 };
1118 let g2_inp = InterpInputs {
1119 by_pset: &g2_sb,
1120 prev: &zero_prev,
1121 };
1122 let g1a_inp = InterpInputs {
1123 by_pset: &g1a_sb,
1124 prev: &zero_prev,
1125 };
1126 let g2a_inp = InterpInputs {
1127 by_pset: &g2a_sb,
1128 prev: &zero_prev,
1129 };
1130 let b_inp = InterpInputs {
1131 by_pset: &b_sb,
1132 prev: &zero_prev,
1133 };
1134
1135 let mut z0_out = Vec::with_capacity(num_ts);
1136 let mut z1_out = Vec::with_capacity(num_ts);
1137 for ts in 0..num_ts {
1138 let mut z0_col = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
1139 let mut z1_col = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
1140 for sb in 0..NUM_QMF_SUBBANDS as u32 {
1141 let g1 = interpolate(
1142 &g1_inp,
1143 num_pset,
1144 sb,
1145 ts as u32,
1146 num_ts as u32,
1147 steep,
1148 param_timeslots,
1149 );
1150 let g2 = interpolate(
1151 &g2_inp,
1152 num_pset,
1153 sb,
1154 ts as u32,
1155 num_ts as u32,
1156 steep,
1157 param_timeslots,
1158 );
1159 let g1a = interpolate(
1160 &g1a_inp,
1161 num_pset,
1162 sb,
1163 ts as u32,
1164 num_ts as u32,
1165 steep,
1166 param_timeslots,
1167 );
1168 let g2a = interpolate(
1169 &g2a_inp,
1170 num_pset,
1171 sb,
1172 ts as u32,
1173 num_ts as u32,
1174 steep,
1175 param_timeslots,
1176 );
1177 let b = interpolate(
1178 &b_inp,
1179 num_pset,
1180 sb,
1181 ts as u32,
1182 num_ts as u32,
1183 steep,
1184 param_timeslots,
1185 );
1186 let sb_i = sb as usize;
1187 let (x0r, x0i) = x0[ts][sb_i];
1188 let (x1r, x1i) = x1[ts][sb_i];
1189 let (yr, yi) = y[ts][sb_i];
1190 z0_col[sb_i] = (
1191 0.5 * (x0r * (g1 + g1a) + x1r * (g2 + g2a) + yr * b),
1192 0.5 * (x0i * (g1 + g1a) + x1i * (g2 + g2a) + yi * b),
1193 );
1194 z1_col[sb_i] = (
1195 0.5 * (x0r * (g1 - g1a) + x1r * (g2 - g2a) - yr * b),
1196 0.5 * (x0i * (g1 - g1a) + x1i * (g2 - g2a) - yi * b),
1197 );
1198 }
1199 z0_out.push(z0_col);
1200 z1_out.push(z1_col);
1201 }
1202 (z0_out, z1_out)
1203}
1204
1205#[allow(clippy::too_many_arguments)]
1221pub fn acpl_module3(
1222 z0: &mut [[(f32, f32); NUM_QMF_SUBBANDS]],
1223 z1: &mut [[(f32, f32); NUM_QMF_SUBBANDS]],
1224 y2: &[[(f32, f32); NUM_QMF_SUBBANDS]],
1225 b3_pb: &[Vec<f32>],
1226 b3a_pb: &[Vec<f32>],
1227 num_param_bands: u32,
1228 steep: bool,
1229 param_timeslots: &[u8],
1230) {
1231 let num_ts = z0.len();
1232 debug_assert_eq!(z1.len(), num_ts);
1233 debug_assert_eq!(y2.len(), num_ts);
1234 let num_pset = b3_pb.len() as u32;
1235 let b3_sb = expand_pb_to_sb(b3_pb, num_param_bands);
1236 let b3a_sb = expand_pb_to_sb(b3a_pb, num_param_bands);
1237 let zero_prev = vec![0.0f32; NUM_QMF_SUBBANDS];
1238 let b3_inp = InterpInputs {
1239 by_pset: &b3_sb,
1240 prev: &zero_prev,
1241 };
1242 let b3a_inp = InterpInputs {
1243 by_pset: &b3a_sb,
1244 prev: &zero_prev,
1245 };
1246 for ts in 0..num_ts {
1247 for sb in 0..NUM_QMF_SUBBANDS as u32 {
1248 let b3 = interpolate(
1249 &b3_inp,
1250 num_pset,
1251 sb,
1252 ts as u32,
1253 num_ts as u32,
1254 steep,
1255 param_timeslots,
1256 );
1257 let b3a = interpolate(
1258 &b3a_inp,
1259 num_pset,
1260 sb,
1261 ts as u32,
1262 num_ts as u32,
1263 steep,
1264 param_timeslots,
1265 );
1266 let sb_i = sb as usize;
1267 let (yr, yi) = y2[ts][sb_i];
1268 z0[ts][sb_i].0 += 0.25 * yr * (b3 + b3a);
1269 z0[ts][sb_i].1 += 0.25 * yi * (b3 + b3a);
1270 z1[ts][sb_i].0 += 0.25 * yr * (b3 - b3a);
1271 z1[ts][sb_i].1 += 0.25 * yi * (b3 - b3a);
1272 }
1273 }
1274}
1275
1276fn pb_matrix_mul(a: &[Vec<f32>], b: &[Vec<f32>]) -> Vec<Vec<f32>> {
1280 debug_assert_eq!(a.len(), b.len());
1281 a.iter()
1282 .zip(b.iter())
1283 .map(|(ar, br)| {
1284 let n = ar.len().min(br.len());
1285 let mut row = Vec::with_capacity(n);
1286 for i in 0..n {
1287 row.push(ar[i] * br[i]);
1288 }
1289 row
1290 })
1291 .collect()
1292}
1293
1294fn pb_matrix_sum3(a: &[Vec<f32>], b: &[Vec<f32>], c: &[Vec<f32>]) -> Vec<Vec<f32>> {
1298 debug_assert_eq!(a.len(), b.len());
1299 debug_assert_eq!(a.len(), c.len());
1300 a.iter()
1301 .zip(b.iter())
1302 .zip(c.iter())
1303 .map(|((ar, br), cr)| {
1304 let n = ar.len().min(br.len()).min(cr.len());
1305 let mut row = Vec::with_capacity(n);
1306 for i in 0..n {
1307 row.push(ar[i] + br[i] + cr[i]);
1308 }
1309 row
1310 })
1311 .collect()
1312}
1313
1314fn pb_matrix_scale(a: &[Vec<f32>], s: f32) -> Vec<Vec<f32>> {
1316 a.iter()
1317 .map(|row| row.iter().map(|&v| v * s).collect())
1318 .collect()
1319}
1320
1321#[derive(Debug, Clone)]
1326pub struct AcplMchState {
1327 pub d0: InputSignalModifier,
1328 pub d1: InputSignalModifier,
1329 pub d2: InputSignalModifier,
1330 pub ducker0: TransientDucker,
1331 pub ducker1: TransientDucker,
1332 pub ducker2: TransientDucker,
1333 pub g1_prev_sb: Vec<f32>,
1335 pub g2_prev_sb: Vec<f32>,
1336 pub g3_prev_sb: Vec<f32>,
1337 pub g4_prev_sb: Vec<f32>,
1338}
1339
1340impl AcplMchState {
1341 pub fn new() -> Self {
1342 Self {
1343 d0: InputSignalModifier::new(DecorrelatorId::D0),
1344 d1: InputSignalModifier::new(DecorrelatorId::D1),
1345 d2: InputSignalModifier::new(DecorrelatorId::D2),
1346 ducker0: TransientDucker::new(),
1347 ducker1: TransientDucker::new(),
1348 ducker2: TransientDucker::new(),
1349 g1_prev_sb: vec![0.0; NUM_QMF_SUBBANDS],
1350 g2_prev_sb: vec![0.0; NUM_QMF_SUBBANDS],
1351 g3_prev_sb: vec![0.0; NUM_QMF_SUBBANDS],
1352 g4_prev_sb: vec![0.0; NUM_QMF_SUBBANDS],
1353 }
1354 }
1355}
1356
1357impl Default for AcplMchState {
1358 fn default() -> Self {
1359 Self::new()
1360 }
1361}
1362
1363pub struct AcplMchFrame<'a> {
1369 pub x0: &'a [[(f32, f32); NUM_QMF_SUBBANDS]],
1371 pub x1: &'a [[(f32, f32); NUM_QMF_SUBBANDS]],
1373 pub x2: &'a [[(f32, f32); NUM_QMF_SUBBANDS]],
1375 pub alpha_1_dq: &'a [Vec<f32>],
1377 pub alpha_2_dq: &'a [Vec<f32>],
1379 pub beta_1_dq: &'a [Vec<f32>],
1381 pub beta_2_dq: &'a [Vec<f32>],
1383 pub beta_3_dq: &'a [Vec<f32>],
1386 pub g1_dq: &'a [Vec<f32>],
1388 pub g2_dq: &'a [Vec<f32>],
1389 pub g3_dq: &'a [Vec<f32>],
1390 pub g4_dq: &'a [Vec<f32>],
1391 pub g5_dq: &'a [Vec<f32>],
1392 pub g6_dq: &'a [Vec<f32>],
1393 pub num_param_bands: u32,
1394 pub steep: bool,
1395 pub param_timeslots: &'a [u8],
1396}
1397
1398pub struct AcplMchOutput {
1401 pub z0: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z2: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z4: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z1: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z3: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, }
1407
1408pub fn run_pseudocode_118_5x(state: &mut AcplMchState, frame: AcplMchFrame<'_>) -> AcplMchOutput {
1436 let num_ts = frame.x0.len();
1437 debug_assert_eq!(frame.x1.len(), num_ts);
1438 debug_assert_eq!(frame.x2.len(), num_ts);
1439
1440 let scale = 1.0 + 2.0 * (0.5f32).sqrt();
1443 let scale_x = |x: &[[(f32, f32); NUM_QMF_SUBBANDS]]| -> Vec<[(f32, f32); NUM_QMF_SUBBANDS]> {
1444 x.iter()
1445 .map(|col| {
1446 let mut out = *col;
1447 for sb in 0..NUM_QMF_SUBBANDS {
1448 out[sb].0 *= scale;
1449 out[sb].1 *= scale;
1450 }
1451 out
1452 })
1453 .collect()
1454 };
1455 let x0in = scale_x(frame.x0);
1456 let x1in = scale_x(frame.x1);
1457
1458 let g_sum_1 = pb_matrix_sum3(frame.g1_dq, frame.g3_dq, frame.g5_dq);
1460 let g_sum_2 = pb_matrix_sum3(frame.g2_dq, frame.g4_dq, frame.g6_dq);
1461 let v1 = transform(
1462 &x0in,
1463 &x1in,
1464 frame.g1_dq,
1465 frame.g2_dq,
1466 frame.num_param_bands,
1467 &state.g1_prev_sb,
1468 &state.g2_prev_sb,
1469 frame.steep,
1470 frame.param_timeslots,
1471 );
1472 let v2 = transform(
1473 &x0in,
1474 &x1in,
1475 frame.g3_dq,
1476 frame.g4_dq,
1477 frame.num_param_bands,
1478 &state.g3_prev_sb,
1479 &state.g4_prev_sb,
1480 frame.steep,
1481 frame.param_timeslots,
1482 );
1483 let v3 = transform(
1484 &x0in,
1485 &x1in,
1486 &g_sum_1,
1487 &g_sum_2,
1488 frame.num_param_bands,
1489 &vec![0.0; NUM_QMF_SUBBANDS],
1490 &vec![0.0; NUM_QMF_SUBBANDS],
1491 frame.steep,
1492 frame.param_timeslots,
1493 );
1494
1495 let mut u0 = Vec::with_capacity(num_ts);
1497 let mut u1 = Vec::with_capacity(num_ts);
1498 let mut u2 = Vec::with_capacity(num_ts);
1499 for ts in 0..num_ts {
1500 let mut col0 = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
1501 let mut col1 = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
1502 let mut col2 = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
1503 for sb in 0..NUM_QMF_SUBBANDS as u32 {
1504 col0[sb as usize] = state.d0.process_sample(sb, v1[ts][sb as usize]);
1505 col1[sb as usize] = state.d1.process_sample(sb, v2[ts][sb as usize]);
1506 col2[sb as usize] = state.d2.process_sample(sb, v3[ts][sb as usize]);
1507 }
1508 u0.push(col0);
1509 u1.push(col1);
1510 u2.push(col2);
1511 }
1512
1513 let apply_ducker = |u: &[[(f32, f32); NUM_QMF_SUBBANDS]],
1515 ducker: &mut TransientDucker|
1516 -> Vec<[(f32, f32); NUM_QMF_SUBBANDS]> {
1517 u.iter()
1518 .map(|col| {
1519 let p_energy = compute_p_energy(col, frame.num_param_bands);
1520 let duck = ducker.update(&p_energy);
1521 apply_transient_ducker(col, &duck, frame.num_param_bands)
1522 })
1523 .collect()
1524 };
1525 let y0 = apply_ducker(&u0, &mut state.ducker0);
1526 let y1 = apply_ducker(&u1, &mut state.ducker1);
1527 let y2 = apply_ducker(&u2, &mut state.ducker2);
1528
1529 let g1_a1 = pb_matrix_mul(frame.g1_dq, frame.alpha_1_dq);
1533 let g2_a1 = pb_matrix_mul(frame.g2_dq, frame.alpha_1_dq);
1534 let (mut z0, mut z1) = acpl_module2(
1535 &x0in,
1536 &x1in,
1537 &y0,
1538 frame.g1_dq,
1539 frame.g2_dq,
1540 &g1_a1,
1541 &g2_a1,
1542 frame.beta_1_dq,
1543 frame.num_param_bands,
1544 frame.steep,
1545 frame.param_timeslots,
1546 );
1547
1548 let g3_a2 = pb_matrix_mul(frame.g3_dq, frame.alpha_2_dq);
1550 let g4_a2 = pb_matrix_mul(frame.g4_dq, frame.alpha_2_dq);
1551 let (mut z2, mut z3) = acpl_module2(
1552 &x0in,
1553 &x1in,
1554 &y1,
1555 frame.g3_dq,
1556 frame.g4_dq,
1557 &g3_a2,
1558 &g4_a2,
1559 frame.beta_2_dq,
1560 frame.num_param_bands,
1561 frame.steep,
1562 frame.param_timeslots,
1563 );
1564
1565 let zero_y = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
1568 let zero_pb: Vec<Vec<f32>> = frame
1570 .g5_dq
1571 .iter()
1572 .map(|row| vec![0.0f32; row.len()])
1573 .collect();
1574 let (mut z4, _z5) = acpl_module2(
1575 &x0in,
1576 &x1in,
1577 &zero_y,
1578 frame.g5_dq,
1579 frame.g6_dq,
1580 frame.g5_dq, frame.g6_dq, &zero_pb,
1583 frame.num_param_bands,
1584 frame.steep,
1585 frame.param_timeslots,
1586 );
1587 let b3_a1 = pb_matrix_mul(frame.beta_3_dq, frame.alpha_1_dq);
1592 acpl_module3(
1593 &mut z0,
1594 &mut z1,
1595 &y2,
1596 frame.beta_3_dq,
1597 &b3_a1,
1598 frame.num_param_bands,
1599 frame.steep,
1600 frame.param_timeslots,
1601 );
1602
1603 let b3_a2 = pb_matrix_mul(frame.beta_3_dq, frame.alpha_2_dq);
1605 acpl_module3(
1606 &mut z2,
1607 &mut z3,
1608 &y2,
1609 frame.beta_3_dq,
1610 &b3_a2,
1611 frame.num_param_bands,
1612 frame.steep,
1613 frame.param_timeslots,
1614 );
1615
1616 let neg_b3 = pb_matrix_scale(frame.beta_3_dq, -1.0);
1620 let neg_b3_a = pb_matrix_scale(frame.beta_3_dq, -1.0); let mut z5_dummy = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
1622 acpl_module3(
1623 &mut z4,
1624 &mut z5_dummy,
1625 &y2,
1626 &neg_b3,
1627 &neg_b3_a,
1628 frame.num_param_bands,
1629 frame.steep,
1630 frame.param_timeslots,
1631 );
1632
1633 let sq2 = (2.0f32).sqrt();
1635 let scale_inplace = |z: &mut [[(f32, f32); NUM_QMF_SUBBANDS]], s: f32| {
1636 for col in z.iter_mut() {
1637 for sb in 0..NUM_QMF_SUBBANDS {
1638 col[sb].0 *= s;
1639 col[sb].1 *= s;
1640 }
1641 }
1642 };
1643 scale_inplace(&mut z1, sq2);
1644 scale_inplace(&mut z3, sq2);
1645 scale_inplace(&mut z4, sq2);
1646
1647 let update_prev = |prev: &mut Vec<f32>, src_pb: &[Vec<f32>]| {
1651 if !src_pb.is_empty() {
1652 let last = &src_pb[src_pb.len() - 1];
1653 let sb = expand_pb_to_sb(std::slice::from_ref(last), frame.num_param_bands);
1654 update_param_prev(prev, &sb[0]);
1655 }
1656 };
1657 update_prev(&mut state.g1_prev_sb, frame.g1_dq);
1658 update_prev(&mut state.g2_prev_sb, frame.g2_dq);
1659 update_prev(&mut state.g3_prev_sb, frame.g3_dq);
1660 update_prev(&mut state.g4_prev_sb, frame.g4_dq);
1661
1662 AcplMchOutput { z0, z2, z4, z1, z3 }
1663}
1664
1665#[derive(Debug, Clone)]
1674pub struct Acpl5xPairState {
1675 pub left_pair: AcplCpeState,
1678 pub right_pair: AcplCpeState,
1681 pub alpha1_diff: AcplDiffState,
1684 pub beta1_diff: AcplDiffState,
1685 pub alpha2_diff: AcplDiffState,
1688 pub beta2_diff: AcplDiffState,
1689}
1690
1691impl Acpl5xPairState {
1692 pub fn new() -> Self {
1693 Self {
1694 left_pair: AcplCpeState::new(DecorrelatorId::D0),
1695 right_pair: AcplCpeState::new(DecorrelatorId::D1),
1696 alpha1_diff: AcplDiffState::new(),
1697 beta1_diff: AcplDiffState::new(),
1698 alpha2_diff: AcplDiffState::new(),
1699 beta2_diff: AcplDiffState::new(),
1700 }
1701 }
1702}
1703
1704impl Default for Acpl5xPairState {
1705 fn default() -> Self {
1706 Self::new()
1707 }
1708}
1709
1710#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1714pub enum Acpl5xPairMode {
1715 AspxAcpl1,
1718 AspxAcpl2,
1721}
1722
1723pub struct Acpl5xPairFrame<'a> {
1737 pub mode: Acpl5xPairMode,
1738 pub x0: &'a [[(f32, f32); NUM_QMF_SUBBANDS]],
1739 pub x1: &'a [[(f32, f32); NUM_QMF_SUBBANDS]],
1740 pub x2: &'a [[(f32, f32); NUM_QMF_SUBBANDS]],
1741 pub x3: Option<&'a [[(f32, f32); NUM_QMF_SUBBANDS]]>,
1742 pub x4: Option<&'a [[(f32, f32); NUM_QMF_SUBBANDS]]>,
1743 pub alpha_1_dq: &'a [Vec<f32>],
1746 pub beta_1_dq: &'a [Vec<f32>],
1747 pub alpha_2_dq: &'a [Vec<f32>],
1750 pub beta_2_dq: &'a [Vec<f32>],
1751 pub num_param_bands: u32,
1752 pub acpl_qmf_band: u32,
1756 pub steep_1: bool,
1757 pub steep_2: bool,
1758 pub param_timeslots_1: &'a [u8],
1759 pub param_timeslots_2: &'a [u8],
1760}
1761
1762pub struct Acpl5xPairOutput {
1766 pub z0: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z1: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z2: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z3: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, pub z4: Vec<[(f32, f32); NUM_QMF_SUBBANDS]>, }
1772
1773pub fn run_pseudocode_117_5x(
1804 state: &mut Acpl5xPairState,
1805 frame: Acpl5xPairFrame<'_>,
1806) -> Acpl5xPairOutput {
1807 let num_ts = frame.x0.len();
1808 debug_assert_eq!(frame.x1.len(), num_ts);
1809 debug_assert_eq!(frame.x2.len(), num_ts);
1810
1811 let pair1_x1 = match frame.mode {
1814 Acpl5xPairMode::AspxAcpl1 => frame.x3,
1815 Acpl5xPairMode::AspxAcpl2 => None,
1816 };
1817 let pair1 = AcplCpeFrame {
1818 x0: frame.x0,
1819 x1: pair1_x1,
1820 alpha_dq: frame.alpha_1_dq,
1821 beta_dq: frame.beta_1_dq,
1822 num_param_bands: frame.num_param_bands,
1823 acpl_qmf_band: frame.acpl_qmf_band,
1824 steep: frame.steep_1,
1825 param_timeslots: frame.param_timeslots_1,
1826 };
1827 let out1 = run_pseudocode_115_pair(&mut state.left_pair, pair1);
1828
1829 let pair2_x1 = match frame.mode {
1832 Acpl5xPairMode::AspxAcpl1 => frame.x4,
1833 Acpl5xPairMode::AspxAcpl2 => None,
1834 };
1835 let pair2 = AcplCpeFrame {
1836 x0: frame.x1,
1837 x1: pair2_x1,
1838 alpha_dq: frame.alpha_2_dq,
1839 beta_dq: frame.beta_2_dq,
1840 num_param_bands: frame.num_param_bands,
1841 acpl_qmf_band: frame.acpl_qmf_band,
1842 steep: frame.steep_2,
1843 param_timeslots: frame.param_timeslots_2,
1844 };
1845 let out2 = run_pseudocode_115_pair(&mut state.right_pair, pair2);
1846
1847 let sq2 = (2.0f32).sqrt();
1850 let scale_inplace = |z: &mut [[(f32, f32); NUM_QMF_SUBBANDS]], s: f32| {
1851 for col in z.iter_mut() {
1852 for sb in 0..NUM_QMF_SUBBANDS {
1853 col[sb].0 *= s;
1854 col[sb].1 *= s;
1855 }
1856 }
1857 };
1858 let mut z0 = out1.z0;
1859 let mut z1 = out1.z1;
1860 let mut z2 = out2.z0;
1861 let mut z3 = out2.z1;
1862 scale_inplace(&mut z1, sq2);
1863 scale_inplace(&mut z3, sq2);
1864
1865 let z4: Vec<[(f32, f32); NUM_QMF_SUBBANDS]> = frame.x2.to_vec();
1867
1868 let _ = (&mut z0, &mut z2);
1870
1871 Acpl5xPairOutput { z0, z1, z2, z3, z4 }
1872}
1873
1874use crate::acpl::{AcplConfig1ch, AcplData1ch, AcplInterpolationType};
1879use crate::qmf::{QmfAnalysisBank, QmfSynthesisBank};
1880
1881#[derive(Debug, Clone)]
1885pub struct AcplSubstreamState {
1886 pub alpha_diff: AcplDiffState,
1887 pub beta_diff: AcplDiffState,
1888 pub cpe: AcplCpeState,
1889}
1890
1891impl AcplSubstreamState {
1892 pub fn new() -> Self {
1893 Self {
1894 alpha_diff: AcplDiffState::new(),
1895 beta_diff: AcplDiffState::new(),
1896 cpe: AcplCpeState::new(DecorrelatorId::D0),
1897 }
1898 }
1899}
1900
1901impl Default for AcplSubstreamState {
1902 fn default() -> Self {
1903 Self::new()
1904 }
1905}
1906
1907pub fn run_acpl_1ch_pcm(
1923 pcm_in: &[f32],
1924 cfg: &AcplConfig1ch,
1925 data: &AcplData1ch,
1926 state: &mut AcplSubstreamState,
1927) -> Option<(Vec<f32>, Vec<f32>)> {
1928 if pcm_in.is_empty() || pcm_in.len() % NUM_QMF_SUBBANDS != 0 {
1929 return None;
1930 }
1931 let n_slots = pcm_in.len() / NUM_QMF_SUBBANDS;
1932 if n_slots == 0 {
1933 return None;
1934 }
1935 let mut ana = QmfAnalysisBank::new();
1938 let x0 = ana.process_block(pcm_in);
1939 let alpha_q = differential_decode(&data.alpha1, cfg.num_param_bands, &mut state.alpha_diff);
1941 let beta_q = differential_decode(&data.beta1, cfg.num_param_bands, &mut state.beta_diff);
1942 let (alpha_dq, beta_dq) = dequantize_alpha_beta(&alpha_q, &beta_q, cfg.quant_mode);
1943 if alpha_dq.is_empty() {
1944 return None;
1945 }
1946 let frame = AcplCpeFrame {
1949 x0: &x0,
1950 x1: None,
1951 alpha_dq: &alpha_dq,
1952 beta_dq: &beta_dq,
1953 num_param_bands: cfg.num_param_bands,
1954 acpl_qmf_band: cfg.qmf_band as u32,
1955 steep: matches!(
1956 data.framing.interpolation_type,
1957 AcplInterpolationType::Steep
1958 ),
1959 param_timeslots: &data.framing.param_timeslots,
1960 };
1961 let out = run_pseudocode_115_pair(&mut state.cpe, frame);
1962 let mut syn0 = QmfSynthesisBank::new();
1964 let mut syn1 = QmfSynthesisBank::new();
1965 let mut left = Vec::with_capacity(pcm_in.len());
1966 let mut right = Vec::with_capacity(pcm_in.len());
1967 for ts in 0..n_slots {
1968 left.extend_from_slice(&syn0.process_slot(&out.z0[ts]));
1969 right.extend_from_slice(&syn1.process_slot(&out.z1[ts]));
1970 }
1971 Some((left, right))
1972}
1973
1974pub fn run_acpl_1ch_pcm_stereo(
1993 pcm_m: &[f32],
1994 pcm_s: &[f32],
1995 cfg: &AcplConfig1ch,
1996 data: &AcplData1ch,
1997 state: &mut AcplSubstreamState,
1998) -> Option<(Vec<f32>, Vec<f32>)> {
1999 if pcm_m.is_empty() || pcm_m.len() % NUM_QMF_SUBBANDS != 0 || pcm_m.len() != pcm_s.len() {
2000 return None;
2001 }
2002 let n_slots = pcm_m.len() / NUM_QMF_SUBBANDS;
2003 if n_slots == 0 {
2004 return None;
2005 }
2006 let mut ana_m = QmfAnalysisBank::new();
2007 let mut ana_s = QmfAnalysisBank::new();
2008 let x0 = ana_m.process_block(pcm_m);
2009 let x1 = ana_s.process_block(pcm_s);
2010 let alpha_q = differential_decode(&data.alpha1, cfg.num_param_bands, &mut state.alpha_diff);
2011 let beta_q = differential_decode(&data.beta1, cfg.num_param_bands, &mut state.beta_diff);
2012 let (alpha_dq, beta_dq) = dequantize_alpha_beta(&alpha_q, &beta_q, cfg.quant_mode);
2013 if alpha_dq.is_empty() {
2014 return None;
2015 }
2016 let frame = AcplCpeFrame {
2017 x0: &x0,
2018 x1: Some(&x1),
2019 alpha_dq: &alpha_dq,
2020 beta_dq: &beta_dq,
2021 num_param_bands: cfg.num_param_bands,
2022 acpl_qmf_band: cfg.qmf_band as u32,
2023 steep: matches!(
2024 data.framing.interpolation_type,
2025 AcplInterpolationType::Steep
2026 ),
2027 param_timeslots: &data.framing.param_timeslots,
2028 };
2029 let out = run_pseudocode_115_pair(&mut state.cpe, frame);
2030 let mut syn0 = QmfSynthesisBank::new();
2031 let mut syn1 = QmfSynthesisBank::new();
2032 let mut left = Vec::with_capacity(pcm_m.len());
2033 let mut right = Vec::with_capacity(pcm_m.len());
2034 for ts in 0..n_slots {
2035 left.extend_from_slice(&syn0.process_slot(&out.z0[ts]));
2036 right.extend_from_slice(&syn1.process_slot(&out.z1[ts]));
2037 }
2038 Some((left, right))
2039}
2040
2041use crate::acpl::{AcplConfig2ch, AcplData1ch as AcplData1chTy, AcplData2ch};
2046
2047#[derive(Debug, Clone)]
2050pub struct Acpl5xPcmOutput {
2051 pub left: Vec<f32>,
2052 pub right: Vec<f32>,
2053 pub centre: Vec<f32>,
2054 pub left_surround: Vec<f32>,
2055 pub right_surround: Vec<f32>,
2056}
2057
2058pub struct Acpl5xPairPcmState {
2063 pub pair: Acpl5xPairState,
2064 pub ana_l: QmfAnalysisBank,
2065 pub ana_r: QmfAnalysisBank,
2066 pub ana_c: QmfAnalysisBank,
2067 pub ana_ls: QmfAnalysisBank,
2068 pub ana_rs: QmfAnalysisBank,
2069 pub syn_l: QmfSynthesisBank,
2070 pub syn_r: QmfSynthesisBank,
2071 pub syn_c: QmfSynthesisBank,
2072 pub syn_ls: QmfSynthesisBank,
2073 pub syn_rs: QmfSynthesisBank,
2074}
2075
2076impl Acpl5xPairPcmState {
2077 pub fn new() -> Self {
2078 Self {
2079 pair: Acpl5xPairState::new(),
2080 ana_l: QmfAnalysisBank::new(),
2081 ana_r: QmfAnalysisBank::new(),
2082 ana_c: QmfAnalysisBank::new(),
2083 ana_ls: QmfAnalysisBank::new(),
2084 ana_rs: QmfAnalysisBank::new(),
2085 syn_l: QmfSynthesisBank::new(),
2086 syn_r: QmfSynthesisBank::new(),
2087 syn_c: QmfSynthesisBank::new(),
2088 syn_ls: QmfSynthesisBank::new(),
2089 syn_rs: QmfSynthesisBank::new(),
2090 }
2091 }
2092}
2093
2094impl Default for Acpl5xPairPcmState {
2095 fn default() -> Self {
2096 Self::new()
2097 }
2098}
2099
2100#[allow(clippy::too_many_arguments)]
2123pub fn run_acpl_5x_pair_pcm(
2124 mode: Acpl5xPairMode,
2125 pcm_l: &[f32],
2126 pcm_r: &[f32],
2127 pcm_c: &[f32],
2128 pcm_ls: Option<&[f32]>,
2129 pcm_rs: Option<&[f32]>,
2130 cfg_1: &AcplConfig1ch,
2131 data_1: &AcplData1chTy,
2132 cfg_2: &AcplConfig1ch,
2133 data_2: &AcplData1chTy,
2134 state: &mut Acpl5xPairPcmState,
2135) -> Option<Acpl5xPcmOutput> {
2136 if pcm_l.is_empty() || pcm_l.len() % NUM_QMF_SUBBANDS != 0 {
2137 return None;
2138 }
2139 if pcm_l.len() != pcm_r.len() || pcm_l.len() != pcm_c.len() {
2140 return None;
2141 }
2142 let n_slots = pcm_l.len() / NUM_QMF_SUBBANDS;
2143 if n_slots == 0 {
2144 return None;
2145 }
2146 match mode {
2148 Acpl5xPairMode::AspxAcpl1 => {
2149 let (ls, rs) = (pcm_ls?, pcm_rs?);
2150 if ls.len() != pcm_l.len() || rs.len() != pcm_l.len() {
2151 return None;
2152 }
2153 }
2154 Acpl5xPairMode::AspxAcpl2 => {
2155 if pcm_ls.is_some() || pcm_rs.is_some() {
2157 return None;
2158 }
2159 }
2160 }
2161 let x0 = state.ana_l.process_block(pcm_l);
2163 let x1 = state.ana_r.process_block(pcm_r);
2164 let x2 = state.ana_c.process_block(pcm_c);
2165 let x3_owned = pcm_ls.map(|p| state.ana_ls.process_block(p));
2166 let x4_owned = pcm_rs.map(|p| state.ana_rs.process_block(p));
2167
2168 let alpha1_q = differential_decode(
2170 &data_1.alpha1,
2171 cfg_1.num_param_bands,
2172 &mut state.pair.alpha1_diff,
2173 );
2174 let beta1_q = differential_decode(
2175 &data_1.beta1,
2176 cfg_1.num_param_bands,
2177 &mut state.pair.beta1_diff,
2178 );
2179 let (alpha1_dq, beta1_dq) = dequantize_alpha_beta(&alpha1_q, &beta1_q, cfg_1.quant_mode);
2180 let alpha2_q = differential_decode(
2181 &data_2.alpha1,
2182 cfg_2.num_param_bands,
2183 &mut state.pair.alpha2_diff,
2184 );
2185 let beta2_q = differential_decode(
2186 &data_2.beta1,
2187 cfg_2.num_param_bands,
2188 &mut state.pair.beta2_diff,
2189 );
2190 let (alpha2_dq, beta2_dq) = dequantize_alpha_beta(&alpha2_q, &beta2_q, cfg_2.quant_mode);
2191 if alpha1_dq.is_empty() || alpha2_dq.is_empty() {
2192 return None;
2193 }
2194 let frame = Acpl5xPairFrame {
2196 mode,
2197 x0: &x0,
2198 x1: &x1,
2199 x2: &x2,
2200 x3: x3_owned.as_deref(),
2201 x4: x4_owned.as_deref(),
2202 alpha_1_dq: &alpha1_dq,
2203 beta_1_dq: &beta1_dq,
2204 alpha_2_dq: &alpha2_dq,
2205 beta_2_dq: &beta2_dq,
2206 num_param_bands: cfg_1.num_param_bands,
2207 acpl_qmf_band: 0,
2209 steep_1: matches!(
2210 data_1.framing.interpolation_type,
2211 AcplInterpolationType::Steep
2212 ),
2213 steep_2: matches!(
2214 data_2.framing.interpolation_type,
2215 AcplInterpolationType::Steep
2216 ),
2217 param_timeslots_1: &data_1.framing.param_timeslots,
2218 param_timeslots_2: &data_2.framing.param_timeslots,
2219 };
2220 let out = run_pseudocode_117_5x(&mut state.pair, frame);
2221
2222 let mut left = Vec::with_capacity(pcm_l.len());
2224 let mut right = Vec::with_capacity(pcm_l.len());
2225 let mut centre = Vec::with_capacity(pcm_l.len());
2226 let mut left_surround = Vec::with_capacity(pcm_l.len());
2227 let mut right_surround = Vec::with_capacity(pcm_l.len());
2228 for ts in 0..n_slots {
2229 left.extend_from_slice(&state.syn_l.process_slot(&out.z0[ts]));
2230 right.extend_from_slice(&state.syn_r.process_slot(&out.z2[ts]));
2231 centre.extend_from_slice(&state.syn_c.process_slot(&out.z4[ts]));
2232 left_surround.extend_from_slice(&state.syn_ls.process_slot(&out.z1[ts]));
2233 right_surround.extend_from_slice(&state.syn_rs.process_slot(&out.z3[ts]));
2234 }
2235 Some(Acpl5xPcmOutput {
2236 left,
2237 right,
2238 centre,
2239 left_surround,
2240 right_surround,
2241 })
2242}
2243
2244pub struct Acpl5xMchPcmState {
2250 pub mch: AcplMchState,
2251 pub ana_l: QmfAnalysisBank,
2252 pub ana_r: QmfAnalysisBank,
2253 pub ana_c: QmfAnalysisBank,
2254 pub syn_l: QmfSynthesisBank,
2255 pub syn_r: QmfSynthesisBank,
2256 pub syn_c: QmfSynthesisBank,
2257 pub syn_ls: QmfSynthesisBank,
2258 pub syn_rs: QmfSynthesisBank,
2259 pub alpha1_diff: AcplDiffState,
2260 pub alpha2_diff: AcplDiffState,
2261 pub beta1_diff: AcplDiffState,
2262 pub beta2_diff: AcplDiffState,
2263 pub beta3_diff: AcplDiffState,
2264 pub gamma_diff: [AcplDiffState; 6],
2265}
2266
2267impl Acpl5xMchPcmState {
2268 pub fn new() -> Self {
2269 Self {
2270 mch: AcplMchState::new(),
2271 ana_l: QmfAnalysisBank::new(),
2272 ana_r: QmfAnalysisBank::new(),
2273 ana_c: QmfAnalysisBank::new(),
2274 syn_l: QmfSynthesisBank::new(),
2275 syn_r: QmfSynthesisBank::new(),
2276 syn_c: QmfSynthesisBank::new(),
2277 syn_ls: QmfSynthesisBank::new(),
2278 syn_rs: QmfSynthesisBank::new(),
2279 alpha1_diff: AcplDiffState::new(),
2280 alpha2_diff: AcplDiffState::new(),
2281 beta1_diff: AcplDiffState::new(),
2282 beta2_diff: AcplDiffState::new(),
2283 beta3_diff: AcplDiffState::new(),
2284 gamma_diff: [
2285 AcplDiffState::new(),
2286 AcplDiffState::new(),
2287 AcplDiffState::new(),
2288 AcplDiffState::new(),
2289 AcplDiffState::new(),
2290 AcplDiffState::new(),
2291 ],
2292 }
2293 }
2294}
2295
2296impl Default for Acpl5xMchPcmState {
2297 fn default() -> Self {
2298 Self::new()
2299 }
2300}
2301
2302pub fn run_acpl_5x_mch_pcm(
2317 pcm_l: &[f32],
2318 pcm_r: &[f32],
2319 pcm_c: &[f32],
2320 cfg: &AcplConfig2ch,
2321 data: &AcplData2ch,
2322 state: &mut Acpl5xMchPcmState,
2323) -> Option<Acpl5xPcmOutput> {
2324 if pcm_l.is_empty() || pcm_l.len() % NUM_QMF_SUBBANDS != 0 {
2325 return None;
2326 }
2327 if pcm_l.len() != pcm_r.len() || pcm_l.len() != pcm_c.len() {
2328 return None;
2329 }
2330 let n_slots = pcm_l.len() / NUM_QMF_SUBBANDS;
2331 if n_slots == 0 {
2332 return None;
2333 }
2334 let x0 = state.ana_l.process_block(pcm_l);
2336 let x1 = state.ana_r.process_block(pcm_r);
2337 let x2 = state.ana_c.process_block(pcm_c);
2338 let nb = cfg.num_param_bands;
2340 let alpha1_q = differential_decode(&data.alpha1, nb, &mut state.alpha1_diff);
2341 let alpha2_q = differential_decode(&data.alpha2, nb, &mut state.alpha2_diff);
2342 let beta1_q = differential_decode(&data.beta1, nb, &mut state.beta1_diff);
2343 let beta2_q = differential_decode(&data.beta2, nb, &mut state.beta2_diff);
2344 let beta3_q = differential_decode(&data.beta3, nb, &mut state.beta3_diff);
2345 let g1q = differential_decode(&data.gamma1, nb, &mut state.gamma_diff[0]);
2346 let g2q = differential_decode(&data.gamma2, nb, &mut state.gamma_diff[1]);
2347 let g3q = differential_decode(&data.gamma3, nb, &mut state.gamma_diff[2]);
2348 let g4q = differential_decode(&data.gamma4, nb, &mut state.gamma_diff[3]);
2349 let g5q = differential_decode(&data.gamma5, nb, &mut state.gamma_diff[4]);
2350 let g6q = differential_decode(&data.gamma6, nb, &mut state.gamma_diff[5]);
2351 let (alpha1_dq, beta1_dq) = dequantize_alpha_beta(&alpha1_q, &beta1_q, cfg.quant_mode_0);
2352 let (alpha2_dq, beta2_dq) = dequantize_alpha_beta(&alpha2_q, &beta2_q, cfg.quant_mode_0);
2353 let beta3_dq = dequantize_beta3(&beta3_q, cfg.quant_mode_0);
2354 let g1_dq = dequantize_gamma(&g1q, cfg.quant_mode_1);
2355 let g2_dq = dequantize_gamma(&g2q, cfg.quant_mode_1);
2356 let g3_dq = dequantize_gamma(&g3q, cfg.quant_mode_1);
2357 let g4_dq = dequantize_gamma(&g4q, cfg.quant_mode_1);
2358 let g5_dq = dequantize_gamma(&g5q, cfg.quant_mode_1);
2359 let g6_dq = dequantize_gamma(&g6q, cfg.quant_mode_1);
2360 if alpha1_dq.is_empty() {
2361 return None;
2362 }
2363 let frame = AcplMchFrame {
2364 x0: &x0,
2365 x1: &x1,
2366 x2: &x2,
2367 alpha_1_dq: &alpha1_dq,
2368 alpha_2_dq: &alpha2_dq,
2369 beta_1_dq: &beta1_dq,
2370 beta_2_dq: &beta2_dq,
2371 beta_3_dq: &beta3_dq,
2372 g1_dq: &g1_dq,
2373 g2_dq: &g2_dq,
2374 g3_dq: &g3_dq,
2375 g4_dq: &g4_dq,
2376 g5_dq: &g5_dq,
2377 g6_dq: &g6_dq,
2378 num_param_bands: nb,
2379 steep: matches!(
2380 data.framing.interpolation_type,
2381 AcplInterpolationType::Steep
2382 ),
2383 param_timeslots: &data.framing.param_timeslots,
2384 };
2385 let out = run_pseudocode_118_5x(&mut state.mch, frame);
2386 let mut left = Vec::with_capacity(pcm_l.len());
2387 let mut right = Vec::with_capacity(pcm_l.len());
2388 let mut centre = Vec::with_capacity(pcm_l.len());
2389 let mut left_surround = Vec::with_capacity(pcm_l.len());
2390 let mut right_surround = Vec::with_capacity(pcm_l.len());
2391 for ts in 0..n_slots {
2392 left.extend_from_slice(&state.syn_l.process_slot(&out.z0[ts]));
2393 right.extend_from_slice(&state.syn_r.process_slot(&out.z2[ts]));
2394 centre.extend_from_slice(&state.syn_c.process_slot(&out.z4[ts]));
2395 left_surround.extend_from_slice(&state.syn_ls.process_slot(&out.z1[ts]));
2396 right_surround.extend_from_slice(&state.syn_rs.process_slot(&out.z3[ts]));
2397 }
2398 Some(Acpl5xPcmOutput {
2399 left,
2400 right,
2401 centre,
2402 left_surround,
2403 right_surround,
2404 })
2405}
2406
2407#[cfg(test)]
2412mod tests {
2413 use super::*;
2414 use crate::acpl::AcplHuffParam;
2415
2416 #[test]
2419 fn alpha_dq_fine_anchors_table_203() {
2420 assert_eq!(ALPHA_DQ_FINE[0], -2.000000);
2422 assert_eq!(ALPHA_DQ_FINE[16], 0.000000);
2423 assert_eq!(ALPHA_DQ_FINE[32], 2.000000);
2424 for k in 1..=16 {
2426 let lo = ALPHA_DQ_FINE[16 - k];
2427 let hi = ALPHA_DQ_FINE[16 + k];
2428 assert!((lo + hi).abs() < 1e-6, "k={k} lo={lo} hi={hi}");
2429 }
2430 }
2431
2432 #[test]
2433 fn alpha_dq_coarse_anchors_table_205() {
2434 assert_eq!(ALPHA_DQ_COARSE[0], -2.000000);
2435 assert_eq!(ALPHA_DQ_COARSE[8], 0.000000);
2436 assert_eq!(ALPHA_DQ_COARSE[16], 2.000000);
2437 for k in 1..=8 {
2438 let lo = ALPHA_DQ_COARSE[8 - k];
2439 let hi = ALPHA_DQ_COARSE[8 + k];
2440 assert!((lo + hi).abs() < 1e-6, "k={k} lo={lo} hi={hi}");
2441 }
2442 }
2443
2444 #[test]
2445 fn ibeta_fine_table_203_column2() {
2446 assert_eq!(IBETA_FINE[0], 0);
2447 assert_eq!(IBETA_FINE[8], 8);
2448 assert_eq!(IBETA_FINE[16], 0);
2449 assert_eq!(IBETA_FINE[24], 8);
2450 assert_eq!(IBETA_FINE[32], 0);
2451 }
2452
2453 #[test]
2454 fn ibeta_coarse_table_205_column2() {
2455 assert_eq!(IBETA_COARSE[0], 0);
2456 assert_eq!(IBETA_COARSE[4], 4);
2457 assert_eq!(IBETA_COARSE[8], 0);
2458 assert_eq!(IBETA_COARSE[12], 4);
2459 assert_eq!(IBETA_COARSE[16], 0);
2460 }
2461
2462 #[test]
2463 fn beta_dq_fine_anchors_table_204() {
2464 for col in 0..9 {
2466 assert_eq!(BETA_DQ_FINE[0][col], 0.0);
2467 }
2468 assert_eq!(BETA_DQ_FINE[8][0], 4.0);
2470 assert_eq!(BETA_DQ_FINE[8][8], 1.0);
2471 for q in 1..=8 {
2473 for c in 1..9 {
2474 assert!(
2475 BETA_DQ_FINE[q][c] < BETA_DQ_FINE[q][c - 1],
2476 "beta_q={q} col={c}"
2477 );
2478 }
2479 }
2480 }
2481
2482 #[test]
2483 fn beta_dq_coarse_anchors_table_206() {
2484 assert_eq!(BETA_DQ_COARSE[0][0], 0.0);
2485 assert_eq!(BETA_DQ_COARSE[4][0], 4.0);
2486 assert_eq!(BETA_DQ_COARSE[4][4], 1.0);
2487 for q in 1..=4 {
2488 for c in 1..5 {
2489 assert!(
2490 BETA_DQ_COARSE[q][c] < BETA_DQ_COARSE[q][c - 1],
2491 "beta_q={q} col={c}"
2492 );
2493 }
2494 }
2495 }
2496
2497 #[test]
2498 fn beta3_and_gamma_deltas_match_tables_207_208() {
2499 assert_eq!(beta3_delta(AcplQuantMode::Fine), 0.125);
2500 assert_eq!(beta3_delta(AcplQuantMode::Coarse), 0.25);
2501 assert!((gamma_delta(AcplQuantMode::Fine) - 1638.0 / 16384.0).abs() < 1e-9);
2502 assert!((gamma_delta(AcplQuantMode::Coarse) - 3276.0 / 16384.0).abs() < 1e-9);
2503 }
2504
2505 #[test]
2506 fn dequantize_alpha_fine_round_trips_through_signed_index() {
2507 let (a, ib) = dequantize_alpha_index(AcplQuantMode::Fine, 0);
2510 assert_eq!(a, 0.0);
2511 assert_eq!(ib, 0);
2512 let (a, ib) = dequantize_alpha_index(AcplQuantMode::Fine, -16);
2514 assert_eq!(a, -2.000000);
2515 assert_eq!(ib, 0);
2516 let (a, ib) = dequantize_alpha_index(AcplQuantMode::Fine, 8);
2518 assert_eq!(a, 1.000000);
2519 assert_eq!(ib, 8);
2520 }
2521
2522 #[test]
2523 fn dequantize_beta_fine_uses_ibeta_column() {
2524 let v = dequantize_beta_index(AcplQuantMode::Fine, 1, 0);
2526 assert!((v - 0.2375).abs() < 1e-6);
2527 let v = dequantize_beta_index(AcplQuantMode::Fine, -1, 0);
2529 assert!((v + 0.2375).abs() < 1e-6);
2530 let v = dequantize_beta_index(AcplQuantMode::Fine, 8, 8);
2532 assert!((v - 1.0).abs() < 1e-6);
2533 }
2534
2535 #[test]
2538 fn differential_decode_freq_accumulates_from_seed() {
2539 let p = AcplHuffParam {
2541 values: vec![5, 1, -2, 3],
2542 direction_time: false,
2543 };
2544 let mut st = AcplDiffState::new();
2545 let out = differential_decode(&[p], 4, &mut st);
2546 assert_eq!(out, vec![vec![5, 6, 4, 7]]);
2547 assert_eq!(st.q_prev, vec![5, 6, 4, 7]);
2548 }
2549
2550 #[test]
2551 fn differential_decode_time_uses_prev_then_carries() {
2552 let p1 = AcplHuffParam {
2555 values: vec![1, 2, 3],
2556 direction_time: false,
2557 };
2558 let p2 = AcplHuffParam {
2559 values: vec![10, -1, 0],
2560 direction_time: true,
2561 };
2562 let mut st = AcplDiffState::new();
2563 let out = differential_decode(&[p1, p2], 3, &mut st);
2564 assert_eq!(out, vec![vec![1, 3, 6], vec![11, 2, 6]]);
2567 assert_eq!(st.q_prev, vec![11, 2, 6]);
2568 }
2569
2570 #[test]
2571 fn differential_decode_carries_across_frames() {
2572 let mut st = AcplDiffState::new();
2575 let p1 = AcplHuffParam {
2576 values: vec![4, 1],
2577 direction_time: false,
2578 };
2579 let _ = differential_decode(&[p1], 2, &mut st);
2580 assert_eq!(st.q_prev, vec![4, 5]);
2581 let p2 = AcplHuffParam {
2582 values: vec![1, -2],
2583 direction_time: true,
2584 };
2585 let out2 = differential_decode(&[p2], 2, &mut st);
2586 assert_eq!(out2, vec![vec![5, 3]]);
2587 assert_eq!(st.q_prev, vec![5, 3]);
2588 }
2589
2590 #[test]
2593 fn dequantize_alpha_beta_returns_two_synced_matrices() {
2594 let alpha_q = vec![vec![0i32, 8]];
2598 let beta_q = vec![vec![1i32, -1]];
2599 let (a, b) = dequantize_alpha_beta(&alpha_q, &beta_q, AcplQuantMode::Fine);
2600 assert_eq!(a.len(), 1);
2601 assert_eq!(a[0].len(), 2);
2602 assert!((a[0][0] - 0.0).abs() < 1e-6);
2603 assert!((a[0][1] - 1.0).abs() < 1e-6);
2604 assert!((b[0][0] - 0.2375).abs() < 1e-6);
2605 assert!((b[0][1] + 0.0593750).abs() < 1e-6);
2606 }
2607
2608 #[test]
2611 fn interpolate_smooth_one_param_set_linear_ramp() {
2612 let p_set = vec![vec![4.0f32; NUM_QMF_SUBBANDS]];
2614 let prev = vec![0.0f32; NUM_QMF_SUBBANDS];
2615 let inp = InterpInputs {
2616 by_pset: &p_set,
2617 prev: &prev,
2618 };
2619 for ts in 0..4u32 {
2620 let v = interpolate(&inp, 1, 0, ts, 4, false, &[]);
2621 let expected = (ts + 1) as f32;
2622 assert!(
2623 (v - expected).abs() < 1e-6,
2624 "ts={ts} v={v} expected={expected}"
2625 );
2626 }
2627 }
2628
2629 #[test]
2630 fn interpolate_steep_falls_to_constants() {
2631 let p_set = vec![vec![5.0f32; NUM_QMF_SUBBANDS]];
2633 let prev = vec![1.0f32; NUM_QMF_SUBBANDS];
2634 let inp = InterpInputs {
2635 by_pset: &p_set,
2636 prev: &prev,
2637 };
2638 assert_eq!(interpolate(&inp, 1, 0, 0, 4, true, &[2]), 1.0);
2640 assert_eq!(interpolate(&inp, 1, 0, 1, 4, true, &[2]), 1.0);
2641 assert_eq!(interpolate(&inp, 1, 0, 2, 4, true, &[2]), 5.0);
2642 assert_eq!(interpolate(&inp, 1, 0, 3, 4, true, &[2]), 5.0);
2643 }
2644
2645 #[test]
2646 fn interpolate_smooth_two_sets_meets_at_midpoint() {
2647 let p_set = vec![
2651 vec![4.0f32; NUM_QMF_SUBBANDS],
2652 vec![8.0f32; NUM_QMF_SUBBANDS],
2653 ];
2654 let prev = vec![0.0f32; NUM_QMF_SUBBANDS];
2655 let inp = InterpInputs {
2656 by_pset: &p_set,
2657 prev: &prev,
2658 };
2659 for ts in 0..8u32 {
2660 let v = interpolate(&inp, 2, 0, ts, 8, false, &[]);
2661 let expected = (ts + 1) as f32;
2662 assert!(
2663 (v - expected).abs() < 1e-5,
2664 "ts={ts} v={v} expected={expected}"
2665 );
2666 }
2667 }
2668
2669 #[test]
2672 fn expand_pb_to_sb_preserves_first_pb_for_low_subbands_15() {
2673 let pb = vec![vec![
2675 0.0f32, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0,
2676 ]];
2677 let sb = expand_pb_to_sb(&pb, 15);
2678 assert_eq!(sb[0][0], 0.0);
2679 assert_eq!(sb[0][8], 8.0);
2680 assert_eq!(sb[0][9], 9.0);
2681 assert_eq!(sb[0][14], 11.0); assert_eq!(sb[0][63], 14.0);
2683 }
2684
2685 #[test]
2688 fn region_delay_filter_length_match_table_198() {
2689 assert_eq!(region_delay(0), 7);
2690 assert_eq!(region_filter_length(0), 7);
2691 assert_eq!(region_delay(6), 7);
2692 assert_eq!(region_filter_length(6), 7);
2693 assert_eq!(region_delay(7), 10);
2694 assert_eq!(region_filter_length(7), 4);
2695 assert_eq!(region_delay(22), 10);
2696 assert_eq!(region_filter_length(22), 4);
2697 assert_eq!(region_delay(23), 12);
2698 assert_eq!(region_filter_length(23), 2);
2699 assert_eq!(region_delay(63), 12);
2700 assert_eq!(region_filter_length(63), 2);
2701 }
2702
2703 #[test]
2704 fn region_coeffs_match_tables_199_200_201_first_row() {
2705 assert_eq!(region_coeffs(DecorrelatorId::D0, 0)[0], 1.0);
2706 assert!((region_coeffs(DecorrelatorId::D0, 0)[1] - 0.5306).abs() < 1e-12);
2707 assert!((region_coeffs(DecorrelatorId::D1, 7)[1] - 0.0425).abs() < 1e-12);
2708 assert!((region_coeffs(DecorrelatorId::D2, 23)[1] + 0.6057).abs() < 1e-12);
2709 }
2710
2711 #[test]
2712 fn input_signal_modifier_zero_input_zero_output() {
2713 let mut m = InputSignalModifier::new(DecorrelatorId::D0);
2714 for sb in 0..NUM_QMF_SUBBANDS as u32 {
2715 let y = m.process_sample(sb, (0.0, 0.0));
2716 assert_eq!(y, (0.0, 0.0));
2717 }
2718 }
2719
2720 #[test]
2721 fn input_signal_modifier_impulse_eventually_yields_nonzero() {
2722 let mut m = InputSignalModifier::new(DecorrelatorId::D0);
2725 let mut energy = 0.0f64;
2726 for ts in 0..32 {
2727 let x = if ts == 0 { (1.0f32, 0.0) } else { (0.0, 0.0) };
2728 let y = m.process_sample(0, x);
2729 energy += (y.0 as f64).powi(2) + (y.1 as f64).powi(2);
2730 }
2731 assert!(energy > 0.0, "decorrelator should emit non-zero IIR tail");
2732 }
2733
2734 #[test]
2737 fn transient_ducker_passes_silence_unmodified() {
2738 let mut d = TransientDucker::new();
2739 let p_e = [0.0f32; ACPL_MAX_NUM_PARAM_BANDS];
2740 let g = d.update(&p_e);
2741 for v in g.iter() {
2742 assert_eq!(*v, 1.0, "silence should yield gain 1.0 (no transient)");
2743 }
2744 }
2745
2746 #[test]
2747 fn transient_ducker_attenuates_after_peak() {
2748 let mut d = TransientDucker::new();
2751 let mut spike = [0.0f32; ACPL_MAX_NUM_PARAM_BANDS];
2752 spike[0] = 1.0;
2753 let _ = d.update(&spike);
2754 let zeros = [0.0f32; ACPL_MAX_NUM_PARAM_BANDS];
2757 let g = d.update(&zeros);
2758 assert!(g[0] < 1.0, "ducker should attenuate the post-peak slot");
2759 assert!(g[0] > 0.0);
2760 }
2761
2762 #[test]
2763 fn compute_p_energy_aggregates_per_param_band() {
2764 let mut x = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
2767 x[0] = (3.0, 0.0);
2768 x[1] = (0.0, 4.0);
2769 let e = compute_p_energy(&x, 15);
2770 assert_eq!(e[0], 9.0);
2771 assert_eq!(e[1], 16.0);
2772 for pb in 2..ACPL_MAX_NUM_PARAM_BANDS {
2773 assert_eq!(e[pb], 0.0);
2774 }
2775 }
2776
2777 #[test]
2778 fn apply_transient_ducker_scales_per_pb() {
2779 let x = [(2.0f32, 0.0f32); NUM_QMF_SUBBANDS];
2780 let mut g = [1.0f32; ACPL_MAX_NUM_PARAM_BANDS];
2781 g[0] = 0.5;
2782 let out = apply_transient_ducker(&x, &g, 15);
2783 assert_eq!(out[0].0, 1.0);
2786 assert_eq!(out[1].0, 2.0);
2787 }
2788
2789 #[test]
2799 fn acpl_module_mixes_channels_above_qmf_band_aspx_acpl_2() {
2800 let num_ts = 32usize;
2801 let num_pb = 15u32;
2802 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
2804 let zero = [(0.0f32, 0.0f32); NUM_QMF_SUBBANDS];
2805 for ts in 0..num_ts {
2806 let phase = (ts as f32) * 0.5;
2807 x0[ts][12] = (phase.cos(), phase.sin());
2808 x0[ts][30] = (0.5 * phase.cos(), 0.5 * phase.sin());
2809 }
2810 let y: Vec<_> = x0.clone();
2812 let alpha_dq = vec![vec![0.5f32; num_pb as usize]];
2814 let beta_dq = vec![vec![0.5f32; num_pb as usize]];
2815 let frame = AcplCpeFrame {
2816 x0: &x0,
2817 x1: None,
2818 alpha_dq: &alpha_dq,
2819 beta_dq: &beta_dq,
2820 num_param_bands: num_pb,
2821 acpl_qmf_band: 8, steep: false,
2823 param_timeslots: &[],
2824 };
2825 let out = acpl_module(&frame, &y);
2826 assert_eq!(out.z0.len(), num_ts);
2827 assert_eq!(out.z1.len(), num_ts);
2828 let early = 0u32;
2836 let interp_early = 0.5_f32 * ((early + 1) as f32) / (num_ts as f32);
2837 let scale_early = 0.5_f32 * (1.0 + 2.0 * interp_early);
2838 let (z0r, z0i) = out.z0[early as usize][12];
2839 let (x0r, x0i) = x0[early as usize][12];
2840 let exp_re = scale_early * x0r;
2841 let exp_im = scale_early * x0i;
2842 assert!(
2843 (z0r - exp_re).abs() < 1e-5,
2844 "z0r {z0r} vs {exp_re} (scale {scale_early})"
2845 );
2846 assert!((z0i - exp_im).abs() < 1e-5, "z0i {z0i} vs {exp_im}");
2847 assert!(
2849 (z0r - x0r).abs() > 1e-4 || (z0i - x0i).abs() > 1e-4,
2850 "z0[early][12] should differ from x0 (mixing scale != 1.0) — got z0=({z0r},{z0i}) x0=({x0r},{x0i}) scale={scale_early}"
2851 );
2852 for sb in 0..8 {
2855 for ts in 0..num_ts {
2856 let (z0r, z0i) = out.z0[ts][sb];
2857 let (z1r, z1i) = out.z1[ts][sb];
2858 assert!((z0r - 0.5 * x0[ts][sb].0).abs() < 1e-6);
2859 assert!((z0i - 0.5 * x0[ts][sb].1).abs() < 1e-6);
2860 assert!((z1r - 0.5 * x0[ts][sb].0).abs() < 1e-6);
2861 assert!((z1i - 0.5 * x0[ts][sb].1).abs() < 1e-6);
2862 }
2863 }
2864 for ts in 0..num_ts {
2866 for sb in 0..NUM_QMF_SUBBANDS {
2867 assert!(out.z0[ts][sb].0.is_finite());
2868 assert!(out.z0[ts][sb].1.is_finite());
2869 assert!(out.z1[ts][sb].0.is_finite());
2870 assert!(out.z1[ts][sb].1.is_finite());
2871 }
2872 }
2873 let _ = zero;
2875 }
2876
2877 #[test]
2880 fn acpl_module_below_qmf_band_is_mid_side_split() {
2881 let num_ts = 8usize;
2882 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
2883 let mut x1 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
2884 for ts in 0..num_ts {
2885 x0[ts][2] = (1.0, 0.0);
2886 x1[ts][2] = (0.0, 1.0);
2887 }
2888 let y = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
2889 let alpha_dq = vec![vec![0.0f32; 15]];
2890 let beta_dq = vec![vec![0.0f32; 15]];
2891 let frame = AcplCpeFrame {
2892 x0: &x0,
2893 x1: Some(&x1),
2894 alpha_dq: &alpha_dq,
2895 beta_dq: &beta_dq,
2896 num_param_bands: 15,
2897 acpl_qmf_band: 4,
2898 steep: false,
2899 param_timeslots: &[],
2900 };
2901 let out = acpl_module(&frame, &y);
2902 for ts in 0..num_ts {
2903 let z0 = out.z0[ts][2];
2904 let z1 = out.z1[ts][2];
2905 assert!((z0.0 - 0.5).abs() < 1e-6);
2907 assert!((z0.1 - 0.5).abs() < 1e-6);
2908 assert!((z1.0 - 0.5).abs() < 1e-6);
2910 assert!((z1.1 + 0.5).abs() < 1e-6);
2911 }
2912 }
2913
2914 #[test]
2918 fn run_pseudocode_115_pair_end_to_end() {
2919 let num_ts = 16usize;
2920 let num_pb = 9u32;
2921 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
2922 for ts in 0..num_ts {
2923 let phase = (ts as f32) * 0.3;
2924 for sb in 0..32 {
2925 x0[ts][sb] = (
2926 0.1 * (phase + sb as f32 * 0.1).cos(),
2927 0.1 * (phase + sb as f32 * 0.1).sin(),
2928 );
2929 }
2930 }
2931 let alpha_dq = vec![vec![0.3f32; num_pb as usize]];
2932 let beta_dq = vec![vec![0.3f32; num_pb as usize]];
2933 let mut state = AcplCpeState::new(DecorrelatorId::D0);
2934 let frame = AcplCpeFrame {
2935 x0: &x0,
2936 x1: None,
2937 alpha_dq: &alpha_dq,
2938 beta_dq: &beta_dq,
2939 num_param_bands: num_pb,
2940 acpl_qmf_band: 4,
2941 steep: false,
2942 param_timeslots: &[],
2943 };
2944 let out = run_pseudocode_115_pair(&mut state, frame);
2945 assert_eq!(out.z0.len(), num_ts);
2946 assert_eq!(out.z1.len(), num_ts);
2947 let mut diff_energy = 0.0f64;
2950 for ts in 0..num_ts {
2951 for sb in 0..NUM_QMF_SUBBANDS {
2952 assert!(out.z0[ts][sb].0.is_finite());
2953 assert!(out.z0[ts][sb].1.is_finite());
2954 assert!(out.z1[ts][sb].0.is_finite());
2955 assert!(out.z1[ts][sb].1.is_finite());
2956 let dr = out.z0[ts][sb].0 - x0[ts][sb].0;
2957 let di = out.z0[ts][sb].1 - x0[ts][sb].1;
2958 diff_energy += (dr as f64).powi(2) + (di as f64).powi(2);
2959 }
2960 }
2961 assert!(diff_energy > 0.0, "output should diverge from x0");
2962 assert_eq!(state.alpha_prev_sb.len(), NUM_QMF_SUBBANDS);
2964 assert_eq!(state.beta_prev_sb.len(), NUM_QMF_SUBBANDS);
2965 for sb in 0..NUM_QMF_SUBBANDS {
2967 assert!((state.alpha_prev_sb[sb] - 0.3).abs() < 1e-6);
2968 assert!((state.beta_prev_sb[sb] - 0.3).abs() < 1e-6);
2969 }
2970 }
2971
2972 #[test]
2975 fn acpl_module_zero_params_passthrough_above_qmf_band() {
2976 let num_ts = 4usize;
2977 let mut x0in = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
2978 for ts in 0..num_ts {
2979 x0in[ts][20] = (2.0, 1.0); }
2981 let y = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
2982 let alpha_dq = vec![vec![0.0f32; 15]];
2983 let beta_dq = vec![vec![0.0f32; 15]];
2984 let frame = AcplCpeFrame {
2985 x0: &x0in,
2986 x1: None,
2987 alpha_dq: &alpha_dq,
2988 beta_dq: &beta_dq,
2989 num_param_bands: 15,
2990 acpl_qmf_band: 8,
2991 steep: false,
2992 param_timeslots: &[],
2993 };
2994 let out = acpl_module(&frame, &y);
2995 for ts in 0..num_ts {
2998 let z = out.z0[ts][20];
2999 assert!((z.0 - 1.0).abs() < 1e-6);
3000 assert!((z.1 - 0.5).abs() < 1e-6);
3001 let z1 = out.z1[ts][20];
3003 assert!((z1.0 - 1.0).abs() < 1e-6);
3004 assert!((z1.1 - 0.5).abs() < 1e-6);
3005 }
3006 }
3007
3008 #[test]
3011 fn run_acpl_1ch_pcm_emits_two_channel_pcm_with_energy() {
3012 use crate::acpl::{
3017 Acpl1chMode, AcplConfig1ch, AcplData1ch, AcplFramingData, AcplHuffParam,
3018 AcplInterpolationType, AcplQuantMode,
3019 };
3020 let _ = Acpl1chMode::Full; let n_slots = 32usize;
3022 let n = n_slots * NUM_QMF_SUBBANDS;
3023 let mut pcm = vec![0.0f32; n];
3024 let f = 440.0_f32 / 48_000.0_f32;
3025 for (i, s) in pcm.iter_mut().enumerate() {
3026 *s = (2.0 * std::f32::consts::PI * f * i as f32).sin();
3027 }
3028 let cfg = AcplConfig1ch {
3029 num_param_bands_id: 0,
3030 num_param_bands: 15,
3031 quant_mode: AcplQuantMode::Fine,
3032 qmf_band: 0,
3033 };
3034 let alpha = AcplHuffParam {
3038 values: vec![4i32; cfg.num_param_bands as usize],
3039 direction_time: false,
3040 };
3041 let beta = AcplHuffParam {
3042 values: vec![2i32; cfg.num_param_bands as usize],
3043 direction_time: false,
3044 };
3045 let data = AcplData1ch {
3046 framing: AcplFramingData {
3047 interpolation_type: AcplInterpolationType::Smooth,
3048 num_param_sets_cod: 0,
3049 num_param_sets: 1,
3050 param_timeslots: vec![],
3051 },
3052 alpha1: vec![alpha],
3053 beta1: vec![beta],
3054 };
3055 let mut state = AcplSubstreamState::new();
3056 let (left, right) = run_acpl_1ch_pcm(&pcm, &cfg, &data, &mut state).expect("synth runs");
3057 assert_eq!(left.len(), pcm.len());
3058 assert_eq!(right.len(), pcm.len());
3059 let start = 1024usize;
3061 let e_l: f64 = left[start..].iter().map(|&s| (s as f64).powi(2)).sum();
3062 let e_r: f64 = right[start..].iter().map(|&s| (s as f64).powi(2)).sum();
3063 assert!(e_l > 1e-6, "left channel silent (e={e_l})");
3064 assert!(e_r > 1e-6, "right channel silent (e={e_r})");
3065 let mut diffs = 0usize;
3068 for (l, r) in left[start..].iter().zip(right[start..].iter()) {
3069 if (l - r).abs() > 1e-6 {
3070 diffs += 1;
3071 }
3072 }
3073 assert!(
3074 diffs > (left.len() - start) / 4,
3075 "channels too similar (diffs={diffs})"
3076 );
3077 }
3078
3079 #[test]
3080 fn run_acpl_1ch_pcm_stereo_emits_two_channels_distinct_from_l_r_passthrough() {
3081 use crate::acpl::{
3085 AcplConfig1ch, AcplData1ch, AcplFramingData, AcplHuffParam, AcplInterpolationType,
3086 AcplQuantMode,
3087 };
3088 let n_slots = 32usize;
3089 let n = n_slots * NUM_QMF_SUBBANDS;
3090 let mut pcm_m = vec![0.0f32; n];
3091 let mut pcm_s = vec![0.0f32; n];
3092 let f_m = 440.0_f32 / 48_000.0_f32;
3093 let f_s = 220.0_f32 / 48_000.0_f32;
3094 for i in 0..n {
3095 pcm_m[i] = (2.0 * std::f32::consts::PI * f_m * i as f32).sin();
3096 pcm_s[i] = 0.3 * (2.0 * std::f32::consts::PI * f_s * i as f32).sin();
3097 }
3098 let cfg = AcplConfig1ch {
3099 num_param_bands_id: 0,
3100 num_param_bands: 15,
3101 quant_mode: AcplQuantMode::Fine,
3102 qmf_band: 8,
3105 };
3106 let alpha = AcplHuffParam {
3107 values: vec![4i32; cfg.num_param_bands as usize],
3108 direction_time: false,
3109 };
3110 let beta = AcplHuffParam {
3111 values: vec![2i32; cfg.num_param_bands as usize],
3112 direction_time: false,
3113 };
3114 let data = AcplData1ch {
3115 framing: AcplFramingData {
3116 interpolation_type: AcplInterpolationType::Smooth,
3117 num_param_sets_cod: 0,
3118 num_param_sets: 1,
3119 param_timeslots: vec![],
3120 },
3121 alpha1: vec![alpha],
3122 beta1: vec![beta],
3123 };
3124 let mut state = AcplSubstreamState::new();
3125 let (left, right) = run_acpl_1ch_pcm_stereo(&pcm_m, &pcm_s, &cfg, &data, &mut state)
3126 .expect("stereo synth runs");
3127 assert_eq!(left.len(), pcm_m.len());
3128 assert_eq!(right.len(), pcm_m.len());
3129 let start = 1024usize;
3130 let e_l: f64 = left[start..].iter().map(|&s| (s as f64).powi(2)).sum();
3131 let e_r: f64 = right[start..].iter().map(|&s| (s as f64).powi(2)).sum();
3132 assert!(e_l > 1e-6, "left channel silent (e={e_l})");
3133 assert!(e_r > 1e-6, "right channel silent (e={e_r})");
3134 let mut diff_from_input = 0usize;
3136 for i in start..left.len() {
3137 if (left[i] - pcm_m[i]).abs() > 1e-3 {
3138 diff_from_input += 1;
3139 }
3140 }
3141 assert!(
3142 diff_from_input > (left.len() - start) / 4,
3143 "left channel matches input PCM (diff_from_input={diff_from_input})"
3144 );
3145 }
3146
3147 #[test]
3148 fn run_acpl_1ch_pcm_stereo_rejects_mismatched_lengths() {
3149 use crate::acpl::{
3150 AcplConfig1ch, AcplData1ch, AcplFramingData, AcplInterpolationType, AcplQuantMode,
3151 };
3152 let pcm_m = vec![0.0f32; 64];
3153 let pcm_s = vec![0.0f32; 128];
3154 let cfg = AcplConfig1ch {
3155 num_param_bands_id: 0,
3156 num_param_bands: 15,
3157 quant_mode: AcplQuantMode::Fine,
3158 qmf_band: 0,
3159 };
3160 let data = AcplData1ch {
3161 framing: AcplFramingData {
3162 interpolation_type: AcplInterpolationType::Smooth,
3163 num_param_sets_cod: 0,
3164 num_param_sets: 1,
3165 param_timeslots: vec![],
3166 },
3167 alpha1: vec![],
3168 beta1: vec![],
3169 };
3170 let mut state = AcplSubstreamState::new();
3171 assert!(run_acpl_1ch_pcm_stereo(&pcm_m, &pcm_s, &cfg, &data, &mut state).is_none());
3172 }
3173
3174 #[test]
3175 fn run_acpl_1ch_pcm_rejects_misaligned_pcm() {
3176 use crate::acpl::{
3177 AcplConfig1ch, AcplData1ch, AcplFramingData, AcplInterpolationType, AcplQuantMode,
3178 };
3179 let pcm = vec![0.0f32; 65]; let cfg = AcplConfig1ch {
3181 num_param_bands_id: 0,
3182 num_param_bands: 15,
3183 quant_mode: AcplQuantMode::Fine,
3184 qmf_band: 0,
3185 };
3186 let data = AcplData1ch {
3187 framing: AcplFramingData {
3188 interpolation_type: AcplInterpolationType::Smooth,
3189 num_param_sets_cod: 0,
3190 num_param_sets: 1,
3191 param_timeslots: vec![],
3192 },
3193 alpha1: vec![],
3194 beta1: vec![],
3195 };
3196 let mut state = AcplSubstreamState::new();
3197 assert!(run_acpl_1ch_pcm(&pcm, &cfg, &data, &mut state).is_none());
3198 }
3199
3200 #[test]
3208 fn transform_unit_gammas_select_carriers() {
3209 let num_ts = 8usize;
3210 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3211 let mut x1 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3212 for ts in 0..num_ts {
3213 x0[ts][10] = (1.0, 0.0);
3214 x1[ts][10] = (0.0, 1.0);
3215 }
3216 let g1 = vec![vec![1.0f32; 15]];
3217 let g2 = vec![vec![0.0f32; 15]];
3218 let prev = vec![1.0f32; NUM_QMF_SUBBANDS];
3219 let prev_zero = vec![0.0f32; NUM_QMF_SUBBANDS];
3220 let v = transform(&x0, &x1, &g1, &g2, 15, &prev, &prev_zero, false, &[]);
3223 for ts in 0..num_ts {
3224 let (vr, vi) = v[ts][10];
3226 assert!((vr - 1.0).abs() < 1e-5, "ts={ts} vr={vr}, expected x0=1.0");
3227 assert!((vi - 0.0).abs() < 1e-5, "ts={ts} vi={vi}");
3228 assert_eq!(v[ts][20], (0.0, 0.0));
3230 }
3231
3232 let g1 = vec![vec![0.0f32; 15]];
3234 let g2 = vec![vec![1.0f32; 15]];
3235 let prev_g2 = vec![1.0f32; NUM_QMF_SUBBANDS];
3236 let v = transform(&x0, &x1, &g1, &g2, 15, &prev_zero, &prev_g2, false, &[]);
3237 for ts in 0..num_ts {
3238 let (vr, vi) = v[ts][10];
3239 assert!((vr - 0.0).abs() < 1e-5);
3240 assert!((vi - 1.0).abs() < 1e-5);
3241 }
3242 }
3243
3244 #[test]
3247 fn transform_mixes_two_carriers_with_gammas() {
3248 let num_ts = 4usize;
3249 let mut x0 = vec![[(2.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3250 let mut x1 = vec![[(0.0f32, 3.0f32); NUM_QMF_SUBBANDS]; num_ts];
3251 let g1 = vec![vec![0.5f32; 15]];
3254 let g2 = vec![vec![0.25f32; 15]];
3255 let prev_g1 = vec![0.5f32; NUM_QMF_SUBBANDS];
3256 let prev_g2 = vec![0.25f32; NUM_QMF_SUBBANDS];
3257 let v = transform(&x0, &x1, &g1, &g2, 15, &prev_g1, &prev_g2, false, &[]);
3258 for ts in 0..num_ts {
3259 for sb in 0..NUM_QMF_SUBBANDS {
3260 let (vr, vi) = v[ts][sb];
3261 assert!((vr - 1.0).abs() < 1e-5, "ts={ts} sb={sb} vr={vr}");
3263 assert!((vi - 0.75).abs() < 1e-5, "ts={ts} sb={sb} vi={vi}");
3264 }
3265 }
3266 let _ = (&mut x0, &mut x1);
3268 }
3269
3270 #[test]
3272 fn acpl_module2_zero_gammas_is_silent() {
3273 let num_ts = 4usize;
3274 let x0 = vec![[(1.0f32, 0.5f32); NUM_QMF_SUBBANDS]; num_ts];
3275 let x1 = vec![[(0.5f32, 1.0f32); NUM_QMF_SUBBANDS]; num_ts];
3276 let y = vec![[(2.0f32, 2.0f32); NUM_QMF_SUBBANDS]; num_ts];
3277 let zero = vec![vec![0.0f32; 15]];
3278 let (z0, z1) = acpl_module2(
3279 &x0,
3280 &x1,
3281 &y,
3282 &zero,
3283 &zero,
3284 &zero,
3285 &zero,
3286 &zero,
3287 15,
3288 false,
3289 &[],
3290 );
3291 for ts in 0..num_ts {
3292 for sb in 0..NUM_QMF_SUBBANDS {
3293 assert_eq!(z0[ts][sb], (0.0, 0.0));
3294 assert_eq!(z1[ts][sb], (0.0, 0.0));
3295 }
3296 }
3297 }
3298
3299 #[test]
3305 fn acpl_module2_unit_g1_zero_alpha_beta_passes_half_x0_to_both() {
3306 let num_ts = 4usize;
3307 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3308 let x1 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3309 let y = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3310 for ts in 0..num_ts {
3311 x0[ts][5] = (4.0, 2.0);
3312 }
3313 let g1 = vec![vec![1.0f32; 15]];
3314 let g2 = vec![vec![0.0f32; 15]];
3315 let g1a = vec![vec![0.0f32; 15]]; let g2a = vec![vec![0.0f32; 15]];
3317 let b = vec![vec![0.0f32; 15]];
3318 let (z0, z1) = acpl_module2(&x0, &x1, &y, &g1, &g2, &g1a, &g2a, &b, 15, false, &[]);
3319 let last = num_ts - 1;
3323 let (z0r, z0i) = z0[last][5];
3324 let (z1r, z1i) = z1[last][5];
3325 assert!((z0r - 2.0).abs() < 1e-5, "z0r={z0r} expected 2.0");
3326 assert!((z0i - 1.0).abs() < 1e-5, "z0i={z0i} expected 1.0");
3327 assert!((z1r - 2.0).abs() < 1e-5, "z1r={z1r}");
3328 assert!((z1i - 1.0).abs() < 1e-5, "z1i={z1i}");
3329 }
3330
3331 #[test]
3334 fn acpl_module3_adds_decorrelator_residual() {
3335 let num_ts = 4usize;
3336 let mut z0 = vec![[(1.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3337 let mut z1 = vec![[(0.0f32, 1.0f32); NUM_QMF_SUBBANDS]; num_ts];
3338 let y2 = vec![[(4.0f32, 4.0f32); NUM_QMF_SUBBANDS]; num_ts];
3339 let b3 = vec![vec![1.0f32; 15]];
3340 let b3a = vec![vec![0.0f32; 15]];
3341 acpl_module3(&mut z0, &mut z1, &y2, &b3, &b3a, 15, false, &[]);
3342 let last = num_ts - 1;
3346 let (z0r, z0i) = z0[last][7];
3347 assert!((z0r - 2.0).abs() < 1e-5, "z0r={z0r}");
3348 assert!((z0i - 1.0).abs() < 1e-5, "z0i={z0i}");
3349 let (z1r, z1i) = z1[last][7];
3350 assert!((z1r - 1.0).abs() < 1e-5, "z1r={z1r}");
3351 assert!((z1i - 2.0).abs() < 1e-5, "z1i={z1i}");
3352 }
3353
3354 #[test]
3356 fn acpl_module3_zero_beta3_is_noop() {
3357 let num_ts = 4usize;
3358 let mut z0 = vec![[(7.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3359 let mut z1 = vec![[(0.0f32, 7.0f32); NUM_QMF_SUBBANDS]; num_ts];
3360 let y2 = vec![[(99.0f32, -99.0f32); NUM_QMF_SUBBANDS]; num_ts];
3361 let zero = vec![vec![0.0f32; 15]];
3362 acpl_module3(&mut z0, &mut z1, &y2, &zero, &zero, 15, false, &[]);
3363 for ts in 0..num_ts {
3364 for sb in 0..NUM_QMF_SUBBANDS {
3365 assert_eq!(z0[ts][sb], (7.0, 0.0));
3366 assert_eq!(z1[ts][sb], (0.0, 7.0));
3367 }
3368 }
3369 }
3370
3371 #[test]
3375 fn run_pseudocode_118_5x_emits_five_finite_channels() {
3376 let num_ts = 16usize;
3377 let num_pb = 9u32;
3378 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3379 let mut x1 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3380 let mut x2 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3381 for ts in 0..num_ts {
3382 for sb in 0..32 {
3383 let p = (ts as f32) * 0.2 + sb as f32 * 0.05;
3384 x0[ts][sb] = (0.1 * p.cos(), 0.1 * p.sin());
3385 x1[ts][sb] = (0.05 * p.sin(), 0.05 * p.cos());
3386 x2[ts][sb] = (0.03 * (p * 1.3).cos(), 0.0);
3387 }
3388 }
3389 let alpha_1 = vec![vec![0.4f32; num_pb as usize]];
3390 let alpha_2 = vec![vec![-0.2f32; num_pb as usize]];
3391 let beta_1 = vec![vec![0.3f32; num_pb as usize]];
3392 let beta_2 = vec![vec![0.2f32; num_pb as usize]];
3393 let beta_3 = vec![vec![0.15f32; num_pb as usize]];
3394 let g1 = vec![vec![0.6f32; num_pb as usize]];
3395 let g2 = vec![vec![0.3f32; num_pb as usize]];
3396 let g3 = vec![vec![0.2f32; num_pb as usize]];
3397 let g4 = vec![vec![0.5f32; num_pb as usize]];
3398 let g5 = vec![vec![0.1f32; num_pb as usize]];
3399 let g6 = vec![vec![0.1f32; num_pb as usize]];
3400 let mut state = AcplMchState::new();
3401 let frame = AcplMchFrame {
3402 x0: &x0,
3403 x1: &x1,
3404 x2: &x2,
3405 alpha_1_dq: &alpha_1,
3406 alpha_2_dq: &alpha_2,
3407 beta_1_dq: &beta_1,
3408 beta_2_dq: &beta_2,
3409 beta_3_dq: &beta_3,
3410 g1_dq: &g1,
3411 g2_dq: &g2,
3412 g3_dq: &g3,
3413 g4_dq: &g4,
3414 g5_dq: &g5,
3415 g6_dq: &g6,
3416 num_param_bands: num_pb,
3417 steep: false,
3418 param_timeslots: &[],
3419 };
3420 let out = run_pseudocode_118_5x(&mut state, frame);
3421 assert_eq!(out.z0.len(), num_ts);
3422 assert_eq!(out.z1.len(), num_ts);
3423 assert_eq!(out.z2.len(), num_ts);
3424 assert_eq!(out.z3.len(), num_ts);
3425 assert_eq!(out.z4.len(), num_ts);
3426 for z in [&out.z0, &out.z1, &out.z2, &out.z3, &out.z4] {
3428 for col in z.iter() {
3429 for sb in 0..NUM_QMF_SUBBANDS {
3430 assert!(
3431 col[sb].0.is_finite() && col[sb].1.is_finite(),
3432 "non-finite output: {:?}",
3433 col[sb]
3434 );
3435 }
3436 }
3437 }
3438 for (name, z) in [
3441 ("z0=L", &out.z0),
3442 ("z1=Ls", &out.z1),
3443 ("z2=R", &out.z2),
3444 ("z3=Rs", &out.z3),
3445 ("z4=C", &out.z4),
3446 ] {
3447 let e: f64 = z
3448 .iter()
3449 .flat_map(|col| col.iter())
3450 .map(|s| (s.0 as f64).powi(2) + (s.1 as f64).powi(2))
3451 .sum();
3452 assert!(e > 0.0, "channel {name} silent (energy {e})");
3453 }
3454 assert_eq!(state.g1_prev_sb.len(), NUM_QMF_SUBBANDS);
3456 for sb in 0..NUM_QMF_SUBBANDS {
3457 assert!((state.g1_prev_sb[sb] - 0.6).abs() < 1e-6);
3458 }
3459 }
3460
3461 #[test]
3465 fn run_pseudocode_118_5x_zero_alpha_beta_remains_finite() {
3466 let num_ts = 8usize;
3467 let num_pb = 9u32;
3468 let x0 = vec![[(0.5f32, 0.5f32); NUM_QMF_SUBBANDS]; num_ts];
3469 let x1 = vec![[(0.5f32, -0.5f32); NUM_QMF_SUBBANDS]; num_ts];
3470 let x2 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3471 let zero = vec![vec![0.0f32; num_pb as usize]];
3472 let g1 = vec![vec![1.0f32; num_pb as usize]]; let mut state = AcplMchState::new();
3474 let frame = AcplMchFrame {
3475 x0: &x0,
3476 x1: &x1,
3477 x2: &x2,
3478 alpha_1_dq: &zero,
3479 alpha_2_dq: &zero,
3480 beta_1_dq: &zero,
3481 beta_2_dq: &zero,
3482 beta_3_dq: &zero,
3483 g1_dq: &g1,
3484 g2_dq: &zero,
3485 g3_dq: &zero,
3486 g4_dq: &zero,
3487 g5_dq: &zero,
3488 g6_dq: &zero,
3489 num_param_bands: num_pb,
3490 steep: false,
3491 param_timeslots: &[],
3492 };
3493 let out = run_pseudocode_118_5x(&mut state, frame);
3494 for col in out.z0.iter() {
3495 for sb in 0..NUM_QMF_SUBBANDS {
3496 assert!(col[sb].0.is_finite());
3497 assert!(col[sb].1.is_finite());
3498 }
3499 }
3500 }
3501
3502 #[test]
3504 fn pb_matrix_helpers() {
3505 let a = vec![vec![1.0f32, 2.0, 3.0]];
3506 let b = vec![vec![10.0f32, 20.0, 30.0]];
3507 let c = vec![vec![100.0f32, 200.0, 300.0]];
3508 let prod = pb_matrix_mul(&a, &b);
3509 assert_eq!(prod, vec![vec![10.0, 40.0, 90.0]]);
3510 let sum = pb_matrix_sum3(&a, &b, &c);
3511 assert_eq!(sum, vec![vec![111.0, 222.0, 333.0]]);
3512 let scaled = pb_matrix_scale(&a, -2.0);
3513 assert_eq!(scaled, vec![vec![-2.0, -4.0, -6.0]]);
3514 }
3515
3516 #[test]
3519 fn pseudocode_118_scaling_factor() {
3520 let s = 1.0f32 + 2.0 * (0.5f32).sqrt();
3521 let expected = 1.0f32 + (2.0f32).sqrt();
3522 assert!((s - expected).abs() < 1e-6);
3523 }
3524
3525 #[test]
3527 fn acpl_mch_state_zero_init() {
3528 let s = AcplMchState::new();
3529 assert!(s.g1_prev_sb.iter().all(|&v| v == 0.0));
3530 assert!(s.g2_prev_sb.iter().all(|&v| v == 0.0));
3531 assert!(s.g3_prev_sb.iter().all(|&v| v == 0.0));
3532 assert!(s.g4_prev_sb.iter().all(|&v| v == 0.0));
3533 assert_eq!(s.g1_prev_sb.len(), NUM_QMF_SUBBANDS);
3534 }
3535
3536 #[test]
3544 fn acpl_5x_pair_state_initial_decorrelators() {
3545 let s = Acpl5xPairState::new();
3546 assert!(matches!(s.left_pair.decorrelator.which, DecorrelatorId::D0));
3547 assert!(matches!(
3548 s.right_pair.decorrelator.which,
3549 DecorrelatorId::D1
3550 ));
3551 assert!(s.left_pair.alpha_prev_sb.iter().all(|&v| v == 0.0));
3552 assert!(s.right_pair.alpha_prev_sb.iter().all(|&v| v == 0.0));
3553 assert!(s.alpha1_diff.q_prev.is_empty());
3554 assert!(s.alpha2_diff.q_prev.is_empty());
3555 }
3556
3557 #[test]
3567 fn run_pseudocode_117_5x_aspx_acpl_2_passthrough_centre_and_finite() {
3568 let num_ts = 16usize;
3569 let num_pb = 9u32;
3570 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3571 let mut x1 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3572 let mut x2 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3573 for ts in 0..num_ts {
3574 x0[ts][8] = (1.0, 0.0);
3575 x1[ts][12] = (0.0, 1.0);
3576 x2[ts][20] = (0.5, -0.5);
3577 }
3578 let alpha1 = vec![vec![0.3f32; num_pb as usize]];
3579 let beta1 = vec![vec![0.2f32; num_pb as usize]];
3580 let alpha2 = vec![vec![-0.4f32; num_pb as usize]];
3581 let beta2 = vec![vec![0.1f32; num_pb as usize]];
3582 let mut state = Acpl5xPairState::new();
3583 let frame = Acpl5xPairFrame {
3584 mode: Acpl5xPairMode::AspxAcpl2,
3585 x0: &x0,
3586 x1: &x1,
3587 x2: &x2,
3588 x3: None,
3589 x4: None,
3590 alpha_1_dq: &alpha1,
3591 beta_1_dq: &beta1,
3592 alpha_2_dq: &alpha2,
3593 beta_2_dq: &beta2,
3594 num_param_bands: num_pb,
3595 acpl_qmf_band: 0,
3596 steep_1: false,
3597 steep_2: false,
3598 param_timeslots_1: &[],
3599 param_timeslots_2: &[],
3600 };
3601 let out = run_pseudocode_117_5x(&mut state, frame);
3602 assert_eq!(out.z0.len(), num_ts);
3603 assert_eq!(out.z1.len(), num_ts);
3604 assert_eq!(out.z2.len(), num_ts);
3605 assert_eq!(out.z3.len(), num_ts);
3606 assert_eq!(out.z4.len(), num_ts);
3607 for ts in 0..num_ts {
3609 for sb in 0..NUM_QMF_SUBBANDS {
3610 assert_eq!(out.z4[ts][sb], x2[ts][sb], "z4 != x2 at ts={ts} sb={sb}");
3611 }
3612 }
3613 for ts in 0..num_ts {
3615 for sb in 0..NUM_QMF_SUBBANDS {
3616 for (re, im) in [
3617 out.z0[ts][sb],
3618 out.z1[ts][sb],
3619 out.z2[ts][sb],
3620 out.z3[ts][sb],
3621 out.z4[ts][sb],
3622 ] {
3623 assert!(re.is_finite(), "non-finite re at ts={ts} sb={sb}");
3624 assert!(im.is_finite(), "non-finite im at ts={ts} sb={sb}");
3625 }
3626 }
3627 }
3628 }
3629
3630 #[test]
3638 fn run_pseudocode_117_5x_aspx_acpl_1_low_band_ms_split() {
3639 let num_ts = 4usize;
3640 let num_pb = 9u32;
3641 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3642 let mut x1 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3643 let x2 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3644 let mut x3 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3645 let mut x4 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3646 for ts in 0..num_ts {
3648 x0[ts][2] = (0.7, 0.0);
3649 x3[ts][2] = (0.3, 0.0);
3650 x1[ts][2] = (0.5, 0.5);
3651 x4[ts][2] = (0.1, -0.1);
3652 }
3653 let alpha1 = vec![vec![0.0f32; num_pb as usize]];
3654 let beta1 = vec![vec![0.0f32; num_pb as usize]];
3655 let alpha2 = vec![vec![0.0f32; num_pb as usize]];
3656 let beta2 = vec![vec![0.0f32; num_pb as usize]];
3657 let mut state = Acpl5xPairState::new();
3658 let frame = Acpl5xPairFrame {
3659 mode: Acpl5xPairMode::AspxAcpl1,
3660 x0: &x0,
3661 x1: &x1,
3662 x2: &x2,
3663 x3: Some(&x3),
3664 x4: Some(&x4),
3665 alpha_1_dq: &alpha1,
3666 beta_1_dq: &beta1,
3667 alpha_2_dq: &alpha2,
3668 beta_2_dq: &beta2,
3669 num_param_bands: num_pb,
3670 acpl_qmf_band: NUM_QMF_SUBBANDS as u32,
3673 steep_1: false,
3674 steep_2: false,
3675 param_timeslots_1: &[],
3676 param_timeslots_2: &[],
3677 };
3678 let out = run_pseudocode_117_5x(&mut state, frame);
3679 let sq2 = (2.0f32).sqrt();
3680 for ts in 0..num_ts {
3681 let (z0r, z0i) = out.z0[ts][2];
3685 let (z1r, z1i) = out.z1[ts][2];
3686 assert!((z0r - 1.0).abs() < 1e-5, "ts={ts} z0r={z0r}");
3687 assert!((z0i - 0.0).abs() < 1e-5, "ts={ts} z0i={z0i}");
3688 assert!(
3689 (z1r - 0.4 * sq2).abs() < 1e-5,
3690 "ts={ts} z1r={z1r} expected={}",
3691 0.4 * sq2
3692 );
3693 assert!((z1i - 0.0).abs() < 1e-5, "ts={ts} z1i={z1i}");
3694 let (z2r, z2i) = out.z2[ts][2];
3698 let (z3r, z3i) = out.z3[ts][2];
3699 assert!((z2r - 0.6).abs() < 1e-5, "ts={ts} z2r={z2r}");
3700 assert!((z2i - 0.4).abs() < 1e-5, "ts={ts} z2i={z2i}");
3701 assert!(
3702 (z3r - 0.4 * sq2).abs() < 1e-5,
3703 "ts={ts} z3r={z3r} expected={}",
3704 0.4 * sq2
3705 );
3706 assert!(
3707 (z3i - 0.6 * sq2).abs() < 1e-5,
3708 "ts={ts} z3i={z3i} expected={}",
3709 0.6 * sq2
3710 );
3711 }
3712 }
3713
3714 #[test]
3720 fn run_pseudocode_117_5x_state_carries_across_frames() {
3721 let num_ts = 8usize;
3722 let num_pb = 9u32;
3723 let x0 = vec![[(1.0f32, 0.5f32); NUM_QMF_SUBBANDS]; num_ts];
3724 let x1 = vec![[(0.5f32, 1.0f32); NUM_QMF_SUBBANDS]; num_ts];
3725 let x2 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3726 let alpha1 = vec![vec![0.42f32; num_pb as usize]];
3727 let beta1 = vec![vec![0.13f32; num_pb as usize]];
3728 let alpha2 = vec![vec![-0.11f32; num_pb as usize]];
3729 let beta2 = vec![vec![0.21f32; num_pb as usize]];
3730 let mut state = Acpl5xPairState::new();
3731 assert!(state.left_pair.alpha_prev_sb.iter().all(|&v| v == 0.0));
3733 assert!(state.right_pair.alpha_prev_sb.iter().all(|&v| v == 0.0));
3734 let frame = Acpl5xPairFrame {
3735 mode: Acpl5xPairMode::AspxAcpl2,
3736 x0: &x0,
3737 x1: &x1,
3738 x2: &x2,
3739 x3: None,
3740 x4: None,
3741 alpha_1_dq: &alpha1,
3742 beta_1_dq: &beta1,
3743 alpha_2_dq: &alpha2,
3744 beta_2_dq: &beta2,
3745 num_param_bands: num_pb,
3746 acpl_qmf_band: 0,
3747 steep_1: false,
3748 steep_2: false,
3749 param_timeslots_1: &[],
3750 param_timeslots_2: &[],
3751 };
3752 let _out1 = run_pseudocode_117_5x(&mut state, frame);
3753 for sb in 0..NUM_QMF_SUBBANDS {
3757 assert!(
3758 (state.left_pair.alpha_prev_sb[sb] - 0.42).abs() < 1e-6,
3759 "left alpha_prev[{sb}] = {}",
3760 state.left_pair.alpha_prev_sb[sb]
3761 );
3762 assert!(
3763 (state.right_pair.alpha_prev_sb[sb] - (-0.11)).abs() < 1e-6,
3764 "right alpha_prev[{sb}] = {}",
3765 state.right_pair.alpha_prev_sb[sb]
3766 );
3767 assert!(
3768 (state.left_pair.beta_prev_sb[sb] - 0.13).abs() < 1e-6,
3769 "left beta_prev[{sb}] = {}",
3770 state.left_pair.beta_prev_sb[sb]
3771 );
3772 assert!(
3773 (state.right_pair.beta_prev_sb[sb] - 0.21).abs() < 1e-6,
3774 "right beta_prev[{sb}] = {}",
3775 state.right_pair.beta_prev_sb[sb]
3776 );
3777 }
3778 }
3779
3780 #[test]
3786 fn run_pseudocode_117_5x_aspx_acpl_2_matches_two_115_passes() {
3787 let num_ts = 12usize;
3788 let num_pb = 9u32;
3789 let mut x0 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3790 let mut x1 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3791 let x2 = vec![[(0.0f32, 0.0f32); NUM_QMF_SUBBANDS]; num_ts];
3792 for ts in 0..num_ts {
3793 for sb in 0..32 {
3794 let phase = (ts as f32 * 0.2) + (sb as f32 * 0.1);
3795 x0[ts][sb] = (0.1 * phase.cos(), 0.1 * phase.sin());
3796 x1[ts][sb] = (0.05 * phase.sin(), 0.05 * phase.cos());
3797 }
3798 }
3799 let alpha1 = vec![vec![0.3f32; num_pb as usize]];
3800 let beta1 = vec![vec![0.2f32; num_pb as usize]];
3801 let alpha2 = vec![vec![0.1f32; num_pb as usize]];
3802 let beta2 = vec![vec![0.4f32; num_pb as usize]];
3803 let mut ref_state_l = AcplCpeState::new(DecorrelatorId::D0);
3805 let mut ref_state_r = AcplCpeState::new(DecorrelatorId::D1);
3806 let ref_l = run_pseudocode_115_pair(
3807 &mut ref_state_l,
3808 AcplCpeFrame {
3809 x0: &x0,
3810 x1: None,
3811 alpha_dq: &alpha1,
3812 beta_dq: &beta1,
3813 num_param_bands: num_pb,
3814 acpl_qmf_band: 0,
3815 steep: false,
3816 param_timeslots: &[],
3817 },
3818 );
3819 let ref_r = run_pseudocode_115_pair(
3820 &mut ref_state_r,
3821 AcplCpeFrame {
3822 x0: &x1,
3823 x1: None,
3824 alpha_dq: &alpha2,
3825 beta_dq: &beta2,
3826 num_param_bands: num_pb,
3827 acpl_qmf_band: 0,
3828 steep: false,
3829 param_timeslots: &[],
3830 },
3831 );
3832 let mut state = Acpl5xPairState::new();
3835 let frame = Acpl5xPairFrame {
3836 mode: Acpl5xPairMode::AspxAcpl2,
3837 x0: &x0,
3838 x1: &x1,
3839 x2: &x2,
3840 x3: None,
3841 x4: None,
3842 alpha_1_dq: &alpha1,
3843 beta_1_dq: &beta1,
3844 alpha_2_dq: &alpha2,
3845 beta_2_dq: &beta2,
3846 num_param_bands: num_pb,
3847 acpl_qmf_band: 0,
3848 steep_1: false,
3849 steep_2: false,
3850 param_timeslots_1: &[],
3851 param_timeslots_2: &[],
3852 };
3853 let out = run_pseudocode_117_5x(&mut state, frame);
3854 let sq2 = (2.0f32).sqrt();
3855 for ts in 0..num_ts {
3857 for sb in [0usize, 5, 16, 31, 47, 63] {
3858 let (a_r, a_i) = out.z0[ts][sb];
3859 let (e_r, e_i) = ref_l.z0[ts][sb];
3860 assert!(
3861 (a_r - e_r).abs() < 1e-5 && (a_i - e_i).abs() < 1e-5,
3862 "z0 mismatch ts={ts} sb={sb} got ({a_r},{a_i}) want ({e_r},{e_i})"
3863 );
3864 let (a_r, a_i) = out.z2[ts][sb];
3865 let (e_r, e_i) = ref_r.z0[ts][sb];
3866 assert!(
3867 (a_r - e_r).abs() < 1e-5 && (a_i - e_i).abs() < 1e-5,
3868 "z2 mismatch ts={ts} sb={sb} got ({a_r},{a_i}) want ({e_r},{e_i})"
3869 );
3870 let (a_r, a_i) = out.z1[ts][sb];
3871 let (e_r, e_i) = (ref_l.z1[ts][sb].0 * sq2, ref_l.z1[ts][sb].1 * sq2);
3872 assert!(
3873 (a_r - e_r).abs() < 1e-5 && (a_i - e_i).abs() < 1e-5,
3874 "z1 mismatch ts={ts} sb={sb} got ({a_r},{a_i}) want ({e_r},{e_i})"
3875 );
3876 let (a_r, a_i) = out.z3[ts][sb];
3877 let (e_r, e_i) = (ref_r.z1[ts][sb].0 * sq2, ref_r.z1[ts][sb].1 * sq2);
3878 assert!(
3879 (a_r - e_r).abs() < 1e-5 && (a_i - e_i).abs() < 1e-5,
3880 "z3 mismatch ts={ts} sb={sb} got ({a_r},{a_i}) want ({e_r},{e_i})"
3881 );
3882 }
3883 }
3884 }
3885
3886 #[test]
3894 fn run_acpl_5x_pair_pcm_rejects_misaligned_inputs() {
3895 use crate::acpl::{
3896 AcplConfig1ch, AcplData1ch, AcplFramingData, AcplHuffParam, AcplInterpolationType,
3897 AcplQuantMode,
3898 };
3899 let cfg = AcplConfig1ch {
3900 num_param_bands_id: 0,
3901 num_param_bands: 15,
3902 quant_mode: AcplQuantMode::Fine,
3903 qmf_band: 0,
3904 };
3905 let data = AcplData1ch {
3906 framing: AcplFramingData {
3907 interpolation_type: AcplInterpolationType::Smooth,
3908 num_param_sets_cod: 0,
3909 num_param_sets: 1,
3910 param_timeslots: vec![],
3911 },
3912 alpha1: vec![AcplHuffParam {
3913 values: vec![4i32; cfg.num_param_bands as usize],
3914 direction_time: false,
3915 }],
3916 beta1: vec![AcplHuffParam {
3917 values: vec![2i32; cfg.num_param_bands as usize],
3918 direction_time: false,
3919 }],
3920 };
3921 let mut state = Acpl5xPairPcmState::new();
3922 let pcm_short = vec![0.0f32; 65];
3924 assert!(run_acpl_5x_pair_pcm(
3925 Acpl5xPairMode::AspxAcpl2,
3926 &pcm_short,
3927 &pcm_short,
3928 &pcm_short,
3929 None,
3930 None,
3931 &cfg,
3932 &data,
3933 &cfg,
3934 &data,
3935 &mut state,
3936 )
3937 .is_none());
3938 let pcm = vec![0.0f32; 64];
3940 assert!(run_acpl_5x_pair_pcm(
3941 Acpl5xPairMode::AspxAcpl2,
3942 &pcm,
3943 &pcm,
3944 &pcm,
3945 Some(&pcm),
3946 Some(&pcm),
3947 &cfg,
3948 &data,
3949 &cfg,
3950 &data,
3951 &mut state,
3952 )
3953 .is_none());
3954 assert!(run_acpl_5x_pair_pcm(
3956 Acpl5xPairMode::AspxAcpl1,
3957 &pcm,
3958 &pcm,
3959 &pcm,
3960 None,
3961 None,
3962 &cfg,
3963 &data,
3964 &cfg,
3965 &data,
3966 &mut state,
3967 )
3968 .is_none());
3969 }
3970
3971 #[test]
3975 fn run_acpl_5x_pair_pcm_aspx_acpl_2_emits_five_channels() {
3976 use crate::acpl::{
3977 AcplConfig1ch, AcplData1ch, AcplFramingData, AcplHuffParam, AcplInterpolationType,
3978 AcplQuantMode,
3979 };
3980 let n_slots = 64usize;
3981 let n = n_slots * NUM_QMF_SUBBANDS;
3982 let mut pcm_l = vec![0.0f32; n];
3983 let mut pcm_r = vec![0.0f32; n];
3984 let mut pcm_c = vec![0.0f32; n];
3985 let f_l = 440.0f32 / 48_000.0;
3986 let f_r = 220.0f32 / 48_000.0;
3987 let f_c = 880.0f32 / 48_000.0;
3988 for i in 0..n {
3989 pcm_l[i] = (2.0 * std::f32::consts::PI * f_l * i as f32).sin();
3990 pcm_r[i] = 0.5 * (2.0 * std::f32::consts::PI * f_r * i as f32).sin();
3991 pcm_c[i] = 0.3 * (2.0 * std::f32::consts::PI * f_c * i as f32).sin();
3992 }
3993 let cfg = AcplConfig1ch {
3994 num_param_bands_id: 0,
3995 num_param_bands: 15,
3996 quant_mode: AcplQuantMode::Fine,
3997 qmf_band: 0,
3998 };
3999 let data1 = AcplData1ch {
4000 framing: AcplFramingData {
4001 interpolation_type: AcplInterpolationType::Smooth,
4002 num_param_sets_cod: 0,
4003 num_param_sets: 1,
4004 param_timeslots: vec![],
4005 },
4006 alpha1: vec![AcplHuffParam {
4007 values: vec![4i32; cfg.num_param_bands as usize],
4008 direction_time: false,
4009 }],
4010 beta1: vec![AcplHuffParam {
4011 values: vec![2i32; cfg.num_param_bands as usize],
4012 direction_time: false,
4013 }],
4014 };
4015 let data2 = AcplData1ch {
4016 framing: AcplFramingData {
4017 interpolation_type: AcplInterpolationType::Smooth,
4018 num_param_sets_cod: 0,
4019 num_param_sets: 1,
4020 param_timeslots: vec![],
4021 },
4022 alpha1: vec![AcplHuffParam {
4023 values: vec![-3i32; cfg.num_param_bands as usize],
4024 direction_time: false,
4025 }],
4026 beta1: vec![AcplHuffParam {
4027 values: vec![1i32; cfg.num_param_bands as usize],
4028 direction_time: false,
4029 }],
4030 };
4031 let mut state = Acpl5xPairPcmState::new();
4032 let out = run_acpl_5x_pair_pcm(
4033 Acpl5xPairMode::AspxAcpl2,
4034 &pcm_l,
4035 &pcm_r,
4036 &pcm_c,
4037 None,
4038 None,
4039 &cfg,
4040 &data1,
4041 &cfg,
4042 &data2,
4043 &mut state,
4044 )
4045 .expect("synth runs");
4046 assert_eq!(out.left.len(), n);
4047 assert_eq!(out.right.len(), n);
4048 assert_eq!(out.centre.len(), n);
4049 assert_eq!(out.left_surround.len(), n);
4050 assert_eq!(out.right_surround.len(), n);
4051 let start = 2048usize;
4052 let energy =
4053 |b: &[f32]| -> f64 { b[start..].iter().map(|&s| (s as f64).powi(2)).sum::<f64>() };
4054 assert!(energy(&out.left) > 1e-6, "left silent");
4055 assert!(energy(&out.right) > 1e-6, "right silent");
4056 assert!(energy(&out.centre) > 1e-6, "centre silent");
4057 assert!(energy(&out.left_surround) > 1e-6, "Ls silent");
4058 assert!(energy(&out.right_surround) > 1e-6, "Rs silent");
4059 for b in [
4060 &out.left,
4061 &out.right,
4062 &out.centre,
4063 &out.left_surround,
4064 &out.right_surround,
4065 ] {
4066 for &s in b.iter() {
4067 assert!(s.is_finite(), "non-finite sample");
4068 }
4069 }
4070 }
4071
4072 #[test]
4075 fn run_acpl_5x_mch_pcm_aspx_acpl_3_emits_five_channels() {
4076 use crate::acpl::{
4077 AcplConfig2ch, AcplData2ch, AcplFramingData, AcplHuffParam, AcplInterpolationType,
4078 AcplQuantMode,
4079 };
4080 let n_slots = 64usize;
4081 let n = n_slots * NUM_QMF_SUBBANDS;
4082 let mut pcm_l = vec![0.0f32; n];
4083 let mut pcm_r = vec![0.0f32; n];
4084 let mut pcm_c = vec![0.0f32; n];
4085 let f_l = 440.0f32 / 48_000.0;
4086 let f_r = 220.0f32 / 48_000.0;
4087 let f_c = 660.0f32 / 48_000.0;
4088 for i in 0..n {
4089 pcm_l[i] = (2.0 * std::f32::consts::PI * f_l * i as f32).sin();
4090 pcm_r[i] = (2.0 * std::f32::consts::PI * f_r * i as f32).cos();
4091 pcm_c[i] = 0.3 * (2.0 * std::f32::consts::PI * f_c * i as f32).sin();
4092 }
4093 let cfg = AcplConfig2ch {
4094 num_param_bands_id: 0,
4095 num_param_bands: 15,
4096 quant_mode_0: AcplQuantMode::Fine,
4097 quant_mode_1: AcplQuantMode::Fine,
4098 };
4099 let mk_huff = |seed: i32| AcplHuffParam {
4100 values: vec![seed; cfg.num_param_bands as usize],
4101 direction_time: false,
4102 };
4103 let data = AcplData2ch {
4104 framing: AcplFramingData {
4105 interpolation_type: AcplInterpolationType::Smooth,
4106 num_param_sets_cod: 0,
4107 num_param_sets: 1,
4108 param_timeslots: vec![],
4109 },
4110 alpha1: vec![mk_huff(4)],
4111 alpha2: vec![mk_huff(-3)],
4112 beta1: vec![mk_huff(2)],
4113 beta2: vec![mk_huff(1)],
4114 beta3: vec![mk_huff(0)],
4115 gamma1: vec![mk_huff(2)],
4116 gamma2: vec![mk_huff(0)],
4117 gamma3: vec![mk_huff(0)],
4118 gamma4: vec![mk_huff(2)],
4119 gamma5: vec![mk_huff(1)],
4120 gamma6: vec![mk_huff(1)],
4121 };
4122 let mut state = Acpl5xMchPcmState::new();
4123 let pcm_bad = vec![0.0f32; 65];
4125 assert!(
4126 run_acpl_5x_mch_pcm(&pcm_bad, &pcm_bad, &pcm_bad, &cfg, &data, &mut state).is_none()
4127 );
4128 let out = run_acpl_5x_mch_pcm(&pcm_l, &pcm_r, &pcm_c, &cfg, &data, &mut state)
4130 .expect("synth runs");
4131 assert_eq!(out.left.len(), n);
4132 assert_eq!(out.right.len(), n);
4133 assert_eq!(out.centre.len(), n);
4134 assert_eq!(out.left_surround.len(), n);
4135 assert_eq!(out.right_surround.len(), n);
4136 let start = 2048usize;
4137 let energy =
4138 |b: &[f32]| -> f64 { b[start..].iter().map(|&s| (s as f64).powi(2)).sum::<f64>() };
4139 for b in [
4140 &out.left,
4141 &out.right,
4142 &out.centre,
4143 &out.left_surround,
4144 &out.right_surround,
4145 ] {
4146 for &s in b.iter() {
4147 assert!(s.is_finite(), "non-finite sample");
4148 }
4149 }
4150 assert!(energy(&out.left) > 1e-6, "left silent");
4151 assert!(energy(&out.right) > 1e-6, "right silent");
4152 assert!(energy(&out.centre) > 1e-6, "centre silent");
4153 }
4154}