Line data Source code
1 : /*====================================================================================
2 : EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
3 : ====================================================================================*/
4 : #include <stdint.h>
5 : #include "options.h" /* Compilation switches */
6 : #include "cnst.h" /* Common constants */
7 : //#include "prot_fx.h" /* Function prototypes */
8 : #include "basop_util.h"
9 : #include "prot_fx.h" /* Function prototypes */
10 : #include "prot_fx_enc.h" /* Function prototypes */
11 :
12 : /*-------------------------------------------------------------------*
13 : * Local constants
14 : *-------------------------------------------------------------------*/
15 :
16 : #define GAIN_PIT_MAX 19661
17 :
18 :
19 : /*-------------------------------------------------------------------*
20 : * Local function prototypes
21 : *-------------------------------------------------------------------*/
22 :
23 : static Word16 adpt_enr_fx( const Word16 codec_mode, const Word16 *exc, const Word16 *h1, Word16 *y1, const Word16 L_subfr, Word16 *gain, Word16 *g_corr, const Word16 clip_gain, const Word16 *xn, Word16 *xn2, Word16 *exp_ener, Word16 use_prev_sf_pit_gain );
24 :
25 : /*-------------------------------------------------------------------*
26 : * function lp_filt_exc_enc_fx()
27 : *
28 : * Low-pass filtering of the adaptive excitation
29 : * Innovation target construction
30 : * Gain quantization limitation
31 : *-------------------------------------------------------------------*/
32 :
33 599001 : Word16 lp_filt_exc_enc_fx(
34 : const Word16 codec_mode, /* i : MODE1 or MODE2 Q0 */
35 : const Word16 coder_type, /* i : coding type Q0 */
36 : const Word16 i_subfr, /* i : subframe index Q0 */
37 : Word16 *exc, /* i/o: pointer to excitation signal frame Q_new */
38 : const Word16 *h1, /* i : weighted filter input response Q(14+shift) */
39 : const Word16 *xn, /* i : target vector Q_new-1+shift */
40 : Word16 *y1, /* o : zero-memory filtered adaptive excitation Q_new-1+shift */
41 : Word16 *xn2, /* o : target vector for innovation search Q_new-1+shift */
42 : const Word16 L_subfr, /* i : length of vectors for gain quantization Q0 */
43 : const Word16 L_frame, /* i : frame size Q0 */
44 : Word16 *g_corr, /* o : ACELP correlation values mant/exp */
45 : const Word16 clip_gain, /* i : adaptive gain clipping flag Q0 */
46 : Word16 *gain_pit, /* o : adaptive excitation gain Q14 */
47 : Word16 *lp_flag /* i/o: mode selection Q0 */
48 : )
49 : {
50 : Word16 gain1, gain2, g_corr2[4], exc_tmp[5 * L_SUBFR], xn2_tmp[5 * L_SUBFR];
51 : Word16 y1_tmp[5 * L_SUBFR];
52 : Word16 select, i, exp_ener, exp_ener1;
53 : Word16 wtmp, wtmp1;
54 : Word32 Ltmp;
55 :
56 599001 : Word16 use_prev_sf_pit_gain = 0; // Q0
57 599001 : move16();
58 :
59 599001 : gain1 = 0;
60 599001 : move16();
61 599001 : gain2 = 0;
62 599001 : move16();
63 :
64 : /*----------------------------------------------------------------*
65 : * Find the target energy if the adaptive exc. is not filtered
66 : *----------------------------------------------------------------*/
67 599001 : test();
68 599001 : IF( EQ_16( codec_mode, MODE2 ) && EQ_16( coder_type, 100 ) )
69 : {
70 0 : use_prev_sf_pit_gain = 1; // Q0
71 0 : move16();
72 : }
73 599001 : exp_ener = 0;
74 599001 : move16();
75 599001 : wtmp = 0;
76 599001 : move16();
77 599001 : test();
78 599001 : IF( EQ_16( *lp_flag, FULL_BAND ) || EQ_16( *lp_flag, NORMAL_OPERATION ) )
79 : {
80 557456 : wtmp = adpt_enr_fx( codec_mode, &exc[i_subfr], h1, y1, L_subfr, &gain1, g_corr, clip_gain, xn, xn2, &exp_ener, use_prev_sf_pit_gain ); // exp_ener
81 557456 : move16();
82 : }
83 :
84 : /*----------------------------------------------------------------*
85 : * Filter the adaptive excitation
86 : * Find the target energy if the adapt. exc. is filtered
87 : *----------------------------------------------------------------*/
88 :
89 599001 : exp_ener1 = 0;
90 599001 : move16();
91 599001 : wtmp1 = 0;
92 599001 : move16();
93 599001 : test();
94 599001 : IF( ( ( *lp_flag == LOW_PASS ) ) || ( EQ_16( *lp_flag, NORMAL_OPERATION ) ) )
95 : {
96 539607 : test();
97 539607 : IF( EQ_16( codec_mode, MODE2 ) && EQ_16( L_frame, L_FRAME16k ) )
98 : {
99 0 : FOR( i = 0; i < L_subfr; i++ )
100 : {
101 0 : Ltmp = L_mult( 6881, exc[i - 1 + i_subfr] ); /* constants in Q15 */
102 0 : Ltmp = L_mac( Ltmp, 19005, exc[i + i_subfr] );
103 0 : Ltmp = L_mac( Ltmp, 6881, exc[i + 1 + i_subfr] );
104 0 : exc_tmp[i] = round_fx( Ltmp );
105 0 : move16();
106 : }
107 : }
108 : ELSE
109 : {
110 35074455 : FOR( i = 0; i < L_subfr; i++ )
111 : {
112 34534848 : Ltmp = L_mult( 5898, exc[i - 1 + i_subfr] ); /* constants in Q15 */
113 34534848 : Ltmp = L_mac( Ltmp, 20972, exc[i + i_subfr] );
114 34534848 : Ltmp = L_mac( Ltmp, 5898, exc[i + 1 + i_subfr] );
115 34534848 : exc_tmp[i] = round_fx( Ltmp );
116 34534848 : move16();
117 : }
118 : }
119 :
120 539607 : wtmp1 = adpt_enr_fx( codec_mode, exc_tmp, h1, y1_tmp, L_subfr, &gain2, g_corr2, clip_gain, xn, xn2_tmp, &exp_ener1, use_prev_sf_pit_gain ); // exp_ener1
121 : }
122 :
123 599001 : if ( LT_16( exp_ener, exp_ener1 ) )
124 : {
125 46754 : wtmp = shr( wtmp, 1 ); // exp_ener + 1
126 : }
127 :
128 599001 : if ( GT_16( exp_ener, exp_ener1 ) )
129 : {
130 77139 : wtmp1 = shr( wtmp1, 1 ); // exp_ener1 + 1
131 : }
132 :
133 : /*-----------------------------------------------------------------*
134 : * use the best prediction (minimize quadratic error)
135 : *-----------------------------------------------------------------*/
136 :
137 599001 : test();
138 599001 : test();
139 599001 : IF( ( ( LT_16( wtmp1, wtmp ) ) && ( EQ_16( *lp_flag, NORMAL_OPERATION ) ) ) || ( ( *lp_flag == LOW_PASS ) ) )
140 : {
141 : /* use the LP filter for pitch excitation prediction */
142 375497 : select = LOW_PASS;
143 375497 : move16();
144 375497 : Copy( exc_tmp, &exc[i_subfr], L_subfr ); // Q_new
145 375497 : Copy( y1_tmp, y1, L_subfr ); // Q_new-1+shift
146 375497 : Copy( xn2_tmp, xn2, L_subfr ); // Q_new-1+shift
147 :
148 375497 : IF( use_prev_sf_pit_gain == 0 )
149 : {
150 375497 : *gain_pit = gain2; // Q14
151 375497 : move16();
152 375497 : g_corr[0] = g_corr2[0];
153 375497 : move16();
154 375497 : g_corr[1] = g_corr2[1];
155 375497 : move16();
156 375497 : g_corr[2] = g_corr2[2];
157 375497 : move16();
158 375497 : g_corr[3] = g_corr2[3];
159 375497 : move16();
160 : }
161 : }
162 : ELSE
163 : {
164 : /* no LP filter used for pitch excitation prediction */
165 223504 : select = FULL_BAND;
166 223504 : move16();
167 223504 : IF( use_prev_sf_pit_gain == 0 )
168 : {
169 223504 : *gain_pit = gain1; // Q14
170 223504 : move16();
171 : }
172 : }
173 :
174 599001 : return select;
175 : }
176 : /*-------------------------------------------------------------------*
177 : * adpt_enr_fx()
178 : *
179 : * Find adaptive excitation energy
180 : * This serves to decide about the filtering of the adaptive excitation
181 : *-------------------------------------------------------------------*/
182 :
183 1097063 : static Word16 adpt_enr_fx( /* o : adaptive excitation energy mant */
184 : const Word16 codec_mode, /* i : MODE1 or MODE2 */
185 : const Word16 *exc, /* i : excitation vector Q_new */
186 : const Word16 *h1, /* i : impuls response Q15 */
187 : Word16 *y1, /* o : zero-memory filtered adpt. excitation 12 bits */
188 : const Word16 L_subfr, /* i : vector length */
189 : Word16 *gain, /* o : subframe adaptive gain Q14 */
190 : Word16 *g_corr, /* o : correlations for adptive gain mant/exp*/
191 : const Word16 clip_gain, /* i : adaptive gain clipping flag Q0 */
192 : const Word16 *xn, /* i : adaptive codebook target 12 bits Q_new-1+shift*/
193 : Word16 *xn2, /* o : algebraic codebook target 12 bits Q_new-1+shift*/
194 : Word16 *exp_ener /* o : adaptive excitation energy exp */
195 : ,
196 : Word16 use_prev_sf_pit_gain /* i : flag to use prev sf pitch gain or not */
197 : )
198 : {
199 : Word16 ener, i;
200 : Word16 exc_tmp[L_FRAME16k], xn_tmp[L_FRAME16k];
201 : Word32 Ltmp;
202 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL /* Critical Overflow */
203 1097063 : Flag Overflow = 0;
204 : #endif
205 :
206 1097063 : Overflow = 0;
207 1097063 : move16();
208 1097063 : Overflow =
209 1097063 : conv_fx( exc, h1, y1, L_subfr );
210 :
211 1097063 : IF( use_prev_sf_pit_gain == 0 )
212 : {
213 1097063 : *gain = corr_xy1_fx( xn, y1, g_corr, L_subfr, codec_mode == MODE2, &Overflow );
214 1097063 : move16();
215 :
216 1097063 : test();
217 1097063 : IF( GT_16( L_subfr, L_SUBFR ) && Overflow )
218 : {
219 46221 : FOR( i = 0; i < L_subfr; i++ )
220 : {
221 45952 : exc_tmp[i] = mult( exc[i], 8192 /*0.25.Q15*/ ); // Q_new
222 45952 : move16();
223 45952 : xn_tmp[i] = mult( xn[i], 8192 /*0.25.Q15*/ ); // Q_new
224 45952 : move16();
225 : }
226 269 : Overflow = 0;
227 :
228 269 : conv_fx( exc_tmp, h1, y1, L_subfr );
229 269 : *gain = corr_xy1_fx( xn_tmp, y1, g_corr, L_subfr, codec_mode == MODE2, &Overflow );
230 269 : move16();
231 : }
232 :
233 : /* clip gain, if necessary to avoid problems at decoder */
234 1097063 : test();
235 1097063 : if ( EQ_16( clip_gain, 1 ) && GT_16( *gain, 15565 ) ) /* constant in Q14 */
236 : {
237 4310 : *gain = 15565; // 0.95.Q14
238 4310 : move16();
239 : }
240 :
241 1097063 : test();
242 1097063 : IF( EQ_16( clip_gain, 2 ) && GT_16( *gain, 10650 ) ) // 0.65.Q14
243 : {
244 4532 : *gain = 10650; // 0.65.Q14
245 4532 : move16();
246 : }
247 : }
248 :
249 : /* find energy of new target xn2[] */
250 1097063 : updt_tar_fx( xn, xn2, y1, *gain, L_subfr );
251 :
252 1097063 : IF( GT_16( L_subfr, L_SUBFR ) )
253 : {
254 : /* could possibly happen in GSC */
255 14914 : Ltmp = Calc_Energy_Autoscaled( xn2, 0, L_subfr, exp_ener );
256 14914 : i = norm_l( Ltmp );
257 14914 : ener = extract_h( L_shl( Ltmp, i ) ); // exp_ener
258 14914 : i = sub( 31, i );
259 14914 : *exp_ener = sub( i, *exp_ener );
260 14914 : move16();
261 : }
262 : ELSE
263 : {
264 1082149 : ener = extract_h( Dot_product12( xn2, xn2, L_SUBFR, exp_ener ) ); // Q15
265 : }
266 :
267 1097063 : return ener;
268 : }
269 :
270 : /*-------------------------------------------------------------------*
271 : * corr_xy1()
272 : *
273 : * Find the correlations between the target xn[] and the filtered adaptive
274 : * codebook excitation y1[]. ( <y1,y1> and -2<xn,y1> )
275 : *-------------------------------------------------------------------*/
276 :
277 1172725 : Word16 corr_xy1_fx( /* o : pitch gain (0..GAIN_PIT_MAX) */
278 : const Word16 xn_1[], /* i : target signal Q_new*/
279 : const Word16 y1_1[], /* i : filtered adaptive codebook excitation 12 bits*/
280 : Word16 g_corr[], /* o : correlations <y1,y1> and -2<xn,y1> mant/exp*/
281 : const Word16 L_subfr, /* i : vector length */
282 : const Word16 norm_flag /* i : flag for constraining pitch contribution */
283 : ,
284 : Flag *Overflow_out /* o : propagating the Overflow flag to upper level */
285 : )
286 : {
287 : Word16 i;
288 : Word16 tmp, xx, xy, yy, exp_xy, exp_xx, exp_yy, exp_div, gain, gain_p_snr;
289 : Word32 Ltmp1, Ltmp2;
290 : Word16 xn[L_FRAME16k], y1[L_FRAME16k];
291 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
292 1172725 : Flag Overflow = 0;
293 : #endif
294 :
295 : /*----------------------------------------------------------------*
296 : * Find the ACELP correlations and the pitch gain
297 : *----------------------------------------------------------------*/
298 :
299 : /* Compute scalar product <y1[],y1[]> */
300 1172725 : Copy( xn_1, xn, L_subfr ); // Q_new
301 1172725 : Copy( y1_1, y1, L_subfr );
302 1172725 : Overflow = 0;
303 1172725 : move16();
304 1172725 : Ltmp1 = Dot_product12_o( y1, y1, L_subfr, &exp_yy, &Overflow );
305 1172725 : *Overflow_out |= Overflow;
306 1172725 : move16();
307 1172725 : IF( Overflow )
308 : {
309 83971 : FOR( i = 0; i < L_subfr; i++ )
310 : {
311 82816 : xn[i] = mult_r( xn_1[i], 4096 /*0.125.Q15*/ ); // Q-new
312 82816 : move16();
313 82816 : y1[i] = mult_r( y1_1[i], 4096 /*0.125.Q15*/ );
314 82816 : move16();
315 : }
316 :
317 1155 : Ltmp1 = Dot_product12( y1, y1, L_subfr, &exp_yy );
318 1155 : exp_yy = add( exp_yy, 6 );
319 1155 : yy = extract_h( Ltmp1 );
320 :
321 : /* Compute scalar product <xn[],y1[]> */
322 1155 : Ltmp2 = Dot_product12( xn, y1, L_subfr, &exp_xy );
323 1155 : xy = extract_h( Ltmp2 );
324 1155 : exp_xy = add( exp_xy, 6 );
325 :
326 1155 : g_corr[0] = yy;
327 1155 : move16();
328 1155 : g_corr[1] = exp_yy;
329 1155 : move16();
330 : /* -2.0*temp1 + 0.01 is done in Gain_enc_2 function */
331 1155 : g_corr[2] = xy;
332 1155 : move16();
333 1155 : g_corr[3] = exp_xy;
334 1155 : move16();
335 : }
336 : ELSE
337 : {
338 1171570 : yy = extract_h( Ltmp1 ); // exp_yy
339 : /* Ltmp1 = L_shr(Ltmp1, sub(30, exp_yy));*/
340 :
341 : /* Compute scalar product <xn[],y1[]> */
342 1171570 : Ltmp2 = Dot_product12_o( xn, y1, L_subfr, &exp_xy, &Overflow );
343 1171570 : *Overflow_out |= Overflow;
344 1171570 : move16();
345 1171570 : xy = extract_h( Ltmp2 );
346 : /* Ltmp2 = L_shr(Ltmp2, sub(30, exp_xy));*/
347 :
348 1171570 : g_corr[0] = yy;
349 1171570 : move16();
350 1171570 : g_corr[1] = exp_yy;
351 1171570 : move16();
352 : /* -2.0*temp1 + 0.01 is done in Gain_enc_2 function*/
353 1171570 : g_corr[2] = xy; // exp_xy
354 1171570 : move16();
355 1171570 : g_corr[3] = exp_xy;
356 1171570 : move16();
357 : }
358 :
359 : /* find pitch gain and bound it by [0,GAIN_PIT_MAX] */
360 1172725 : test();
361 1172725 : IF( xy >= 0 && NE_16( s_or( yy, xy ), 16384 ) )
362 : {
363 : /* compute gain = xy/yy */
364 1119046 : xy = shr( xy, 1 ); /* be sure that xy < yy */
365 1119046 : gain = div_s( xy, yy ); // Q15
366 1119046 : i = sub( exp_xy, exp_yy );
367 1119046 : gain = shl_o( gain, i, &Overflow ); /* saturation can occur here */
368 1119046 : *Overflow_out |= Overflow;
369 1119046 : move16();
370 :
371 1119046 : gain = s_max( gain, 0 );
372 1119046 : gain = s_min( gain, GAIN_PIT_MAX ); /* 1.2 in Q14 */
373 : }
374 : ELSE
375 : {
376 53679 : gain = 0;
377 53679 : move16();
378 : }
379 :
380 : /* Limit the energy of pitch contribution */
381 1172725 : IF( norm_flag )
382 : {
383 : /*that part of code seems never used*/
384 : /* Compute scalar product <xn[],xn[]> */
385 0 : xx = round_fx( Dot_product12_offs( xn, xn, L_subfr, &exp_xx, 1 ) );
386 :
387 : /* gain_p_snr = sqrt(<xn,xn>/<y1,y1>) */
388 0 : tmp = BASOP_Util_Divide1616_Scale( xx, yy, &exp_div );
389 0 : exp_xx = add( sub( exp_xx, exp_yy ), exp_div );
390 0 : tmp = Sqrt16( tmp, &exp_xx ); // exp_xx
391 :
392 : /* Note: shl works as shl or shr. */
393 0 : exp_xx = sub( exp_xx, 1 );
394 : BASOP_SATURATE_WARNING_OFF_EVS
395 0 : gain_p_snr = round_fx_sat( L_shl_sat( Mpy_32_16_1( 1717986944l /*ACELP_GAINS_CONST Q31*/, tmp ), exp_xx ) );
396 : BASOP_SATURATE_WARNING_ON_EVS
397 :
398 0 : gain = s_min( gain, gain_p_snr ); // Q14
399 : }
400 :
401 1172725 : return gain; // Q14
402 : }
|