xref: /aosp_15_r20/external/liblc3/src/tns.c (revision 49fe348c0058011ee60b6957cdd9d52742df84bc)
1*49fe348cSAndroid Build Coastguard Worker /******************************************************************************
2*49fe348cSAndroid Build Coastguard Worker  *
3*49fe348cSAndroid Build Coastguard Worker  *  Copyright 2022 Google LLC
4*49fe348cSAndroid Build Coastguard Worker  *
5*49fe348cSAndroid Build Coastguard Worker  *  Licensed under the Apache License, Version 2.0 (the "License");
6*49fe348cSAndroid Build Coastguard Worker  *  you may not use this file except in compliance with the License.
7*49fe348cSAndroid Build Coastguard Worker  *  You may obtain a copy of the License at:
8*49fe348cSAndroid Build Coastguard Worker  *
9*49fe348cSAndroid Build Coastguard Worker  *  http://www.apache.org/licenses/LICENSE-2.0
10*49fe348cSAndroid Build Coastguard Worker  *
11*49fe348cSAndroid Build Coastguard Worker  *  Unless required by applicable law or agreed to in writing, software
12*49fe348cSAndroid Build Coastguard Worker  *  distributed under the License is distributed on an "AS IS" BASIS,
13*49fe348cSAndroid Build Coastguard Worker  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*49fe348cSAndroid Build Coastguard Worker  *  See the License for the specific language governing permissions and
15*49fe348cSAndroid Build Coastguard Worker  *  limitations under the License.
16*49fe348cSAndroid Build Coastguard Worker  *
17*49fe348cSAndroid Build Coastguard Worker  ******************************************************************************/
18*49fe348cSAndroid Build Coastguard Worker 
19*49fe348cSAndroid Build Coastguard Worker #include "tns.h"
20*49fe348cSAndroid Build Coastguard Worker #include "tables.h"
21*49fe348cSAndroid Build Coastguard Worker 
22*49fe348cSAndroid Build Coastguard Worker 
23*49fe348cSAndroid Build Coastguard Worker /* ----------------------------------------------------------------------------
24*49fe348cSAndroid Build Coastguard Worker  *  Filter Coefficients
25*49fe348cSAndroid Build Coastguard Worker  * -------------------------------------------------------------------------- */
26*49fe348cSAndroid Build Coastguard Worker 
27*49fe348cSAndroid Build Coastguard Worker /**
28*49fe348cSAndroid Build Coastguard Worker  * Resolve LPC Weighting indication according bitrate
29*49fe348cSAndroid Build Coastguard Worker  * dt, nbytes      Duration and size of the frame
30*49fe348cSAndroid Build Coastguard Worker  * return          True when LPC Weighting enabled
31*49fe348cSAndroid Build Coastguard Worker  */
resolve_lpc_weighting(enum lc3_dt dt,int nbytes)32*49fe348cSAndroid Build Coastguard Worker static bool resolve_lpc_weighting(enum lc3_dt dt, int nbytes)
33*49fe348cSAndroid Build Coastguard Worker {
34*49fe348cSAndroid Build Coastguard Worker     return nbytes * 8 < 120 * (int)(1 + dt);
35*49fe348cSAndroid Build Coastguard Worker }
36*49fe348cSAndroid Build Coastguard Worker 
37*49fe348cSAndroid Build Coastguard Worker /**
38*49fe348cSAndroid Build Coastguard Worker  * Return dot product of 2 vectors
39*49fe348cSAndroid Build Coastguard Worker  * a, b, n         The 2 vectors of size `n`
40*49fe348cSAndroid Build Coastguard Worker  * return          sum( a[i] * b[i] ), i = [0..n-1]
41*49fe348cSAndroid Build Coastguard Worker  */
dot(const float * a,const float * b,int n)42*49fe348cSAndroid Build Coastguard Worker LC3_HOT static inline float dot(const float *a, const float *b, int n)
43*49fe348cSAndroid Build Coastguard Worker {
44*49fe348cSAndroid Build Coastguard Worker     float v = 0;
45*49fe348cSAndroid Build Coastguard Worker 
46*49fe348cSAndroid Build Coastguard Worker     while (n--)
47*49fe348cSAndroid Build Coastguard Worker         v += *(a++) * *(b++);
48*49fe348cSAndroid Build Coastguard Worker 
49*49fe348cSAndroid Build Coastguard Worker     return v;
50*49fe348cSAndroid Build Coastguard Worker }
51*49fe348cSAndroid Build Coastguard Worker 
52*49fe348cSAndroid Build Coastguard Worker /**
53*49fe348cSAndroid Build Coastguard Worker  * LPC Coefficients
54*49fe348cSAndroid Build Coastguard Worker  * dt, bw          Duration and bandwidth of the frame
55*49fe348cSAndroid Build Coastguard Worker  * maxorder        Maximum order of filter
56*49fe348cSAndroid Build Coastguard Worker  * x               Spectral coefficients
57*49fe348cSAndroid Build Coastguard Worker  * gain, a         Output the prediction gains and LPC coefficients
58*49fe348cSAndroid Build Coastguard Worker  */
compute_lpc_coeffs(enum lc3_dt dt,enum lc3_bandwidth bw,int maxorder,const float * x,float * gain,float (* a)[9])59*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void compute_lpc_coeffs(
60*49fe348cSAndroid Build Coastguard Worker     enum lc3_dt dt, enum lc3_bandwidth bw, int maxorder,
61*49fe348cSAndroid Build Coastguard Worker     const float *x, float *gain, float (*a)[9])
62*49fe348cSAndroid Build Coastguard Worker {
63*49fe348cSAndroid Build Coastguard Worker 
64*49fe348cSAndroid Build Coastguard Worker #if LC3_PLUS
65*49fe348cSAndroid Build Coastguard Worker 
66*49fe348cSAndroid Build Coastguard Worker     static const int sub_2m5_nb[]   = {  3,  10,  20 };
67*49fe348cSAndroid Build Coastguard Worker     static const int sub_2m5_wb[]   = {  3,  20,  40 };
68*49fe348cSAndroid Build Coastguard Worker     static const int sub_2m5_sswb[] = {  3,  30,  60 };
69*49fe348cSAndroid Build Coastguard Worker     static const int sub_2m5_swb[]  = {  3,  40,  80 };
70*49fe348cSAndroid Build Coastguard Worker     static const int sub_2m5_fb[]   = {  3,  51, 100 };
71*49fe348cSAndroid Build Coastguard Worker 
72*49fe348cSAndroid Build Coastguard Worker     static const int sub_5m_nb[]    = {  6,  23,  40 };
73*49fe348cSAndroid Build Coastguard Worker     static const int sub_5m_wb[]    = {  6,  43,  80 };
74*49fe348cSAndroid Build Coastguard Worker     static const int sub_5m_sswb[]  = {  6,  63, 120 };
75*49fe348cSAndroid Build Coastguard Worker     static const int sub_5m_swb[]   = {  6,  43,  80, 120, 160 };
76*49fe348cSAndroid Build Coastguard Worker     static const int sub_5m_fb[]    = {  6,  53, 100, 150, 200 };
77*49fe348cSAndroid Build Coastguard Worker 
78*49fe348cSAndroid Build Coastguard Worker #endif /* LC3_PLUS */
79*49fe348cSAndroid Build Coastguard Worker 
80*49fe348cSAndroid Build Coastguard Worker     static const int sub_7m5_nb[]   = {  9,  26,  43,  60 };
81*49fe348cSAndroid Build Coastguard Worker     static const int sub_7m5_wb[]   = {  9,  46,  83, 120 };
82*49fe348cSAndroid Build Coastguard Worker     static const int sub_7m5_sswb[] = {  9,  66, 123, 180 };
83*49fe348cSAndroid Build Coastguard Worker     static const int sub_7m5_swb[]  = {  9,  46,  82, 120, 159, 200, 240 };
84*49fe348cSAndroid Build Coastguard Worker     static const int sub_7m5_fb[]   = {  9,  56, 103, 150, 200, 250, 300 };
85*49fe348cSAndroid Build Coastguard Worker 
86*49fe348cSAndroid Build Coastguard Worker     static const int sub_10m_nb[]   = { 12,  34,  57,  80 };
87*49fe348cSAndroid Build Coastguard Worker     static const int sub_10m_wb[]   = { 12,  61, 110, 160 };
88*49fe348cSAndroid Build Coastguard Worker     static const int sub_10m_sswb[] = { 12,  88, 164, 240 };
89*49fe348cSAndroid Build Coastguard Worker     static const int sub_10m_swb[]  = { 12,  61, 110, 160, 213, 266, 320 };
90*49fe348cSAndroid Build Coastguard Worker     static const int sub_10m_fb[]   = { 12,  74, 137, 200, 266, 333, 400 };
91*49fe348cSAndroid Build Coastguard Worker 
92*49fe348cSAndroid Build Coastguard Worker     static const float lag_window[] = {
93*49fe348cSAndroid Build Coastguard Worker         1.00000000e+00, 9.98028026e-01, 9.92135406e-01, 9.82391584e-01,
94*49fe348cSAndroid Build Coastguard Worker         9.68910791e-01, 9.51849807e-01, 9.31404933e-01, 9.07808230e-01,
95*49fe348cSAndroid Build Coastguard Worker         8.81323137e-01
96*49fe348cSAndroid Build Coastguard Worker     };
97*49fe348cSAndroid Build Coastguard Worker 
98*49fe348cSAndroid Build Coastguard Worker     const int *sub = (const int * const [LC3_NUM_DT][LC3_NUM_BANDWIDTH]){
99*49fe348cSAndroid Build Coastguard Worker 
100*49fe348cSAndroid Build Coastguard Worker #if LC3_PLUS
101*49fe348cSAndroid Build Coastguard Worker 
102*49fe348cSAndroid Build Coastguard Worker         [LC3_DT_2M5] = {
103*49fe348cSAndroid Build Coastguard Worker           sub_2m5_nb, sub_2m5_wb, sub_2m5_sswb, sub_2m5_swb,
104*49fe348cSAndroid Build Coastguard Worker           sub_2m5_fb, sub_2m5_fb, sub_2m5_fb                },
105*49fe348cSAndroid Build Coastguard Worker 
106*49fe348cSAndroid Build Coastguard Worker         [LC3_DT_5M] = {
107*49fe348cSAndroid Build Coastguard Worker             sub_5m_nb , sub_5m_wb , sub_5m_sswb , sub_5m_swb ,
108*49fe348cSAndroid Build Coastguard Worker             sub_5m_fb , sub_5m_fb , sub_5m_fb                 },
109*49fe348cSAndroid Build Coastguard Worker 
110*49fe348cSAndroid Build Coastguard Worker #endif /* LC3_PLUS */
111*49fe348cSAndroid Build Coastguard Worker 
112*49fe348cSAndroid Build Coastguard Worker         [LC3_DT_7M5] = {
113*49fe348cSAndroid Build Coastguard Worker             sub_7m5_nb, sub_7m5_wb, sub_7m5_sswb, sub_7m5_swb,
114*49fe348cSAndroid Build Coastguard Worker             sub_7m5_fb                                        },
115*49fe348cSAndroid Build Coastguard Worker 
116*49fe348cSAndroid Build Coastguard Worker         [LC3_DT_10M] = {
117*49fe348cSAndroid Build Coastguard Worker             sub_10m_nb, sub_10m_wb, sub_10m_sswb, sub_10m_swb,
118*49fe348cSAndroid Build Coastguard Worker             sub_10m_fb, sub_10m_fb, sub_10m_fb                },
119*49fe348cSAndroid Build Coastguard Worker 
120*49fe348cSAndroid Build Coastguard Worker     }[dt][bw];
121*49fe348cSAndroid Build Coastguard Worker 
122*49fe348cSAndroid Build Coastguard Worker     /* --- Normalized autocorrelation --- */
123*49fe348cSAndroid Build Coastguard Worker 
124*49fe348cSAndroid Build Coastguard Worker     int nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
125*49fe348cSAndroid Build Coastguard Worker     int nsubdivisions = 2 + (dt >= LC3_DT_7M5);
126*49fe348cSAndroid Build Coastguard Worker 
127*49fe348cSAndroid Build Coastguard Worker     const float *xs, *xe = x + *sub;
128*49fe348cSAndroid Build Coastguard Worker     float r[2][9];
129*49fe348cSAndroid Build Coastguard Worker 
130*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < nfilters; f++) {
131*49fe348cSAndroid Build Coastguard Worker         float c[9][3] = { 0 };
132*49fe348cSAndroid Build Coastguard Worker 
133*49fe348cSAndroid Build Coastguard Worker         for (int s = 0; s < nsubdivisions; s++) {
134*49fe348cSAndroid Build Coastguard Worker             xs = xe, xe = x + *(++sub);
135*49fe348cSAndroid Build Coastguard Worker 
136*49fe348cSAndroid Build Coastguard Worker             for (int k = 0; k <= maxorder; k++)
137*49fe348cSAndroid Build Coastguard Worker                 c[k][s] = dot(xs, xs + k, (xe - xs) - k);
138*49fe348cSAndroid Build Coastguard Worker         }
139*49fe348cSAndroid Build Coastguard Worker 
140*49fe348cSAndroid Build Coastguard Worker         r[f][0] = nsubdivisions;
141*49fe348cSAndroid Build Coastguard Worker         if (nsubdivisions == 2) {
142*49fe348cSAndroid Build Coastguard Worker             float e0 = c[0][0], e1 = c[0][1];
143*49fe348cSAndroid Build Coastguard Worker             for (int k = 1; k <= maxorder; k++)
144*49fe348cSAndroid Build Coastguard Worker                 r[f][k] = e0 == 0 || e1 == 0 ? 0 :
145*49fe348cSAndroid Build Coastguard Worker                   (c[k][0]/e0 + c[k][1]/e1) * lag_window[k];
146*49fe348cSAndroid Build Coastguard Worker 
147*49fe348cSAndroid Build Coastguard Worker         } else {
148*49fe348cSAndroid Build Coastguard Worker             float e0 = c[0][0], e1 = c[0][1], e2 = c[0][2];
149*49fe348cSAndroid Build Coastguard Worker             for (int k = 1; k <= maxorder; k++)
150*49fe348cSAndroid Build Coastguard Worker                 r[f][k] = e0 == 0 || e1 == 0 || e2 == 0 ? 0 :
151*49fe348cSAndroid Build Coastguard Worker                   (c[k][0]/e0 + c[k][1]/e1 + c[k][2]/e2) * lag_window[k];
152*49fe348cSAndroid Build Coastguard Worker         }
153*49fe348cSAndroid Build Coastguard Worker     }
154*49fe348cSAndroid Build Coastguard Worker 
155*49fe348cSAndroid Build Coastguard Worker     /* --- Levinson-Durbin recursion --- */
156*49fe348cSAndroid Build Coastguard Worker 
157*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < nfilters; f++) {
158*49fe348cSAndroid Build Coastguard Worker         float *a0 = a[f], a1[9];
159*49fe348cSAndroid Build Coastguard Worker         float err = r[f][0], rc;
160*49fe348cSAndroid Build Coastguard Worker 
161*49fe348cSAndroid Build Coastguard Worker         gain[f] = err;
162*49fe348cSAndroid Build Coastguard Worker 
163*49fe348cSAndroid Build Coastguard Worker         a0[0] = 1;
164*49fe348cSAndroid Build Coastguard Worker         for (int k = 1; k <= maxorder; ) {
165*49fe348cSAndroid Build Coastguard Worker 
166*49fe348cSAndroid Build Coastguard Worker             rc = -r[f][k];
167*49fe348cSAndroid Build Coastguard Worker             for (int i = 1; i < k; i++)
168*49fe348cSAndroid Build Coastguard Worker                 rc -= a0[i] * r[f][k-i];
169*49fe348cSAndroid Build Coastguard Worker 
170*49fe348cSAndroid Build Coastguard Worker             rc /= err;
171*49fe348cSAndroid Build Coastguard Worker             err *= 1 - rc * rc;
172*49fe348cSAndroid Build Coastguard Worker 
173*49fe348cSAndroid Build Coastguard Worker             for (int i = 1; i < k; i++)
174*49fe348cSAndroid Build Coastguard Worker                 a1[i] = a0[i] + rc * a0[k-i];
175*49fe348cSAndroid Build Coastguard Worker             a1[k++] = rc;
176*49fe348cSAndroid Build Coastguard Worker 
177*49fe348cSAndroid Build Coastguard Worker             rc = -r[f][k];
178*49fe348cSAndroid Build Coastguard Worker             for (int i = 1; i < k; i++)
179*49fe348cSAndroid Build Coastguard Worker                 rc -= a1[i] * r[f][k-i];
180*49fe348cSAndroid Build Coastguard Worker 
181*49fe348cSAndroid Build Coastguard Worker             rc /= err;
182*49fe348cSAndroid Build Coastguard Worker             err *= 1 - rc * rc;
183*49fe348cSAndroid Build Coastguard Worker 
184*49fe348cSAndroid Build Coastguard Worker             for (int i = 1; i < k; i++)
185*49fe348cSAndroid Build Coastguard Worker                 a0[i] = a1[i] + rc * a1[k-i];
186*49fe348cSAndroid Build Coastguard Worker             a0[k++] = rc;
187*49fe348cSAndroid Build Coastguard Worker         }
188*49fe348cSAndroid Build Coastguard Worker 
189*49fe348cSAndroid Build Coastguard Worker         gain[f] /= err;
190*49fe348cSAndroid Build Coastguard Worker     }
191*49fe348cSAndroid Build Coastguard Worker }
192*49fe348cSAndroid Build Coastguard Worker 
193*49fe348cSAndroid Build Coastguard Worker /**
194*49fe348cSAndroid Build Coastguard Worker  * LPC Weighting
195*49fe348cSAndroid Build Coastguard Worker  * gain, a         Prediction gain and LPC coefficients, weighted as output
196*49fe348cSAndroid Build Coastguard Worker  */
lpc_weighting(float pred_gain,float * a)197*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void lpc_weighting(float pred_gain, float *a)
198*49fe348cSAndroid Build Coastguard Worker {
199*49fe348cSAndroid Build Coastguard Worker     float gamma = 1.f - (1.f - 0.85f) * (2.f - pred_gain) / (2.f - 1.5f);
200*49fe348cSAndroid Build Coastguard Worker     float g = 1.f;
201*49fe348cSAndroid Build Coastguard Worker 
202*49fe348cSAndroid Build Coastguard Worker     for (int i = 1; i < 9; i++)
203*49fe348cSAndroid Build Coastguard Worker         a[i] *= (g *= gamma);
204*49fe348cSAndroid Build Coastguard Worker }
205*49fe348cSAndroid Build Coastguard Worker 
206*49fe348cSAndroid Build Coastguard Worker /**
207*49fe348cSAndroid Build Coastguard Worker  * LPC reflection
208*49fe348cSAndroid Build Coastguard Worker  * a, maxorder     LPC coefficients, and maximum order (4 or 8)
209*49fe348cSAndroid Build Coastguard Worker  * rc              Output refelection coefficients
210*49fe348cSAndroid Build Coastguard Worker  */
lpc_reflection(const float * a,int maxorder,float * rc)211*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void lpc_reflection(
212*49fe348cSAndroid Build Coastguard Worker     const float *a, int maxorder, float *rc)
213*49fe348cSAndroid Build Coastguard Worker {
214*49fe348cSAndroid Build Coastguard Worker     float e, b[2][7], *b0, *b1;
215*49fe348cSAndroid Build Coastguard Worker 
216*49fe348cSAndroid Build Coastguard Worker     rc[maxorder-1] = a[maxorder];
217*49fe348cSAndroid Build Coastguard Worker     e = 1 - rc[maxorder-1] * rc[maxorder-1];
218*49fe348cSAndroid Build Coastguard Worker 
219*49fe348cSAndroid Build Coastguard Worker     b1 = b[1];
220*49fe348cSAndroid Build Coastguard Worker     for (int i = 0; i < maxorder-1; i++)
221*49fe348cSAndroid Build Coastguard Worker         b1[i] = (a[1+i] - rc[maxorder-1] * a[(maxorder-1)-i]) / e;
222*49fe348cSAndroid Build Coastguard Worker 
223*49fe348cSAndroid Build Coastguard Worker     for (int k = maxorder-2; k > 0; k--) {
224*49fe348cSAndroid Build Coastguard Worker         b0 = b1, b1 = b[k & 1];
225*49fe348cSAndroid Build Coastguard Worker 
226*49fe348cSAndroid Build Coastguard Worker         rc[k] = b0[k];
227*49fe348cSAndroid Build Coastguard Worker         e = 1 - rc[k] * rc[k];
228*49fe348cSAndroid Build Coastguard Worker 
229*49fe348cSAndroid Build Coastguard Worker         for (int i = 0; i < k; i++)
230*49fe348cSAndroid Build Coastguard Worker             b1[i] = (b0[i] - rc[k] * b0[k-1-i]) / e;
231*49fe348cSAndroid Build Coastguard Worker     }
232*49fe348cSAndroid Build Coastguard Worker 
233*49fe348cSAndroid Build Coastguard Worker     rc[0] = b1[0];
234*49fe348cSAndroid Build Coastguard Worker }
235*49fe348cSAndroid Build Coastguard Worker 
236*49fe348cSAndroid Build Coastguard Worker /**
237*49fe348cSAndroid Build Coastguard Worker  * Quantization of RC coefficients
238*49fe348cSAndroid Build Coastguard Worker  * rc, maxorder    Refelection coefficients, and maximum order (4 or 8)
239*49fe348cSAndroid Build Coastguard Worker  * order           Return order of coefficients
240*49fe348cSAndroid Build Coastguard Worker  * rc_i            Return quantized coefficients
241*49fe348cSAndroid Build Coastguard Worker  */
quantize_rc(const float * rc,int maxorder,int * order,int * rc_q)242*49fe348cSAndroid Build Coastguard Worker static void quantize_rc(const float *rc, int maxorder, int *order, int *rc_q)
243*49fe348cSAndroid Build Coastguard Worker {
244*49fe348cSAndroid Build Coastguard Worker     /* Quantization table, sin(delta * (i + 0.5)), delta = Pi / 17,
245*49fe348cSAndroid Build Coastguard Worker      * rounded to fixed point Q15 value (LC3-Plus HR requirements). */
246*49fe348cSAndroid Build Coastguard Worker 
247*49fe348cSAndroid Build Coastguard Worker     static float q_thr[] = {
248*49fe348cSAndroid Build Coastguard Worker         0x0bcfp-15, 0x2307p-15, 0x390ep-15, 0x4d23p-15,
249*49fe348cSAndroid Build Coastguard Worker         0x5e98p-15, 0x6cd4p-15, 0x775bp-15, 0x7dd2p-15,
250*49fe348cSAndroid Build Coastguard Worker     };
251*49fe348cSAndroid Build Coastguard Worker 
252*49fe348cSAndroid Build Coastguard Worker     *order = maxorder;
253*49fe348cSAndroid Build Coastguard Worker 
254*49fe348cSAndroid Build Coastguard Worker     for (int i = 0; i < maxorder; i++) {
255*49fe348cSAndroid Build Coastguard Worker         float rc_m = fabsf(rc[i]);
256*49fe348cSAndroid Build Coastguard Worker 
257*49fe348cSAndroid Build Coastguard Worker         rc_q[i] = 4 * (rc_m >= q_thr[4]);
258*49fe348cSAndroid Build Coastguard Worker         for (int j = 0; j < 4 && rc_m >= q_thr[rc_q[i]]; j++, rc_q[i]++);
259*49fe348cSAndroid Build Coastguard Worker 
260*49fe348cSAndroid Build Coastguard Worker         if (rc[i] < 0)
261*49fe348cSAndroid Build Coastguard Worker             rc_q[i] = -rc_q[i];
262*49fe348cSAndroid Build Coastguard Worker 
263*49fe348cSAndroid Build Coastguard Worker         *order = rc_q[i] != 0 ? maxorder : *order - 1;
264*49fe348cSAndroid Build Coastguard Worker     }
265*49fe348cSAndroid Build Coastguard Worker }
266*49fe348cSAndroid Build Coastguard Worker 
267*49fe348cSAndroid Build Coastguard Worker /**
268*49fe348cSAndroid Build Coastguard Worker  * Unquantization of RC coefficients
269*49fe348cSAndroid Build Coastguard Worker  * rc_q, order     Quantized coefficients, and order
270*49fe348cSAndroid Build Coastguard Worker  * rc              Return refelection coefficients
271*49fe348cSAndroid Build Coastguard Worker  */
unquantize_rc(const int * rc_q,int order,float rc[8])272*49fe348cSAndroid Build Coastguard Worker static void unquantize_rc(const int *rc_q, int order, float rc[8])
273*49fe348cSAndroid Build Coastguard Worker {
274*49fe348cSAndroid Build Coastguard Worker     /* Quantization table, sin(delta * i), delta = Pi / 17,
275*49fe348cSAndroid Build Coastguard Worker      * rounded to fixed point Q15 value (LC3-Plus HR requirements). */
276*49fe348cSAndroid Build Coastguard Worker 
277*49fe348cSAndroid Build Coastguard Worker     static float q_inv[] = {
278*49fe348cSAndroid Build Coastguard Worker         0x0000p-15, 0x1785p-15, 0x2e3dp-15, 0x4362p-15,
279*49fe348cSAndroid Build Coastguard Worker         0x563cp-15, 0x6625p-15, 0x7295p-15, 0x7b1dp-15, 0x7f74p-15,
280*49fe348cSAndroid Build Coastguard Worker     };
281*49fe348cSAndroid Build Coastguard Worker 
282*49fe348cSAndroid Build Coastguard Worker     int i;
283*49fe348cSAndroid Build Coastguard Worker 
284*49fe348cSAndroid Build Coastguard Worker     for (i = 0; i < order; i++) {
285*49fe348cSAndroid Build Coastguard Worker         float rc_m = q_inv[LC3_ABS(rc_q[i])];
286*49fe348cSAndroid Build Coastguard Worker         rc[i] = rc_q[i] < 0 ? -rc_m : rc_m;
287*49fe348cSAndroid Build Coastguard Worker     }
288*49fe348cSAndroid Build Coastguard Worker }
289*49fe348cSAndroid Build Coastguard Worker 
290*49fe348cSAndroid Build Coastguard Worker 
291*49fe348cSAndroid Build Coastguard Worker /* ----------------------------------------------------------------------------
292*49fe348cSAndroid Build Coastguard Worker  *  Filtering
293*49fe348cSAndroid Build Coastguard Worker  * -------------------------------------------------------------------------- */
294*49fe348cSAndroid Build Coastguard Worker 
295*49fe348cSAndroid Build Coastguard Worker /**
296*49fe348cSAndroid Build Coastguard Worker  * Forward filtering
297*49fe348cSAndroid Build Coastguard Worker  * dt, bw          Duration and bandwidth of the frame
298*49fe348cSAndroid Build Coastguard Worker  * rc_order, rc    Order of coefficients, and coefficients
299*49fe348cSAndroid Build Coastguard Worker  * x               Spectral coefficients, filtered as output
300*49fe348cSAndroid Build Coastguard Worker  */
forward_filtering(enum lc3_dt dt,enum lc3_bandwidth bw,const int rc_order[2],float (* const rc)[8],float * x)301*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void forward_filtering(
302*49fe348cSAndroid Build Coastguard Worker     enum lc3_dt dt, enum lc3_bandwidth bw,
303*49fe348cSAndroid Build Coastguard Worker     const int rc_order[2], float (* const rc)[8], float *x)
304*49fe348cSAndroid Build Coastguard Worker {
305*49fe348cSAndroid Build Coastguard Worker     int nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
306*49fe348cSAndroid Build Coastguard Worker     int nf = lc3_ne(dt, (enum lc3_srate)LC3_MIN(bw, LC3_BANDWIDTH_FB))
307*49fe348cSAndroid Build Coastguard Worker                 >> (nfilters - 1);
308*49fe348cSAndroid Build Coastguard Worker     int i0, ie = 3*(1 + dt);
309*49fe348cSAndroid Build Coastguard Worker 
310*49fe348cSAndroid Build Coastguard Worker     float s[8] = { 0 };
311*49fe348cSAndroid Build Coastguard Worker 
312*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < nfilters; f++) {
313*49fe348cSAndroid Build Coastguard Worker 
314*49fe348cSAndroid Build Coastguard Worker         i0 = ie;
315*49fe348cSAndroid Build Coastguard Worker         ie = nf * (1 + f);
316*49fe348cSAndroid Build Coastguard Worker 
317*49fe348cSAndroid Build Coastguard Worker         if (!rc_order[f])
318*49fe348cSAndroid Build Coastguard Worker             continue;
319*49fe348cSAndroid Build Coastguard Worker 
320*49fe348cSAndroid Build Coastguard Worker         for (int i = i0; i < ie; i++) {
321*49fe348cSAndroid Build Coastguard Worker             float xi = x[i];
322*49fe348cSAndroid Build Coastguard Worker             float s0, s1 = xi;
323*49fe348cSAndroid Build Coastguard Worker 
324*49fe348cSAndroid Build Coastguard Worker             for (int k = 0; k < rc_order[f]; k++) {
325*49fe348cSAndroid Build Coastguard Worker                 s0 = s[k];
326*49fe348cSAndroid Build Coastguard Worker                 s[k] = s1;
327*49fe348cSAndroid Build Coastguard Worker 
328*49fe348cSAndroid Build Coastguard Worker                 s1  = rc[f][k] * xi + s0;
329*49fe348cSAndroid Build Coastguard Worker                 xi += rc[f][k] * s0;
330*49fe348cSAndroid Build Coastguard Worker             }
331*49fe348cSAndroid Build Coastguard Worker 
332*49fe348cSAndroid Build Coastguard Worker             x[i] = xi;
333*49fe348cSAndroid Build Coastguard Worker         }
334*49fe348cSAndroid Build Coastguard Worker     }
335*49fe348cSAndroid Build Coastguard Worker }
336*49fe348cSAndroid Build Coastguard Worker 
337*49fe348cSAndroid Build Coastguard Worker /**
338*49fe348cSAndroid Build Coastguard Worker  * Inverse filtering
339*49fe348cSAndroid Build Coastguard Worker  * dt, bw          Duration and bandwidth of the frame
340*49fe348cSAndroid Build Coastguard Worker  * rc_order, rc    Order of coefficients, and unquantized coefficients
341*49fe348cSAndroid Build Coastguard Worker  * x               Spectral coefficients, filtered as output
342*49fe348cSAndroid Build Coastguard Worker  */
inverse_filtering(enum lc3_dt dt,enum lc3_bandwidth bw,const int rc_order[2],float (* const rc)[8],float * x)343*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void inverse_filtering(
344*49fe348cSAndroid Build Coastguard Worker     enum lc3_dt dt, enum lc3_bandwidth bw,
345*49fe348cSAndroid Build Coastguard Worker     const int rc_order[2], float (* const rc)[8], float *x)
346*49fe348cSAndroid Build Coastguard Worker {
347*49fe348cSAndroid Build Coastguard Worker     int nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
348*49fe348cSAndroid Build Coastguard Worker     int nf = lc3_ne(dt, (enum lc3_srate)LC3_MIN(bw, LC3_BANDWIDTH_FB))
349*49fe348cSAndroid Build Coastguard Worker                 >> (nfilters - 1);
350*49fe348cSAndroid Build Coastguard Worker     int i0, ie = 3*(1 + dt);
351*49fe348cSAndroid Build Coastguard Worker 
352*49fe348cSAndroid Build Coastguard Worker     float s[8] = { 0 };
353*49fe348cSAndroid Build Coastguard Worker 
354*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < nfilters; f++) {
355*49fe348cSAndroid Build Coastguard Worker 
356*49fe348cSAndroid Build Coastguard Worker         i0 = ie;
357*49fe348cSAndroid Build Coastguard Worker         ie = nf * (1 + f);
358*49fe348cSAndroid Build Coastguard Worker 
359*49fe348cSAndroid Build Coastguard Worker         if (!rc_order[f])
360*49fe348cSAndroid Build Coastguard Worker             continue;
361*49fe348cSAndroid Build Coastguard Worker 
362*49fe348cSAndroid Build Coastguard Worker         for (int i = i0; i < ie; i++) {
363*49fe348cSAndroid Build Coastguard Worker             float xi = x[i];
364*49fe348cSAndroid Build Coastguard Worker 
365*49fe348cSAndroid Build Coastguard Worker             xi -= s[7] * rc[f][7];
366*49fe348cSAndroid Build Coastguard Worker             for (int k = 6; k >= 0; k--) {
367*49fe348cSAndroid Build Coastguard Worker                 xi -= s[k] * rc[f][k];
368*49fe348cSAndroid Build Coastguard Worker                 s[k+1] = s[k] + rc[f][k] * xi;
369*49fe348cSAndroid Build Coastguard Worker             }
370*49fe348cSAndroid Build Coastguard Worker             s[0] = xi;
371*49fe348cSAndroid Build Coastguard Worker             x[i] = xi;
372*49fe348cSAndroid Build Coastguard Worker         }
373*49fe348cSAndroid Build Coastguard Worker 
374*49fe348cSAndroid Build Coastguard Worker         for (int k = 7; k >= rc_order[f]; k--)
375*49fe348cSAndroid Build Coastguard Worker             s[k] = 0;
376*49fe348cSAndroid Build Coastguard Worker     }
377*49fe348cSAndroid Build Coastguard Worker }
378*49fe348cSAndroid Build Coastguard Worker 
379*49fe348cSAndroid Build Coastguard Worker 
380*49fe348cSAndroid Build Coastguard Worker /* ----------------------------------------------------------------------------
381*49fe348cSAndroid Build Coastguard Worker  *  Interface
382*49fe348cSAndroid Build Coastguard Worker  * -------------------------------------------------------------------------- */
383*49fe348cSAndroid Build Coastguard Worker 
384*49fe348cSAndroid Build Coastguard Worker /**
385*49fe348cSAndroid Build Coastguard Worker  * TNS analysis
386*49fe348cSAndroid Build Coastguard Worker  */
lc3_tns_analyze(enum lc3_dt dt,enum lc3_bandwidth bw,bool nn_flag,int nbytes,struct lc3_tns_data * data,float * x)387*49fe348cSAndroid Build Coastguard Worker void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw,
388*49fe348cSAndroid Build Coastguard Worker     bool nn_flag, int nbytes, struct lc3_tns_data *data, float *x)
389*49fe348cSAndroid Build Coastguard Worker {
390*49fe348cSAndroid Build Coastguard Worker     /* Processing steps :
391*49fe348cSAndroid Build Coastguard Worker      * - Determine the LPC (Linear Predictive Coding) Coefficients
392*49fe348cSAndroid Build Coastguard Worker      * - Check is the filtering is disabled
393*49fe348cSAndroid Build Coastguard Worker      * - The coefficients are weighted on low bitrates and predicition gain
394*49fe348cSAndroid Build Coastguard Worker      * - Convert to reflection coefficients and quantize
395*49fe348cSAndroid Build Coastguard Worker      * - Finally filter the spectral coefficients */
396*49fe348cSAndroid Build Coastguard Worker 
397*49fe348cSAndroid Build Coastguard Worker     float pred_gain[2], a[2][9];
398*49fe348cSAndroid Build Coastguard Worker     float rc[2][8];
399*49fe348cSAndroid Build Coastguard Worker 
400*49fe348cSAndroid Build Coastguard Worker     data->lpc_weighting = resolve_lpc_weighting(dt, nbytes);
401*49fe348cSAndroid Build Coastguard Worker     data->nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
402*49fe348cSAndroid Build Coastguard Worker     int maxorder = dt <= LC3_DT_5M ? 4 : 8;
403*49fe348cSAndroid Build Coastguard Worker 
404*49fe348cSAndroid Build Coastguard Worker     compute_lpc_coeffs(dt, bw, maxorder, x, pred_gain, a);
405*49fe348cSAndroid Build Coastguard Worker 
406*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < data->nfilters; f++) {
407*49fe348cSAndroid Build Coastguard Worker 
408*49fe348cSAndroid Build Coastguard Worker         data->rc_order[f] = 0;
409*49fe348cSAndroid Build Coastguard Worker         if (nn_flag || pred_gain[f] <= 1.5f)
410*49fe348cSAndroid Build Coastguard Worker             continue;
411*49fe348cSAndroid Build Coastguard Worker 
412*49fe348cSAndroid Build Coastguard Worker         if (data->lpc_weighting && pred_gain[f] < 2.f)
413*49fe348cSAndroid Build Coastguard Worker             lpc_weighting(pred_gain[f], a[f]);
414*49fe348cSAndroid Build Coastguard Worker 
415*49fe348cSAndroid Build Coastguard Worker         lpc_reflection(a[f], maxorder, rc[f]);
416*49fe348cSAndroid Build Coastguard Worker 
417*49fe348cSAndroid Build Coastguard Worker         quantize_rc(rc[f], maxorder, &data->rc_order[f], data->rc[f]);
418*49fe348cSAndroid Build Coastguard Worker         unquantize_rc(data->rc[f], data->rc_order[f], rc[f]);
419*49fe348cSAndroid Build Coastguard Worker     }
420*49fe348cSAndroid Build Coastguard Worker 
421*49fe348cSAndroid Build Coastguard Worker     forward_filtering(dt, bw, data->rc_order, rc, x);
422*49fe348cSAndroid Build Coastguard Worker }
423*49fe348cSAndroid Build Coastguard Worker 
424*49fe348cSAndroid Build Coastguard Worker /**
425*49fe348cSAndroid Build Coastguard Worker  * TNS synthesis
426*49fe348cSAndroid Build Coastguard Worker  */
lc3_tns_synthesize(enum lc3_dt dt,enum lc3_bandwidth bw,const struct lc3_tns_data * data,float * x)427*49fe348cSAndroid Build Coastguard Worker void lc3_tns_synthesize(enum lc3_dt dt, enum lc3_bandwidth bw,
428*49fe348cSAndroid Build Coastguard Worker     const struct lc3_tns_data *data, float *x)
429*49fe348cSAndroid Build Coastguard Worker {
430*49fe348cSAndroid Build Coastguard Worker     float rc[2][8] = { 0 };
431*49fe348cSAndroid Build Coastguard Worker 
432*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < data->nfilters; f++)
433*49fe348cSAndroid Build Coastguard Worker         if (data->rc_order[f])
434*49fe348cSAndroid Build Coastguard Worker             unquantize_rc(data->rc[f], data->rc_order[f], rc[f]);
435*49fe348cSAndroid Build Coastguard Worker 
436*49fe348cSAndroid Build Coastguard Worker     inverse_filtering(dt, bw, data->rc_order, rc, x);
437*49fe348cSAndroid Build Coastguard Worker }
438*49fe348cSAndroid Build Coastguard Worker 
439*49fe348cSAndroid Build Coastguard Worker /**
440*49fe348cSAndroid Build Coastguard Worker  * Bit consumption of bitstream data
441*49fe348cSAndroid Build Coastguard Worker  */
lc3_tns_get_nbits(const struct lc3_tns_data * data)442*49fe348cSAndroid Build Coastguard Worker int lc3_tns_get_nbits(const struct lc3_tns_data *data)
443*49fe348cSAndroid Build Coastguard Worker {
444*49fe348cSAndroid Build Coastguard Worker     int nbits = 0;
445*49fe348cSAndroid Build Coastguard Worker 
446*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < data->nfilters; f++) {
447*49fe348cSAndroid Build Coastguard Worker 
448*49fe348cSAndroid Build Coastguard Worker         int nbits_2048 = 2048;
449*49fe348cSAndroid Build Coastguard Worker         int rc_order = data->rc_order[f];
450*49fe348cSAndroid Build Coastguard Worker 
451*49fe348cSAndroid Build Coastguard Worker         nbits_2048 += rc_order > 0 ? lc3_tns_order_bits
452*49fe348cSAndroid Build Coastguard Worker             [data->lpc_weighting][rc_order-1] : 0;
453*49fe348cSAndroid Build Coastguard Worker 
454*49fe348cSAndroid Build Coastguard Worker         for (int i = 0; i < rc_order; i++)
455*49fe348cSAndroid Build Coastguard Worker             nbits_2048 += lc3_tns_coeffs_bits[i][8 + data->rc[f][i]];
456*49fe348cSAndroid Build Coastguard Worker 
457*49fe348cSAndroid Build Coastguard Worker         nbits += (nbits_2048 + (1 << 11) - 1) >> 11;
458*49fe348cSAndroid Build Coastguard Worker     }
459*49fe348cSAndroid Build Coastguard Worker 
460*49fe348cSAndroid Build Coastguard Worker     return nbits;
461*49fe348cSAndroid Build Coastguard Worker }
462*49fe348cSAndroid Build Coastguard Worker 
463*49fe348cSAndroid Build Coastguard Worker /**
464*49fe348cSAndroid Build Coastguard Worker  * Put bitstream data
465*49fe348cSAndroid Build Coastguard Worker  */
lc3_tns_put_data(lc3_bits_t * bits,const struct lc3_tns_data * data)466*49fe348cSAndroid Build Coastguard Worker void lc3_tns_put_data(lc3_bits_t *bits, const struct lc3_tns_data *data)
467*49fe348cSAndroid Build Coastguard Worker {
468*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < data->nfilters; f++) {
469*49fe348cSAndroid Build Coastguard Worker         int rc_order = data->rc_order[f];
470*49fe348cSAndroid Build Coastguard Worker 
471*49fe348cSAndroid Build Coastguard Worker         lc3_put_bits(bits, rc_order > 0, 1);
472*49fe348cSAndroid Build Coastguard Worker         if (rc_order <= 0)
473*49fe348cSAndroid Build Coastguard Worker             continue;
474*49fe348cSAndroid Build Coastguard Worker 
475*49fe348cSAndroid Build Coastguard Worker         lc3_put_symbol(bits,
476*49fe348cSAndroid Build Coastguard Worker             lc3_tns_order_models + data->lpc_weighting, rc_order-1);
477*49fe348cSAndroid Build Coastguard Worker 
478*49fe348cSAndroid Build Coastguard Worker         for (int i = 0; i < rc_order; i++)
479*49fe348cSAndroid Build Coastguard Worker             lc3_put_symbol(bits,
480*49fe348cSAndroid Build Coastguard Worker                 lc3_tns_coeffs_models + i, 8 + data->rc[f][i]);
481*49fe348cSAndroid Build Coastguard Worker     }
482*49fe348cSAndroid Build Coastguard Worker }
483*49fe348cSAndroid Build Coastguard Worker 
484*49fe348cSAndroid Build Coastguard Worker /**
485*49fe348cSAndroid Build Coastguard Worker  * Get bitstream data
486*49fe348cSAndroid Build Coastguard Worker  */
lc3_tns_get_data(lc3_bits_t * bits,enum lc3_dt dt,enum lc3_bandwidth bw,int nbytes,lc3_tns_data_t * data)487*49fe348cSAndroid Build Coastguard Worker int lc3_tns_get_data(lc3_bits_t *bits,
488*49fe348cSAndroid Build Coastguard Worker     enum lc3_dt dt, enum lc3_bandwidth bw, int nbytes, lc3_tns_data_t *data)
489*49fe348cSAndroid Build Coastguard Worker {
490*49fe348cSAndroid Build Coastguard Worker     data->nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
491*49fe348cSAndroid Build Coastguard Worker     data->lpc_weighting = resolve_lpc_weighting(dt, nbytes);
492*49fe348cSAndroid Build Coastguard Worker 
493*49fe348cSAndroid Build Coastguard Worker     for (int f = 0; f < data->nfilters; f++) {
494*49fe348cSAndroid Build Coastguard Worker 
495*49fe348cSAndroid Build Coastguard Worker         data->rc_order[f] = lc3_get_bit(bits);
496*49fe348cSAndroid Build Coastguard Worker         if (!data->rc_order[f])
497*49fe348cSAndroid Build Coastguard Worker             continue;
498*49fe348cSAndroid Build Coastguard Worker 
499*49fe348cSAndroid Build Coastguard Worker         data->rc_order[f] += lc3_get_symbol(bits,
500*49fe348cSAndroid Build Coastguard Worker             lc3_tns_order_models + data->lpc_weighting);
501*49fe348cSAndroid Build Coastguard Worker         if (dt <= LC3_DT_5M && data->rc_order[f] > 4)
502*49fe348cSAndroid Build Coastguard Worker             return -1;
503*49fe348cSAndroid Build Coastguard Worker 
504*49fe348cSAndroid Build Coastguard Worker         for (int i = 0; i < data->rc_order[f]; i++)
505*49fe348cSAndroid Build Coastguard Worker             data->rc[f][i] = (int)lc3_get_symbol(bits,
506*49fe348cSAndroid Build Coastguard Worker                 lc3_tns_coeffs_models + i) - 8;
507*49fe348cSAndroid Build Coastguard Worker     }
508*49fe348cSAndroid Build Coastguard Worker 
509*49fe348cSAndroid Build Coastguard Worker     return 0;
510*49fe348cSAndroid Build Coastguard Worker }
511