|
1 | 1 | use crate::silk::bwexpander_32::silk_bwexpander_32;
|
2 |
| -use crate::silk::define::MAX_LPC_STABILIZE_ITERATIONS; |
| 2 | +use crate::silk::define::{LSF_COS_TAB_SZ_FIX, MAX_LPC_STABILIZE_ITERATIONS}; |
3 | 3 | use crate::silk::table_LSF_cos::silk_LSFCosTab_FIX_Q12;
|
4 | 4 | use crate::silk::LPC_fit::silk_LPC_fit;
|
5 | 5 | use crate::silk::LPC_inv_pred_gain::silk_LPC_inverse_pred_gain_c;
|
6 |
| -use crate::silk::SigProc_FIX::{silk_RSHIFT_ROUND64, SILK_MAX_ORDER_LPC}; |
| 6 | +use crate::silk::SigProc_FIX::{silk_RSHIFT_ROUND, silk_RSHIFT_ROUND64, SILK_MAX_ORDER_LPC}; |
| 7 | +use ndarray::azip; |
7 | 8 |
|
8 | 9 | pub const QA: i32 = 16;
|
9 | 10 |
|
@@ -36,74 +37,86 @@ fn silk_NLSF2A_find_poly(out: &mut [i32], cLSF: &[i32]) {
|
36 | 37 | }
|
37 | 38 |
|
38 | 39 | /// compute whitening filter coefficients from normalized line spectral frequencies
|
39 |
| -pub unsafe fn silk_NLSF2A(a_Q12: *mut i16, NLSF: *const i16, d: i32, _arch: i32) { |
| 40 | +/// |
| 41 | +/// ```text |
| 42 | +/// a_Q12 O monic whitening filter coefficients in Q12, [ d ] |
| 43 | +/// NLSF I normalized line spectral frequencies in Q15, [ d ] |
| 44 | +/// d I filter order (should be even) |
| 45 | +/// arch I Run-time architecture |
| 46 | +/// ``` |
| 47 | +pub fn silk_NLSF2A(a_Q12: &mut [i16], NLSF: &[i16]) { |
| 48 | + let d = a_Q12.len(); |
| 49 | + |
| 50 | + /* This ordering was found to maximize quality. It improves the numerical accuracy of |
| 51 | + silk_NLSF2A_find_poly() compared to "standard" ordering. */ |
40 | 52 | static ordering16: [u8; 16] = [0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1];
|
41 | 53 | static ordering10: [u8; 10] = [0, 9, 6, 3, 4, 5, 8, 1, 2, 7];
|
42 |
| - let mut ordering: *const u8 = 0 as *const u8; |
43 |
| - let mut k: i32 = 0; |
44 |
| - let mut i: i32 = 0; |
45 |
| - let mut dd: i32 = 0; |
| 54 | + |
| 55 | + assert!(d == 10 || d == 16); |
| 56 | + |
| 57 | + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ |
| 58 | + let ordering = if d == 16 { |
| 59 | + ordering16.as_slice() |
| 60 | + } else { |
| 61 | + ordering10.as_slice() |
| 62 | + }; |
| 63 | + |
46 | 64 | let mut cos_LSF_QA: [i32; SILK_MAX_ORDER_LPC] = [0; 24];
|
| 65 | + let cos_LSF_QA = &mut cos_LSF_QA[..d + 1]; |
| 66 | + azip!((&ordering in ordering, &NLSF in NLSF) { |
| 67 | + debug_assert!(NLSF >= 0); |
| 68 | + |
| 69 | + /* f_int on a scale 0-127 (rounded down) */ |
| 70 | + let f_int = NLSF as i32 >> (15 - 7); |
| 71 | + |
| 72 | + /* f_frac, range: 0..255 */ |
| 73 | + let f_frac = NLSF as i32 - (f_int << (15 - 7)); |
| 74 | + |
| 75 | + debug_assert!(f_int >= 0); |
| 76 | + debug_assert!(f_int < LSF_COS_TAB_SZ_FIX); |
| 77 | + |
| 78 | + /* Read start and end value from table */ |
| 79 | + let cos_val = silk_LSFCosTab_FIX_Q12[f_int as usize] as i32; /* Q12 */ |
| 80 | + let delta = silk_LSFCosTab_FIX_Q12[(f_int + 1) as usize] as i32 - cos_val; /* Q12, with a range of 0..200 */ |
| 81 | + |
| 82 | + cos_LSF_QA[ordering as usize] = |
| 83 | + silk_RSHIFT_ROUND((cos_val << 8) + delta * f_frac, 20 - QA); /* QA */ |
| 84 | + }); |
| 85 | + |
| 86 | + let dd = d / 2; |
| 87 | + |
| 88 | + /* generate even and odd polynomials using convolution */ |
47 | 89 | let mut P: [i32; SILK_MAX_ORDER_LPC / 2 + 1] = [0; 13];
|
48 | 90 | let mut Q: [i32; SILK_MAX_ORDER_LPC / 2 + 1] = [0; 13];
|
49 |
| - let mut Ptmp: i32 = 0; |
50 |
| - let mut Qtmp: i32 = 0; |
51 |
| - let mut f_int: i32 = 0; |
52 |
| - let mut f_frac: i32 = 0; |
53 |
| - let mut cos_val: i32 = 0; |
54 |
| - let mut delta: i32 = 0; |
| 91 | + let P = &mut P[..dd + 1]; |
| 92 | + let Q = &mut Q[..dd + 1]; |
| 93 | + silk_NLSF2A_find_poly(P, &cos_LSF_QA[..d]); |
| 94 | + silk_NLSF2A_find_poly(Q, &cos_LSF_QA[1..][..d]); |
| 95 | + |
| 96 | + /* convert even and odd polynomials to opus_int32 Q12 filter coefs */ |
55 | 97 | let mut a32_QA1: [i32; SILK_MAX_ORDER_LPC] = [0; 24];
|
56 |
| - assert!(d == 10 || d == 16); |
57 |
| - ordering = if d == 16 { |
58 |
| - ordering16.as_ptr() |
59 |
| - } else { |
60 |
| - ordering10.as_ptr() |
61 |
| - }; |
62 |
| - k = 0; |
63 |
| - while k < d { |
64 |
| - f_int = *NLSF.offset(k as isize) as i32 >> 15 - 7; |
65 |
| - f_frac = *NLSF.offset(k as isize) as i32 - ((f_int as u32) << 15 - 7) as i32; |
66 |
| - cos_val = silk_LSFCosTab_FIX_Q12[f_int as usize] as i32; |
67 |
| - delta = silk_LSFCosTab_FIX_Q12[(f_int + 1) as usize] as i32 - cos_val; |
68 |
| - cos_LSF_QA[*ordering.offset(k as isize) as usize] = if 20 - 16 == 1 { |
69 |
| - (((cos_val as u32) << 8) as i32 + delta * f_frac >> 1) |
70 |
| - + (((cos_val as u32) << 8) as i32 + delta * f_frac & 1) |
71 |
| - } else { |
72 |
| - (((cos_val as u32) << 8) as i32 + delta * f_frac >> 20 - 16 - 1) + 1 >> 1 |
73 |
| - }; |
74 |
| - k += 1; |
75 |
| - } |
76 |
| - dd = d >> 1; |
77 |
| - silk_NLSF2A_find_poly(&mut P[..dd as usize + 1], &cos_LSF_QA[..d as usize]); |
78 |
| - silk_NLSF2A_find_poly(&mut Q[..dd as usize + 1], &cos_LSF_QA[1..][..d as usize]); |
79 |
| - k = 0; |
80 |
| - while k < dd { |
81 |
| - Ptmp = P[(k + 1) as usize] + P[k as usize]; |
82 |
| - Qtmp = Q[(k + 1) as usize] - Q[k as usize]; |
83 |
| - a32_QA1[k as usize] = -Qtmp - Ptmp; |
84 |
| - a32_QA1[(d - k - 1) as usize] = Qtmp - Ptmp; |
85 |
| - k += 1; |
| 98 | + let a32_QA1 = &mut a32_QA1[..d]; |
| 99 | + for k in 0..dd { |
| 100 | + let Ptmp = P[k + 1] + P[k]; |
| 101 | + let Qtmp = Q[k + 1] - Q[k]; |
| 102 | + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ |
| 103 | + a32_QA1[k] = -Qtmp - Ptmp; /* QA+1 */ |
| 104 | + a32_QA1[d - k - 1] = Qtmp - Ptmp; /* QA+1 */ |
86 | 105 | }
|
87 |
| - silk_LPC_fit( |
88 |
| - std::slice::from_raw_parts_mut(a_Q12, d as usize), |
89 |
| - &mut a32_QA1[..d as usize], |
90 |
| - 12, |
91 |
| - QA + 1, |
92 |
| - ); |
93 |
| - i = 0; |
94 |
| - while silk_LPC_inverse_pred_gain_c(std::slice::from_raw_parts(a_Q12, d as usize)) == 0 |
95 |
| - && i < MAX_LPC_STABILIZE_ITERATIONS |
96 |
| - { |
97 |
| - silk_bwexpander_32(&mut a32_QA1[..d as usize], 65536 - ((2) << i) as i32); |
98 |
| - k = 0; |
99 |
| - while k < d { |
100 |
| - *a_Q12.offset(k as isize) = (if 16 + 1 - 12 == 1 { |
101 |
| - (a32_QA1[k as usize] >> 1) + (a32_QA1[k as usize] & 1) |
102 |
| - } else { |
103 |
| - (a32_QA1[k as usize] >> 16 + 1 - 12 - 1) + 1 >> 1 |
104 |
| - }) as i16; |
105 |
| - k += 1; |
106 |
| - } |
| 106 | + |
| 107 | + /* Convert int32 coefficients to Q12 int16 coefs */ |
| 108 | + silk_LPC_fit(a_Q12, &mut a32_QA1[..d], 12, QA + 1); |
| 109 | + |
| 110 | + let mut i = 0; |
| 111 | + while silk_LPC_inverse_pred_gain_c(a_Q12) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS { |
| 112 | + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ |
| 113 | + /* on the unscaled coefficients, convert to Q12 and measure again */ |
| 114 | + silk_bwexpander_32(a32_QA1, 65536 - (2 << i)); |
| 115 | + |
| 116 | + azip!((a_Q12 in &mut a_Q12[..], &a32_QA1 in &a32_QA1[..]) { |
| 117 | + *a_Q12 = silk_RSHIFT_ROUND(a32_QA1, QA + 1 - 12) as i16; /* QA+1 -> Q12 */ |
| 118 | + }); |
| 119 | + |
107 | 120 | i += 1;
|
108 | 121 | }
|
109 | 122 | }
|
0 commit comments