Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : /*====================================================================================
34 : EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0
35 : ====================================================================================*/
36 :
37 : #include <stdint.h>
38 : #include "options.h"
39 : #ifdef DEBUGGING
40 : #include "debug.h"
41 : #endif
42 : #include <math.h>
43 : #include "cnst.h"
44 : #include "rom_dec.h"
45 : #include "prot.h"
46 : #include "wmc_auto.h"
47 :
48 : /*-------------------------------------------------------------------------
49 : * FEC_synchro_exc()
50 : *
51 : * Perform resynchronisation of the last glottal pulse in voiced frame lost
52 : *------------------------------------------------------------------------*/
53 :
54 : /*! r: do_WI flag */
55 0 : static int16_t FEC_synchro_exc(
56 : const int16_t L_frame, /* i : length of the frame */
57 : float *exc, /* i/o: exc vector to modify */
58 : const int16_t desire_puls_pos, /* i : Pulse position send by the encoder */
59 : const int16_t true_puls_pos, /* i : Present pulse location */
60 : const int16_t Old_pitch /* i : Pitch use to create temporary adaptive codebook */
61 : )
62 : {
63 : float exc_tmp[L_FRAME16k + L_SUBFR], min_energy, *pt_exc, *pt_exc1, ftmp, fact;
64 0 : int16_t i, j, point_to_remove, point_to_add = -1, nb_min;
65 : int16_t min_pos[L_FRAME16k / PIT_MIN_DOUBLEEXTEND], points_by_pos[L_FRAME16k / PIT_MIN_DOUBLEEXTEND], total_point, tmp_len;
66 : int16_t *pt_pos, pos, start_search, tmp16;
67 : int16_t remaining_len;
68 :
69 : /* Init */
70 0 : for ( i = 0; i < L_FRAME16k / PIT_MIN_DOUBLEEXTEND; i++ )
71 : {
72 0 : min_pos[i] = 10000;
73 0 : points_by_pos[i] = 0;
74 : }
75 :
76 : /* Find number of point to remove and number of minimum */
77 0 : point_to_remove = true_puls_pos - desire_puls_pos; /* if it is negative it means remove point else it means add point */
78 :
79 0 : pos = L_frame - true_puls_pos;
80 0 : nb_min = pos / Old_pitch;
81 :
82 : /* if Old pitch < 128, must have at least 2 min */
83 0 : if ( Old_pitch <= 128 && nb_min < 2 )
84 : {
85 0 : nb_min = 2;
86 : }
87 :
88 : /* Must have at least 1 min */
89 0 : if ( nb_min == 0 )
90 : {
91 : /* Safety check, should be very rare but still needed*/
92 0 : nb_min = 1;
93 : }
94 :
95 0 : pt_exc = exc + pos;
96 :
97 : /* Find start_search for minimum energy search*/
98 0 : start_search = -3 * Old_pitch / 4;
99 :
100 0 : if ( start_search + pos < 0 )
101 : {
102 : /* This case is rare but still need to be taken care*/
103 0 : start_search = -pos;
104 :
105 0 : if ( abs( start_search ) < Old_pitch / 8 )
106 : {
107 : /* it's not safe to remove/add point inside 1/8 of the pulse position */
108 0 : return 0;
109 : }
110 : }
111 :
112 : /* Find min energy in the first pitch section */
113 0 : min_energy = 65536 * 65536.0f;
114 :
115 : /* --------------------------------------------------------------------
116 : * The minimum energy regions are determined by the computing the energy
117 : * using a sliding 5-sample window. The minimum energy position is set
118 : * at the middle of the window at which the energy is at minimum
119 : * --------------------------------------------------------------------*/
120 :
121 0 : ftmp = ( pt_exc[start_search] * pt_exc[start_search] );
122 0 : ftmp += ( pt_exc[start_search + 1] * pt_exc[start_search + 1] );
123 0 : ftmp += ( pt_exc[start_search + 2] * pt_exc[start_search + 2] );
124 0 : ftmp += ( pt_exc[start_search + 3] * pt_exc[start_search + 3] );
125 0 : ftmp += ( pt_exc[start_search + 4] * pt_exc[start_search + 4] );
126 :
127 0 : if ( ftmp < min_energy )
128 : {
129 0 : min_energy = ftmp;
130 0 : min_pos[0] = ( pos + start_search + 2 );
131 : }
132 :
133 0 : for ( i = start_search; i < -5; i++ )
134 : {
135 0 : ftmp -= pt_exc[i] * pt_exc[i];
136 0 : ftmp += pt_exc[i + 5] * pt_exc[i + 5];
137 0 : if ( ftmp < min_energy )
138 : {
139 0 : min_energy = ftmp;
140 0 : min_pos[0] = pos + i + 2;
141 : }
142 : }
143 :
144 0 : for ( j = 1; j < nb_min; j++ )
145 : {
146 0 : min_pos[j] = min_pos[j - 1] - Old_pitch;
147 : /* If the first minimum is in the past, forget this minimum */
148 0 : if ( min_pos[j] < 0 )
149 : {
150 : /* Safety check */
151 0 : min_pos[j] = -10000;
152 0 : nb_min = nb_min - 1;
153 : }
154 : }
155 :
156 : /* safety-measure against not properly initialized min_pos[] */
157 0 : if ( min_energy >= 65536 * 65536.0f )
158 : {
159 0 : return 0;
160 : }
161 :
162 : /*--------------------------------------------------------------------
163 : * Determine the number of samples to be added or removed at each pitch
164 : * cycle whereby less samples are added/removed at the beginning and
165 : * more towards the end of the frame
166 : * --------------------------------------------------------------------*/
167 :
168 0 : if ( nb_min == 1 || abs( point_to_remove ) == 1 )
169 : {
170 0 : nb_min = 1;
171 0 : points_by_pos[0] = (int16_t) abs( point_to_remove );
172 : }
173 : else
174 : {
175 : /* First position */
176 0 : fact = (float) abs( point_to_remove ) / ( nb_min * nb_min );
177 :
178 0 : total_point = (int16_t) ( fact + 0.5 );
179 0 : points_by_pos[0] = total_point;
180 :
181 0 : for ( i = 2; i <= nb_min; i++ )
182 : {
183 0 : points_by_pos[i - 1] = (int16_t) ( fact * ( i * i ) - total_point + 0.5 );
184 0 : total_point += points_by_pos[i - 1];
185 :
186 : /* ensure a constant increase */
187 0 : if ( points_by_pos[i - 1] < points_by_pos[i - 2] )
188 : {
189 0 : tmp16 = points_by_pos[i - 2];
190 0 : points_by_pos[i - 2] = points_by_pos[i - 1];
191 0 : points_by_pos[i - 1] = tmp16;
192 : }
193 : }
194 : }
195 :
196 : /* --------------------------------------------------------------------
197 : * Sample deletion or insertion is performed in minimum energy regions.
198 : * At the end of this section the last maximum pulse in the concealed
199 : * excitation is forced to align to the actual maximum pulse position
200 : * at the end of the frame which is transmitted in the future frame.
201 : * --------------------------------------------------------------------*/
202 :
203 0 : if ( point_to_remove > 0 )
204 : {
205 0 : point_to_add = point_to_remove;
206 : }
207 :
208 0 : pt_exc = exc_tmp;
209 0 : pt_exc1 = exc;
210 :
211 0 : i = 0;
212 0 : pt_pos = min_pos + nb_min - 1;
213 0 : if ( point_to_add > 0 ) /* add some points */
214 : {
215 0 : remaining_len = L_frame;
216 :
217 0 : for ( i = 0; i < nb_min; i++ )
218 : {
219 : /* Copy section */
220 0 : if ( i == 0 )
221 : {
222 : /* Compute len to copy */
223 0 : tmp_len = *pt_pos;
224 : }
225 : else
226 : {
227 : /* Compute len to copy */
228 0 : tmp_len = *pt_pos - *( pt_pos + 1 ) - points_by_pos[i - 1];
229 : }
230 :
231 0 : mvr2r( pt_exc1, pt_exc, tmp_len );
232 0 : remaining_len -= tmp_len;
233 0 : pt_exc1 += tmp_len;
234 0 : pt_exc += tmp_len;
235 :
236 : /* add some points */
237 0 : ftmp = -( *pt_exc1 / 20 );
238 0 : for ( j = 0; j < points_by_pos[i]; j++ )
239 : {
240 0 : *pt_exc++ = ftmp;
241 0 : ftmp = -ftmp;
242 : }
243 :
244 0 : remaining_len -= points_by_pos[i];
245 0 : pt_pos--;
246 : }
247 :
248 : /* Copy remaining length */
249 0 : remaining_len = max( 0, remaining_len );
250 0 : mvr2r( pt_exc1, pt_exc, remaining_len );
251 :
252 : /* Update true excitation buffer*/
253 0 : mvr2r( exc_tmp, exc, L_frame );
254 : }
255 : else /* Remove points */
256 : {
257 0 : remaining_len = L_frame;
258 :
259 0 : for ( i = 0; i < nb_min; i++ )
260 : {
261 0 : if ( i == 0 )
262 : {
263 : /* Compute len to copy */
264 0 : tmp_len = *pt_pos;
265 : }
266 : else
267 : {
268 : /* Compute len to copy */
269 0 : tmp_len = *pt_pos - *( pt_pos + 1 ) - points_by_pos[i - 1];
270 : }
271 :
272 0 : mvr2r( pt_exc1, pt_exc, tmp_len );
273 0 : remaining_len -= tmp_len;
274 0 : pt_exc1 += tmp_len;
275 0 : pt_exc += tmp_len;
276 :
277 : /* Remove points */
278 0 : for ( j = 0; j < points_by_pos[i]; j++ )
279 : {
280 0 : pt_exc1++;
281 : }
282 0 : pt_pos--;
283 : }
284 :
285 : /* Copy remaining length */
286 0 : remaining_len = max( 0, remaining_len );
287 0 : mvr2r( pt_exc1, pt_exc, remaining_len );
288 :
289 : /* Update true excitation buffer*/
290 0 : mvr2r( exc_tmp, exc, L_frame );
291 : }
292 :
293 0 : return 1;
294 : }
295 :
296 :
297 : /*---------------------------------------------------------------------*
298 : * FEC_SinOnset()
299 : *
300 : * Create an artificial onset when it is lost
301 : *---------------------------------------------------------------------*/
302 :
303 9 : void FEC_SinOnset(
304 : float *exc, /* i/o: exc vector to modify */
305 : int16_t puls_pos, /* i : last pulse position desired */
306 : int16_t T0,
307 : float enr_q, /* i : energy provided by the encoder */
308 : float *Aq, /* i : A(z) filter */
309 : const int16_t L_frame /* i : frame length */
310 : )
311 : {
312 9 : int16_t P0, onset_len, sign = 0, i, len, L_subfr;
313 : float h1[L_SUBFR16k], mem[M], exc_tmp[L_FRAME16k + MODE1_L_FIR_FER];
314 : float *pt_end, *pt_exc, enr_LP, gain;
315 :
316 9 : L_subfr = L_SUBFR;
317 9 : if ( L_frame == L_FRAME16k )
318 : {
319 9 : L_subfr = L_SUBFR16k;
320 : }
321 :
322 9 : if ( T0 < 2 * L_subfr )
323 : {
324 9 : onset_len = 2 * L_subfr;
325 : }
326 : else
327 : {
328 0 : onset_len = T0;
329 : }
330 :
331 :
332 9 : P0 = puls_pos;
333 :
334 9 : if ( P0 < 0 )
335 : {
336 0 : sign = 1;
337 0 : P0 = -P0;
338 : }
339 :
340 9 : if ( P0 > PIT_MAX && L_frame == L_FRAME )
341 : {
342 0 : P0 = PIT_MAX; /* Should never be the case, however... */
343 : }
344 9 : else if ( P0 > PIT16k_MAX && L_frame == L_FRAME16k )
345 : {
346 0 : P0 = PIT16k_MAX; /* Should never be the case, however... */
347 : }
348 9 : set_f( exc_tmp, 0, L_frame + MODE1_L_FIR_FER ); /* Reset excitation vector */
349 :
350 : /*--------------------------------------------*
351 : * Find LP filter impulse response energy
352 : *--------------------------------------------*/
353 :
354 9 : set_f( h1, 0, L_subfr ); /* Find the impulse response */
355 9 : set_f( mem, 0, M );
356 9 : h1[0] = 1.0f;
357 9 : syn_filt( Aq, M, h1, h1, L_subfr, mem, 0 );
358 9 : enr_LP = dotp( h1, h1, L_subfr ) + 0.01f; /* Find the impulse response energy */
359 :
360 : /*------------------------------------------------------------------------------------------*
361 : * Construct the harmonic part as a train of low-pass filtered pulses
362 : *------------------------------------------------------------------------------------------*/
363 :
364 9 : pt_exc = exc_tmp + L_frame - 1 - MODE1_L_FIR_FER / 2 - P0; /* beginning of the 1st pulse */
365 9 : pt_end = exc_tmp + onset_len;
366 :
367 9 : len = (int16_t) ( pt_exc - pt_end );
368 9 : if ( len > MODE1_L_FIR_FER )
369 : {
370 9 : len = MODE1_L_FIR_FER;
371 : }
372 9 : if ( !sign )
373 : {
374 54 : for ( i = 0; i < len; i++ )
375 : {
376 : /* The filter response would have E=1 in full band. */
377 45 : pt_exc[i] += h_low[i]; /* As it is lp filtered, the E is somewhat lower */
378 : }
379 : }
380 : else
381 : {
382 0 : for ( i = 0; i < len; i++ )
383 : {
384 : /* The filter response would have E=1 in full band. */
385 0 : pt_exc[i] -= h_low[i]; /* As it is lp filtered, the E is somewhat lower */
386 : }
387 : }
388 :
389 9 : gain = (float) sqrt( 1.5 * enr_q / enr_LP ); /* divide by LP filter E, scale by transmitted E */
390 9 : gain *= 0.96f;
391 2889 : for ( i = 0; i < L_frame; i++ )
392 : {
393 2880 : exc_tmp[i] *= gain;
394 : }
395 :
396 9 : mvr2r( &exc_tmp[L_frame - L_EXC_MEM], exc, L_EXC_MEM );
397 :
398 9 : return;
399 : }
400 :
401 0 : int16_t FEC_enhACB(
402 : const int16_t L_frame, /* i : frame length */
403 : const int16_t last_L_frame, /* i : frame length of last frame */
404 : float *exc_io, /* i/o: adaptive codebook memory */
405 : const int16_t new_pit, /* i : decoded first frame pitch */
406 : const int16_t puls_pos, /* i : decoder position of the last glottal pulses decoded in the previous frame */
407 : const float bfi_pitch /* i : pitch used for concealment */
408 : )
409 : {
410 : int16_t Tc, P0, sign, pit_search;
411 : int16_t Tlist[10], Terr, diff_pit, dist_Plast;
412 : float ftmp;
413 : float exc[L_FRAME16k + L_SUBFR];
414 0 : int16_t do_WI = 1;
415 :
416 0 : set_f( exc, 0.0f, L_FRAME16k - L_EXC_MEM );
417 0 : set_f( exc + L_FRAME16k, 0.0f, L_SUBFR );
418 0 : mvr2r( exc_io, exc + L_FRAME16k - L_EXC_MEM, L_EXC_MEM );
419 :
420 0 : Tc = (int16_t) bfi_pitch;
421 0 : mvr2r( exc + L_FRAME16k - Tc, exc + L_FRAME16k, L_SUBFR );
422 :
423 : /*------------------------------------------------------------
424 : * Decode phase information transmitted in the bitstream
425 : * (The position of the absolute maximum glottal pulse from
426 : * the end of the frame and its sign)
427 : *------------------------------------------------------------*/
428 :
429 0 : P0 = puls_pos;
430 0 : sign = 0;
431 0 : if ( P0 < 0 )
432 : {
433 0 : sign = 1;
434 0 : P0 = -P0;
435 : }
436 :
437 0 : if ( L_frame == L_FRAME )
438 : {
439 0 : if ( P0 > PIT_MAX )
440 : {
441 0 : P0 = PIT_MAX; /* Should never be the case, however... */
442 : }
443 : }
444 : else /* L_frame == L_FRAME16k */
445 : {
446 0 : if ( P0 > PIT16k_MAX )
447 : {
448 0 : P0 = PIT16k_MAX; /* Should never be the case, however... */
449 : }
450 : }
451 :
452 : /*----------------------------------------------------------------------------------
453 : * Find the position of the first the maximum(minimum) lp_filtered pulse
454 : * <----- Mem --->|<--------------------- L_frame ------------>|<----- L_SUBFR --->|
455 : * |<-------pit_search----> | |
456 : *----------------------------------------------------------------------------------*/
457 :
458 0 : pit_search = Tc;
459 :
460 0 : Tlist[0] = findpulse( L_frame, exc + L_frame - pit_search, pit_search, DEC, &sign );
461 :
462 0 : Terr = (int16_t) abs( pit_search - Tlist[0] - P0 );
463 :
464 0 : dist_Plast = Tc - Tlist[0];
465 :
466 0 : Tlist[1] = findpulse( L_frame, exc + L_frame - pit_search, pit_search + L_SUBFR, DEC, &sign );
467 :
468 0 : if ( Terr > abs( Tlist[1] - Tc + P0 ) )
469 : {
470 0 : dist_Plast = Tc - Tlist[1];
471 0 : Terr = (int16_t) abs( Tlist[1] - Tc + P0 );
472 : }
473 :
474 0 : diff_pit = (int16_t) abs( new_pit - Tc );
475 0 : ftmp = (float) (int16_t) ( (float) L_frame / (float) Tc + 0.5 );
476 :
477 0 : if ( Terr <= ftmp * diff_pit && Terr != 0 /* If Terr = 0, no resynchronization required */
478 0 : && Terr < L_SUBFR ) /* prevent catastrophy search */
479 : {
480 : /* perform excitation resynchronization here */
481 0 : do_WI = FEC_synchro_exc( L_frame, exc, P0, dist_Plast, Tc );
482 0 : mvr2r( exc + L_FRAME16k - L_EXC_MEM, exc_io, L_EXC_MEM );
483 : }
484 : else
485 : {
486 0 : do_WI = 0;
487 : }
488 :
489 0 : if ( last_L_frame != L_FRAME16k )
490 : {
491 : /* This is essential in case of bitrate switching + FEC*/
492 0 : do_WI = 0;
493 : }
494 :
495 0 : return do_WI;
496 : }
|