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