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 <stdlib.h>
6 : #include "options.h" /* Compilation switches */
7 : #include "cnst.h" /* Common constants */
8 : #include "rom_dec.h" /* Decoder static table prototypes */
9 : #include "prot_fx.h" /* Function prototypes */
10 :
11 :
12 : /*---------------------------------------------------------------------*
13 : * FEC_SinOnset()
14 : *
15 : * Create an artificial onset when it is lost
16 : *---------------------------------------------------------------------*/
17 3 : Word16 FEC_SinOnset_fx(
18 : Word16 *exc,
19 : /* i/o : exc vector to modify */ // Qin = Qold, Qout = Q_exc
20 : Word16 puls_pos, /* i : last pulse position desired */
21 : const Word16 T0, /* i : Pitch information of the 1 subfr */
22 : Word32 enr_q, /* i : energy provide by the encoder */
23 : Word16 *Aq, /* i : A(z) filter Q12 */
24 : const Word16 L_frame /* i : frame length */
25 : ,
26 : const Word16 Qold )
27 : {
28 : Word16 P0, onset_len, sign, i, len, L_subfr, L_subfr2;
29 : Word16 h1[L_SUBFR16k], mem[M], exc_tmp[L_FRAME16k + MODE1_L_FIR_FER];
30 : Word16 *pt_end, *pt_exc, enr_LP, gain, H_low_s[5], exp_gain, exp2, tmp;
31 : Word32 L_tmp;
32 : Word16 Q_exc;
33 :
34 3 : sign = 0;
35 3 : move16();
36 3 : Q_exc = Qold;
37 3 : move16();
38 3 : L_subfr = L_SUBFR;
39 3 : move16();
40 3 : if ( EQ_16( L_frame, L_FRAME16k ) )
41 : {
42 3 : L_subfr = L_SUBFR16k;
43 3 : move16();
44 : }
45 :
46 3 : L_subfr2 = shl( L_subfr, 1 );
47 3 : onset_len = s_max( T0, L_subfr2 );
48 :
49 3 : P0 = puls_pos;
50 3 : move16();
51 :
52 3 : IF( P0 < 0 )
53 : {
54 0 : sign = 1;
55 0 : move16();
56 0 : P0 = negate( P0 );
57 : }
58 :
59 3 : test();
60 3 : test();
61 3 : IF( GT_16( P0, PIT_MAX ) && EQ_16( L_frame, L_FRAME ) )
62 : {
63 0 : P0 = PIT_MAX;
64 0 : move16(); /* Should never be the case, however... */
65 : }
66 3 : ELSE IF( GT_16( P0, PIT16k_MAX ) && EQ_16( L_frame, L_FRAME16k ) )
67 : {
68 0 : P0 = PIT16k_MAX;
69 0 : move16(); /* Should never be the case, however... */
70 : }
71 3 : set16_fx( exc_tmp, 0, add( L_frame, MODE1_L_FIR_FER ) ); /* Reset excitation vector */
72 :
73 : /*-------------------------------------------------------------------------------*
74 : * Find LP filter impulse response energy and Generate the scaled pulse prototype
75 : *-------------------------------------------------------------------------------*/
76 :
77 3 : set16_fx( h1, 0, L_subfr ); /* Find the impulse response */
78 3 : set16_fx( mem, 0, M );
79 3 : h1[0] = 1024; // 1.0f Q10
80 3 : move16();
81 3 : Syn_filt_s( 1, Aq, M, h1, h1, L_subfr, mem, 0 );
82 :
83 :
84 3 : enr_LP = extract_h( Dot_product12( h1, h1, L_subfr, &exp_gain ) );
85 3 : exp_gain = sub( exp_gain, 10 + 10 ); /* h1 in Q10 */
86 :
87 : /* divide by LP filter E, scaled by transmitted E */
88 : /* gain = (float)sqrt( enr_q / enr_LP ); */
89 :
90 3 : enr_q = L_max( enr_q, 1 );
91 :
92 3 : exp2 = norm_l( enr_q );
93 3 : tmp = extract_h( L_shl( enr_q, exp2 ) );
94 3 : tmp = mult( tmp, 24576 ); /* multpiply by 1.5 */
95 :
96 3 : IF( LT_16( tmp, 16384 ) )
97 : {
98 0 : exp2 = add( exp2, 1 );
99 0 : tmp = shl( tmp, 1 );
100 : }
101 3 : exp2 = sub( 30, exp2 ); /* in Q15 */
102 :
103 :
104 3 : IF( GT_16( enr_LP, tmp ) )
105 : {
106 0 : enr_LP = shr( enr_LP, 1 );
107 0 : exp_gain = add( exp_gain, 1 );
108 : }
109 :
110 3 : tmp = div_s( enr_LP, tmp );
111 3 : exp2 = sub( exp_gain, exp2 );
112 :
113 3 : L_tmp = L_deposit_h( tmp );
114 3 : L_tmp = Isqrt_lc( L_tmp, &exp2 );
115 3 : gain = round_fx( L_tmp );
116 :
117 3 : gain = mult_r( gain, 31457 ); /* multiply by .96 like floating point 0.96f in Q15*/
118 3 : exp2 = add( sub( exp2, 15 ), Q_exc ); /* from Q15 to Q_exc */
119 :
120 : /* Find if rescaling needed */
121 3 : tmp = extract_h( L_mult( h_low_fx[2], gain ) );
122 3 : exp_gain = norm_s( tmp );
123 3 : tmp = sub( exp_gain, exp2 ); /* difference */
124 :
125 3 : IF( tmp < 0 ) /* Need to correct scaling */
126 : {
127 0 : Q_exc = add( Q_exc, tmp );
128 0 : exp2 = add( exp2, tmp );
129 : }
130 : /* Scale pulse "prototype" energy */
131 : /* Generate the scaled pulse */
132 18 : FOR( i = 0; i < MODE1_L_FIR_FER; i++ )
133 : {
134 15 : L_tmp = L_mult( gain, h_low_fx[i] ); /* Q_exc*Q15 -> Q_exc */
135 15 : H_low_s[i] = round_fx( L_shl( L_tmp, exp2 ) );
136 15 : move16();
137 : }
138 : /*------------------------------------------------------------------------------------------*
139 : * Construct the harmonic part as a train of low-pass filtered pulses
140 : *------------------------------------------------------------------------------------------*/
141 3 : pt_exc = exc_tmp + sub( L_frame, add( add( 1, MODE1_L_FIR_FER / 2 ), P0 ) ); /* beginning of the 1st pulse */
142 3 : pt_end = exc_tmp + onset_len;
143 3 : len = (Word16) ( pt_exc - pt_end );
144 :
145 3 : len = s_min( len, MODE1_L_FIR_FER );
146 3 : IF( !sign )
147 : {
148 :
149 18 : FOR( i = 0; i < len; i++ )
150 : {
151 : /* The filter response would have E=1 in full band. */
152 15 : pt_exc[i] = add( pt_exc[i], H_low_s[i] );
153 15 : move16();
154 : }
155 : }
156 : ELSE
157 : {
158 0 : FOR( i = 0; i < len; i++ )
159 : {
160 : /* The filter response would have E=1 in full band. */
161 0 : pt_exc[i] = sub( pt_exc[i], H_low_s[i] );
162 0 : move16();
163 : }
164 : }
165 3 : Copy( &exc_tmp[L_frame - L_EXC_MEM], exc, L_EXC_MEM );
166 3 : return Q_exc;
167 : }
168 :
169 0 : Word16 FEC_enhACB_fx(
170 : const Word16 L_frame, /* i : frame length */
171 : const Word16 last_L_frame, /* i : frame length of previous frame */
172 : Word16 *exc_io,
173 : /* i/o : adaptive codebook memory */ // st->Q_exc
174 : const Word16 new_pit, /* i : decoded first frame pitch */
175 : const Word16 puls_pos, /* i : decoder position of the last glottal pulses decoded in the previous frame */
176 : const Word16 bfi_pitch /* i : Q6 pitch used for concealment */
177 : )
178 : {
179 : Word16 Tc, P0, sign, pit_search;
180 : Word16 Tlist[10], Terr, diff_pit, dist_Plast;
181 : Word16 tmp2;
182 : Word16 exc[L_FRAME16k + L_SUBFR]; // Q0
183 0 : Word16 Do_WI = 1;
184 0 : move16();
185 :
186 :
187 0 : set16_fx( exc, 0, L_FRAME16k - L_EXC_MEM );
188 0 : set16_fx( exc + L_FRAME16k, 0, L_SUBFR );
189 0 : Copy( exc_io, exc + L_FRAME16k - L_EXC_MEM, L_EXC_MEM );
190 :
191 0 : Tc = shr( bfi_pitch, 6 ); // Q0
192 0 : Copy( exc + sub( L_FRAME16k, Tc ), exc + L_FRAME16k, L_SUBFR );
193 :
194 : /*------------------------------------------------------------
195 : * Decode phase information transmitted in the bitstream
196 : * (The position of the absolute maximum glottal pulse from
197 : * the end of the frame and its sign)
198 : *------------------------------------------------------------*/
199 :
200 0 : P0 = puls_pos;
201 0 : move16();
202 0 : sign = 0;
203 0 : move16();
204 0 : IF( P0 < 0 )
205 : {
206 0 : sign = 1;
207 0 : move16();
208 0 : P0 = negate( P0 );
209 : }
210 :
211 0 : IF( EQ_16( L_frame, L_FRAME ) )
212 : {
213 0 : P0 = s_min( PIT_MAX, P0 );
214 : }
215 : ELSE /* L_frame == L_FRAME16k */
216 : {
217 0 : P0 = s_min( PIT16k_MAX, P0 );
218 : }
219 :
220 : /*----------------------------------------------------------------------------------
221 : * Find the position of the first the maximum(minimum) lp_filtered pulse
222 : * <----- Mem --->|<--------------------- L_frame ------------>|<----- L_SUBFR --->|
223 : * |<-------pit_search----> | |
224 : *----------------------------------------------------------------------------------*/
225 :
226 0 : pit_search = Tc;
227 0 : move16();
228 :
229 0 : Tlist[0] = findpulse_fx( L_frame, exc + sub( L_frame, pit_search ), pit_search, DEC, &sign );
230 0 : move16();
231 :
232 : /*Terr = (short) abs(pit_search-Tlist[0]-P0);*/
233 0 : Terr = abs_s( sub( pit_search, add( Tlist[0], P0 ) ) );
234 :
235 0 : dist_Plast = sub( Tc, Tlist[0] );
236 :
237 0 : Tlist[1] = findpulse_fx( L_frame, exc + sub( L_frame, pit_search ), add( pit_search, L_SUBFR ), DEC, &sign ); // Q0
238 0 : move16();
239 :
240 :
241 : /*if(Terr > abs(Tlist[1]-Tc + P0))*/
242 0 : IF( GT_16( Terr, abs_s( add( sub( Tlist[1], Tc ), P0 ) ) ) )
243 : {
244 0 : dist_Plast = sub( Tc, Tlist[1] );
245 0 : Terr = abs_s( add( sub( Tlist[1], Tc ), P0 ) );
246 : }
247 :
248 0 : diff_pit = abs_s( sub( new_pit, Tc ) );
249 : /*ftmp = (float) (int)((float)L_frame/(float)Tc+0.5);*/
250 0 : tmp2 = mult_r( div_s( 16, Tc ), shr( L_frame, 4 ) );
251 0 : test();
252 0 : test();
253 0 : IF( LE_16( Terr, i_mult( tmp2, diff_pit ) ) &&
254 : Terr != 0 && /* If Terr = 0, no resynchronization required */
255 : sub( Terr, L_SUBFR ) < 0 ) /* prevent catastrophy search */
256 : {
257 : /* performe excitation resynchronization here */
258 0 : Do_WI = FEC_synchro_exc_fx( L_frame, exc, P0, dist_Plast, Tc );
259 0 : Copy( exc + L_FRAME16k - L_EXC_MEM, exc_io, L_EXC_MEM );
260 : }
261 : ELSE
262 : {
263 0 : Do_WI = 0;
264 0 : move16();
265 : }
266 :
267 0 : if ( NE_16( last_L_frame, L_FRAME16k ) )
268 : {
269 0 : Do_WI = 0;
270 0 : move16();
271 : }
272 :
273 0 : return Do_WI;
274 : }
275 :
276 0 : Word16 FEC_synchro_exc_fx( /* o : do_WI flag */
277 : const Word16 L_frame, /* i : length of the frame */
278 : Word16 *exc,
279 : /* i/o: exc vector to modify */ // st->Q_exc
280 : const Word16 desire_puls_pos, /* i : Pulse position send by the encoder */
281 : const Word16 true_puls_pos, /* i : Present pulse location */
282 : const Word16 Old_pitch /* i : Pitch use to create temporary adaptive codebook */
283 : )
284 : {
285 : Word16 exc_tmp[L_FRAME16k + L_SUBFR];
286 : Word16 fact;
287 : Word32 L_min_energy, L_tmp; // Q0
288 : Word16 *pt_exc, *pt_exc1;
289 : Word16 i, j, point_to_remove, point_to_add, nb_min;
290 : Word16 min_pos[L_FRAME16k / PIT_MIN_DOUBLEEXTEND], points_by_pos[L_FRAME16k / PIT_MIN_DOUBLEEXTEND];
291 : Word16 total_point, tmp_len;
292 : Word16 *pt_pos, pos, start_search, tmp16;
293 : Word16 remaining_len;
294 :
295 0 : point_to_add = -1;
296 0 : move16();
297 :
298 : /* Init */
299 0 : FOR( i = 0; i < L_FRAME16k / PIT_MIN_DOUBLEEXTEND; i++ )
300 : {
301 0 : min_pos[i] = 10000;
302 0 : move16();
303 0 : points_by_pos[i] = 0;
304 0 : move16();
305 : }
306 :
307 : /* Find number of point to remove and number of minimum */
308 0 : point_to_remove = sub( true_puls_pos, desire_puls_pos ); /* if it is negative it means remove point else it means add point */
309 :
310 0 : pos = sub( L_frame, true_puls_pos );
311 :
312 : /* Find number of minimum energy region */
313 : /* nb_min = (L_FRAME - true_puls_pos)/Old_pitch */
314 0 : tmp16 = shl( Old_pitch, 5 );
315 0 : tmp16 = div_s( pos, tmp16 );
316 0 : nb_min = shr( tmp16, 10 );
317 : /* if Old pitch < 128, must have at least 2 min */
318 0 : if ( LE_16( Old_pitch, 128 ) )
319 : {
320 0 : nb_min = s_max( nb_min, 2 );
321 : }
322 : /* Must have at least 1 min */
323 0 : nb_min = s_max( nb_min, 1 );
324 :
325 0 : pt_exc = exc + pos;
326 0 : move16();
327 :
328 : /* Find starting point for minimum energy search */
329 0 : start_search = mult_r( Old_pitch, -24576 ); // Q0
330 0 : if ( EQ_16( s_and( Old_pitch, 3 ), 1 ) )
331 : {
332 : /* Only be align with integer operation -3*Old_pitch/4 */
333 0 : start_search = add( start_search, 1 );
334 : }
335 0 : IF( add( start_search, pos ) < 0 )
336 : {
337 0 : start_search = negate( pos );
338 0 : if ( LT_16( abs_s( start_search ), shr( Old_pitch, 3 ) ) )
339 : {
340 : /* it's not safe to remove/add point inside 1/8 of the pulse position */
341 0 : return 0;
342 : }
343 : }
344 :
345 : /* Find min energy in the first pitch section */
346 : /* --------------------------------------------------------------------
347 : * The minimum energy regions are determined by the computing the energy
348 : * using a sliding 5-sample window. The minimum energy position is set
349 : * at the middle of the window at which the energy is at minimum
350 : * --------------------------------------------------------------------*/
351 0 : L_min_energy = L_add( MAX_32, 0 );
352 0 : L_tmp = L_mult( pt_exc[start_search], pt_exc[start_search] );
353 0 : L_tmp = L_mac( L_tmp, pt_exc[start_search + 1], pt_exc[start_search + 1] );
354 0 : L_tmp = L_mac( L_tmp, pt_exc[start_search + 2], pt_exc[start_search + 2] );
355 0 : L_tmp = L_mac( L_tmp, pt_exc[start_search + 3], pt_exc[start_search + 3] );
356 0 : L_tmp = L_mac( L_tmp, pt_exc[start_search + 4], pt_exc[start_search + 4] );
357 :
358 0 : IF( LT_32( L_tmp, L_min_energy ) )
359 : {
360 0 : L_min_energy = L_add( L_tmp, 0 );
361 0 : min_pos[0] = add( add( pos, start_search ), 2 );
362 0 : move16();
363 : }
364 :
365 0 : FOR( i = start_search; i < -5; i++ )
366 : {
367 0 : L_tmp = L_msu( L_tmp, pt_exc[i], pt_exc[i] );
368 0 : L_tmp = L_mac( L_tmp, pt_exc[i + 5], pt_exc[i + 5] );
369 :
370 0 : IF( LT_32( L_tmp, L_min_energy ) )
371 : {
372 0 : L_min_energy = L_tmp; /* sets to 'L_tmp' in 1 clock */
373 0 : move32();
374 0 : min_pos[0] = add( add( pos, i ), 2 );
375 0 : move16();
376 : }
377 : }
378 :
379 0 : FOR( j = 1; j < nb_min; j++ )
380 : {
381 0 : min_pos[j] = sub( min_pos[j - 1], Old_pitch );
382 : /* If the first minimum is in the past, forget this minimum */
383 0 : IF( min_pos[j] < 0 )
384 : {
385 0 : min_pos[j] = -10000;
386 0 : move16();
387 0 : nb_min = sub( nb_min, 1 );
388 : }
389 : }
390 :
391 : /* safety-measure against not properly initialized min_pos[] */
392 0 : IF( GE_32( L_min_energy, MAX_32 ) )
393 : {
394 0 : return 0;
395 : }
396 :
397 0 : IF( GT_16( nb_min, 16 ) ) /* inv_sqi & sqi are built for a maximum of nb_min-2 = 14 values*/
398 : {
399 0 : return 0;
400 : }
401 : /*--------------------------------------------------------------------
402 : * Determine the number of samples to be added or removed at each pitch
403 : * cycle whereby less samples are added/removed at the beginning and
404 : * more towards the end of the frame
405 : * --------------------------------------------------------------------*/
406 0 : test();
407 0 : IF( EQ_16( nb_min, 1 ) || EQ_16( abs_s( point_to_remove ), 1 ) )
408 : {
409 0 : nb_min = 1;
410 0 : move16();
411 0 : points_by_pos[0] = abs_s( point_to_remove );
412 0 : move16();
413 : }
414 : ELSE
415 : {
416 : /* First position */
417 : /* fact = (float)fabs(point_to_remove) / sqi[nb_min-2]; (nb_min*nb_min) */
418 0 : fact = mult_r( shl( abs_s( point_to_remove ), 7 ), inv_sqi[nb_min - 2] ); /*Q7 */
419 0 : points_by_pos[0] = mult_r( fact, 256 ); /*Q7 */
420 0 : move16();
421 0 : total_point = points_by_pos[0];
422 0 : move16();
423 :
424 0 : FOR( i = 2; i <= nb_min; i++ )
425 : {
426 : /* points_by_pos[i-1] = (Word16)(fact*(sqi[i-2]) - total_point+0.5) */
427 0 : points_by_pos[i - 1] = sub( shr( extract_l( L_mac0( 64L, fact, sqi[i - 2] ) ), 7 ), total_point );
428 0 : move16();
429 0 : total_point = add( total_point, points_by_pos[i - 1] );
430 :
431 : /* ensure a constant increase */
432 0 : IF( LT_16( points_by_pos[i - 1], points_by_pos[i - 2] ) )
433 : {
434 0 : tmp16 = points_by_pos[i - 2];
435 0 : move16();
436 0 : points_by_pos[i - 2] = points_by_pos[i - 1];
437 0 : move16();
438 0 : points_by_pos[i - 1] = tmp16;
439 0 : move16();
440 : }
441 : }
442 : }
443 : /* --------------------------------------------------------------------
444 : * Sample deletion or insertion is performed in minimum energy regions.
445 : * At the end of this section the last maximum pulse in the concealed
446 : * excitation is forced to align to the actual maximum pulse position
447 : * at the end of the frame which is transmitted in the future frame.
448 : * --------------------------------------------------------------------*/
449 0 : if ( point_to_remove > 0 )
450 : {
451 0 : point_to_add = point_to_remove;
452 0 : move16();
453 : }
454 :
455 0 : pt_exc = exc_tmp;
456 0 : move16();
457 0 : pt_exc1 = exc;
458 0 : move16();
459 :
460 0 : i = 0;
461 0 : move16();
462 0 : pt_pos = min_pos + sub( nb_min, 1 );
463 :
464 0 : IF( point_to_add > 0 ) /* Samples insertion */
465 : {
466 0 : remaining_len = L_frame;
467 0 : move16();
468 0 : FOR( i = 0; i < nb_min; i++ )
469 : {
470 : /* Copy section */
471 : /* Compute len to copy */
472 0 : tmp_len = *pt_pos;
473 0 : move16();
474 0 : IF( i != 0 )
475 : {
476 : /* Compute len to copy */
477 0 : tmp_len = sub( sub( *pt_pos, *( pt_pos + 1 ) ), points_by_pos[i - 1] );
478 : }
479 : /*Copy section */
480 0 : Copy( pt_exc1, pt_exc, tmp_len );
481 0 : remaining_len = sub( remaining_len, tmp_len );
482 0 : pt_exc1 += tmp_len;
483 0 : pt_exc += tmp_len;
484 :
485 : /* Find point to add and Add points */
486 0 : tmp16 = mult_r( *pt_exc1, -1638 );
487 0 : FOR( j = 0; j < points_by_pos[i]; j++ )
488 : {
489 0 : *pt_exc++ = tmp16;
490 0 : move16(); /* repeat last point */
491 0 : tmp16 = negate( tmp16 );
492 : }
493 :
494 0 : remaining_len = sub( remaining_len, points_by_pos[i] );
495 0 : pt_pos--;
496 : }
497 : /* Copy remaining data */
498 0 : remaining_len = s_max( 0, remaining_len );
499 0 : Copy( pt_exc1, pt_exc, remaining_len );
500 : /* Update true excitation vector */
501 0 : Copy( exc_tmp, exc, L_frame );
502 : }
503 : ELSE /* Samples deletion */
504 : {
505 0 : remaining_len = L_frame;
506 0 : move16();
507 :
508 0 : FOR( i = 0; i < nb_min; i++ )
509 : {
510 : /* Compute len to copy */
511 0 : tmp_len = *pt_pos;
512 0 : move16();
513 0 : IF( i != 0 )
514 : {
515 : /* Compute len to copy */
516 0 : tmp_len = sub( sub( *pt_pos, *( pt_pos + 1 ) ), points_by_pos[i - 1] );
517 : }
518 0 : Copy( pt_exc1, pt_exc, tmp_len );
519 0 : remaining_len = sub( remaining_len, tmp_len );
520 0 : pt_exc1 += tmp_len;
521 0 : pt_exc += tmp_len;
522 : /* Remove points */
523 0 : FOR( j = 0; j < points_by_pos[i]; j++ )
524 : {
525 0 : pt_exc1++;
526 : }
527 0 : pt_pos--;
528 : }
529 : /* Copy remaining data */
530 0 : remaining_len = s_max( 0, remaining_len );
531 0 : Copy( pt_exc1, pt_exc, remaining_len );
532 : /* Update true excitation vector */
533 0 : Copy( exc_tmp, exc, L_frame );
534 : }
535 :
536 0 : return 1;
537 : }
|