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 "prot.h"
44 : #include "wmc_auto.h"
45 :
46 :
47 : /*-------------------------------------------------------------------*
48 : * Local functions
49 : *
50 : *-------------------------------------------------------------------*/
51 :
52 0 : static void LpFilter2(
53 : const float *x,
54 : float *y,
55 : const int16_t N,
56 : float *mem )
57 : {
58 : int16_t i;
59 :
60 0 : y[0] = 0.18f * mem[0] + 0.64f * mem[1] + 0.18f * x[0];
61 0 : y[1] = 0.18f * mem[1] + 0.64f * y[0] + 0.18f * x[1];
62 :
63 0 : for ( i = 2; i < N; i++ )
64 : {
65 0 : y[i] = 0.18f * y[i - 2] + 0.64f * y[i - 1] + 0.18f * x[i];
66 : }
67 :
68 0 : return;
69 : }
70 :
71 0 : static float harmo(
72 : const float *X,
73 : const int16_t n,
74 : const float f )
75 : {
76 0 : int16_t h, k, m = 8;
77 0 : float ener = 0, ener_harmo = 0;
78 :
79 0 : for ( k = 1; k < m + 1; k++ )
80 : {
81 0 : h = (int16_t) ( k * f - 0.5f );
82 0 : if ( k * f - h > 0.5f )
83 : {
84 0 : ener_harmo += X[h] * X[h] + X[h + 1] * X[h + 1];
85 : }
86 : else
87 : {
88 0 : ener_harmo += X[h] * X[h];
89 : }
90 : }
91 :
92 0 : for ( k = 0; k < n; k++ )
93 : {
94 0 : ener += X[k] * X[k];
95 : }
96 :
97 0 : return ener_harmo / ( ener + EPSILON );
98 : }
99 :
100 :
101 0 : static int16_t Is_Periodic(
102 : const float cov_max,
103 : const int16_t zp,
104 : const float ener,
105 : const float ener_mean,
106 : const int16_t pitch,
107 : const int16_t L_frameTCX,
108 : const float *mdctdata )
109 : {
110 0 : int16_t flag = 0;
111 0 : float f = 2.0f * L_frameTCX / pitch;
112 : float harm;
113 :
114 0 : harm = harmo( mdctdata /*X*/, L_frameTCX, f );
115 :
116 0 : if ( ener < 50 || ( ener < ener_mean - 8.0f && cov_max < 0.9f ) )
117 : {
118 0 : flag = 0;
119 : }
120 0 : else if ( cov_max > 0.8f )
121 : {
122 0 : flag = 1;
123 : }
124 0 : else if ( zp > 100 )
125 : {
126 0 : flag = 0;
127 : }
128 0 : else if ( ener < ener_mean - 6 )
129 : {
130 0 : flag = 0;
131 : }
132 0 : else if ( ener > ener_mean + 1 && cov_max > 0.6f )
133 : {
134 0 : flag = 1;
135 : }
136 0 : else if ( harm < 0.7f )
137 : {
138 0 : flag = 0;
139 : }
140 : else
141 : {
142 0 : flag = 1;
143 : }
144 :
145 0 : return flag;
146 : }
147 :
148 :
149 0 : static int16_t zero_pass(
150 : const float *s,
151 : const int16_t N )
152 : {
153 0 : int16_t zp = 0, i;
154 :
155 0 : for ( i = 1; i < N; i++ )
156 : {
157 0 : if ( s[i - 1] * s[i] <= 0 )
158 : {
159 0 : zp++;
160 : }
161 : }
162 :
163 0 : return zp;
164 : }
165 :
166 :
167 0 : static float sig_tilt(
168 : const float *s,
169 : const int16_t L_frameTCX )
170 : {
171 : float tilt, enr1, enr2;
172 0 : int16_t L_subfr, shift = 2;
173 : const float *p1, *p2;
174 :
175 0 : L_subfr = L_frameTCX >> 2;
176 0 : p1 = s + L_subfr;
177 0 : p2 = s + L_subfr - shift;
178 0 : enr1 = dotp( p1, p2, L_frameTCX - L_subfr );
179 0 : enr2 = dotp( p1, p1, L_frameTCX - L_subfr );
180 0 : tilt = enr1 / ( enr2 + EPSILON );
181 :
182 0 : return tilt;
183 : }
184 :
185 :
186 0 : static int16_t pitch_search(
187 : float *s, /* lastPcmOut */
188 : float *outx_new,
189 : const int16_t L_frameTCX,
190 : float *voicing,
191 : int16_t *zp,
192 : float *ener,
193 : float ener_mean,
194 : float *mdct_data,
195 : const int16_t core )
196 : {
197 : int16_t pitch, t, i;
198 : float cov_max, temp, tmp, tilt, mdct_ener, low_freq_rate;
199 : float s_LP[L_FRAME_MAX];
200 : float s_tmp[L_FRAME_MAX];
201 : int16_t L_frameTCX_tmp;
202 : int16_t pitch_tmp[3];
203 : float mem[2];
204 : int16_t start_pos, end_pos;
205 : int16_t cov_size;
206 : int16_t flag, zp_current;
207 : int16_t curr_frmsize;
208 : float tmp_last;
209 : float cov_max_tmp;
210 : float temp2, voicing2;
211 :
212 0 : set_f( s_LP, 0, L_FRAME_MAX );
213 0 : mem[0] = 0.0f;
214 0 : mem[1] = 0.0f;
215 0 : tmp_last = 0;
216 0 : cov_max_tmp = 0;
217 0 : flag = 0;
218 :
219 0 : curr_frmsize = L_frameTCX;
220 0 : if ( core == TCX_10_CORE )
221 : {
222 0 : curr_frmsize = L_frameTCX >> 1;
223 : }
224 :
225 0 : zp_current = zero_pass( outx_new, curr_frmsize );
226 0 : if ( core == TCX_10_CORE )
227 : {
228 0 : zp_current = zp_current << 1;
229 : }
230 :
231 0 : if ( L_frameTCX <= L_FRAME )
232 : {
233 0 : if ( zp_current > 70 )
234 : {
235 0 : return 0;
236 : }
237 : }
238 : else
239 : {
240 0 : if ( zp_current > 105 )
241 : {
242 0 : return 0;
243 : }
244 : }
245 :
246 0 : t = 30;
247 0 : if ( core == TCX_10_CORE )
248 : {
249 0 : t = 30 / 2;
250 0 : mdct_data = mdct_data + curr_frmsize;
251 : }
252 :
253 0 : mdct_ener = 0;
254 0 : for ( i = 0; i < t; i++ )
255 : {
256 0 : mdct_ener += mdct_data[i] * mdct_data[i];
257 : }
258 0 : low_freq_rate = mdct_ener;
259 0 : for ( ; i < curr_frmsize; i++ )
260 : {
261 0 : mdct_ener += mdct_data[i] * mdct_data[i];
262 : }
263 0 : low_freq_rate /= ( mdct_ener + EPSILON );
264 :
265 0 : if ( core == TCX_10_CORE )
266 : {
267 0 : mdct_data = mdct_data - curr_frmsize;
268 : }
269 :
270 0 : if ( low_freq_rate < 0.02f )
271 : {
272 0 : return 0;
273 : }
274 :
275 0 : LpFilter2( s, s_LP, L_frameTCX, mem );
276 :
277 0 : tilt = sig_tilt( s_LP, L_frameTCX );
278 :
279 0 : if ( L_frameTCX <= L_FRAME16k )
280 : {
281 0 : if ( tilt < 0.5f )
282 : {
283 0 : return 0;
284 : }
285 : }
286 : else
287 : {
288 0 : if ( tilt < 0.7f )
289 : {
290 0 : return 0;
291 : }
292 : }
293 :
294 0 : cov_max = 0;
295 0 : pitch = 0;
296 0 : if ( L_frameTCX <= L_FRAME16k )
297 : {
298 0 : start_pos = (int16_t) ( L_frameTCX * 34 / 256.0 + 0.5f );
299 0 : end_pos = (int16_t) ( L_frameTCX * 3 / 4.0 + 0.5f );
300 0 : for ( t = start_pos; t < end_pos; t++ )
301 : {
302 0 : cov_size = L_frameTCX - t;
303 0 : tmp = dotp( s_LP, s_LP + t, cov_size ) / cov_size;
304 0 : if ( t > start_pos ) /* don't use the first value */
305 : {
306 0 : if ( tmp > tmp_last ) /* store the current cov, if it is larger than the last one */
307 : {
308 0 : cov_max_tmp = tmp;
309 : }
310 0 : else if ( cov_max < cov_max_tmp ) /* otherwise */
311 : {
312 0 : cov_max = cov_max_tmp; /* use the last value cov, being a max */
313 0 : pitch = t - 1; /* and the last index as pitch */
314 : }
315 : }
316 0 : tmp_last = tmp;
317 : }
318 :
319 0 : temp = (float) ( sqrt( dotp( s_LP + pitch, s_LP + pitch, L_frameTCX - pitch ) ) * sqrt( dotp( s_LP, s_LP, L_frameTCX - pitch ) ) );
320 :
321 0 : *voicing = cov_max * ( L_frameTCX - pitch ) / ( temp + EPSILON );
322 :
323 0 : temp2 = (float) ( sqrt( dotp( s_LP + ( pitch >> 1 ), s_LP + ( pitch >> 1 ), L_frameTCX - ( pitch >> 1 ) ) ) * sqrt( dotp( s_LP, s_LP, L_frameTCX - ( pitch >> 1 ) ) ) );
324 :
325 0 : voicing2 = dotp( s_LP + ( pitch >> 1 ), s_LP, L_frameTCX - ( pitch >> 1 ) ) / temp2;
326 :
327 0 : if ( voicing2 > *voicing )
328 : {
329 0 : pitch = pitch >> 1;
330 0 : *voicing = voicing2;
331 : }
332 : }
333 : else
334 : {
335 0 : L_frameTCX_tmp = L_frameTCX >> 1;
336 :
337 0 : for ( i = 0; i < L_frameTCX_tmp; i++ )
338 : {
339 0 : s_tmp[i] = s_LP[2 * i];
340 : }
341 :
342 0 : start_pos = (int16_t) ( ( 34.0f * L_frameTCX_tmp ) / L_FRAME + 0.5f );
343 0 : end_pos = (int16_t) ( ( L_frameTCX_tmp >> 1 ) * 1.5f + 0.5f );
344 0 : for ( t = start_pos; t < end_pos; t++ )
345 : {
346 0 : cov_size = L_frameTCX_tmp - t;
347 0 : tmp = dotp( s_tmp, s_tmp + t, cov_size ) / cov_size;
348 :
349 0 : if ( t > start_pos ) /* don't use the first value */
350 : {
351 0 : if ( tmp > tmp_last ) /* store the current cov, if it is larger than the last one */
352 : {
353 0 : cov_max_tmp = tmp;
354 : }
355 0 : else if ( cov_max < cov_max_tmp ) /* otherwise */
356 : {
357 0 : cov_max = cov_max_tmp; /* use the last value cov, being a max */
358 0 : pitch = t - 1; /* and the last index as pitch */
359 : }
360 : }
361 :
362 0 : tmp_last = tmp;
363 : }
364 :
365 0 : if ( pitch > 0 )
366 : {
367 0 : pitch_tmp[0] = max( 2 * pitch - 1, 0 );
368 0 : pitch_tmp[1] = 2 * pitch;
369 0 : pitch_tmp[2] = 2 * pitch + 1;
370 0 : cov_max = 0;
371 0 : pitch = 0;
372 :
373 0 : for ( i = 0; i < 3; i++ )
374 : {
375 0 : cov_size = L_frameTCX - pitch_tmp[i];
376 :
377 0 : temp = (float) ( sqrt( dotp( s_LP + pitch_tmp[i], s_LP + pitch_tmp[i], cov_size ) ) * sqrt( dotp( s_LP, s_LP, cov_size ) ) );
378 :
379 0 : tmp = dotp( s_LP, s_LP + pitch_tmp[i], cov_size ) / ( temp + EPSILON );
380 :
381 0 : if ( tmp > cov_max )
382 : {
383 0 : cov_max = tmp;
384 0 : pitch = pitch_tmp[i];
385 : }
386 : }
387 :
388 0 : *voicing = cov_max;
389 : }
390 : }
391 :
392 0 : if ( pitch > 0 )
393 : {
394 0 : flag = Is_Periodic( *voicing, *zp, *ener, ener_mean, pitch, L_frameTCX, mdct_data );
395 : }
396 :
397 0 : if ( flag == 0 )
398 : {
399 0 : pitch = 0;
400 : }
401 :
402 0 : return pitch;
403 : }
404 :
405 :
406 0 : static int16_t OverlapAdd(
407 : float *pitch125_data,
408 : float *sbuf,
409 : const int16_t n,
410 : const int16_t pitch,
411 : const int16_t Bufsize )
412 : {
413 0 : int16_t pitch125 = (int16_t) floor( 0.5f + ( 1.25f * (float) pitch ) );
414 0 : int16_t Loverlap = pitch125 - pitch;
415 0 : int16_t n1 = min( Loverlap, Bufsize - n );
416 0 : int16_t n2 = min( pitch125, Bufsize - n );
417 : int16_t i;
418 : float tmp, dat;
419 :
420 0 : for ( i = 0; i < n1; i++ )
421 : {
422 0 : tmp = (float) i / (float) Loverlap;
423 0 : dat = sbuf[n + i];
424 0 : sbuf[n + i] = (float) ( ( 1.0 - tmp ) * dat + tmp * pitch125_data[i] );
425 : }
426 :
427 0 : for ( i = n1; i < n2; i++ )
428 : {
429 0 : sbuf[n + i] = pitch125_data[i];
430 : }
431 :
432 0 : return ( n + pitch );
433 : }
434 :
435 :
436 0 : static void add_noise(
437 : float *sbuf,
438 : float *outx_new_n1,
439 : float *noise_seg,
440 : const int16_t Len,
441 : float *gain,
442 : const float *gain_n,
443 : const int16_t firstFrame )
444 : {
445 : int16_t i;
446 :
447 0 : if ( !firstFrame )
448 : {
449 0 : sbuf[0] += *gain * ( noise_seg[0] - 0.68f * ( *outx_new_n1 ) );
450 0 : *gain = 0.99f * ( *gain ) + 0.01f * ( *gain_n );
451 : }
452 0 : for ( i = 1; i < Len; i++ )
453 : {
454 0 : sbuf[i] += *gain * ( noise_seg[i] - 0.68f * noise_seg[i - 1] );
455 0 : *gain = 0.99f * ( *gain ) + 0.01f * ( *gain_n );
456 : }
457 0 : *outx_new_n1 = noise_seg[i - 1];
458 :
459 0 : return;
460 : }
461 :
462 0 : static int16_t waveform_adj(
463 : T_PLCInfo_HANDLE hPlcInfo,
464 : float *overlapbuf,
465 : float *outdata2,
466 : float *outx_new,
467 : const int16_t L_frameTCX,
468 : const float voicing,
469 : const int16_t core )
470 : {
471 : int16_t i, i1, i2, zp1, zp2, pitch;
472 : float sbuf[L_FRAME_MAX];
473 : float tmp_buf[L_FRAME_MAX], *p_tmp;
474 : int16_t pitch125, Loverlap, n;
475 : float pitch125_data[L_FRAME_MAX];
476 :
477 0 : set_f( sbuf, 0, L_FRAME_MAX );
478 0 : set_f( tmp_buf, 0, L_FRAME_MAX );
479 0 : set_f( pitch125_data, 0, L_FRAME_MAX );
480 :
481 0 : zp1 = zero_pass( outdata2, L_frameTCX >> 1 );
482 0 : zp2 = zero_pass( outdata2 + ( L_frameTCX >> 1 ), L_frameTCX >> 1 );
483 :
484 0 : pitch = hPlcInfo->Pitch;
485 :
486 : /* judge if the pitch is usable */
487 0 : if ( 4 * max( zp1, 1 ) < zp2 )
488 : {
489 0 : return 0;
490 : }
491 :
492 : /* adjust the pitch value */
493 0 : if ( hPlcInfo->T_bfi && pitch <= L_frameTCX >> 1 && L_frameTCX > L_FRAME && core == TCX_20_CORE )
494 : {
495 0 : i1 = 1 + maximum( outx_new, pitch, NULL );
496 0 : i2 = 1 + maximum( outx_new + pitch, pitch, NULL );
497 0 : if ( (float) ( i2 + pitch - i1 ) < ( 1.25f * pitch ) && ( 1.25f * ( i2 + pitch - i1 ) ) > (float) pitch && (float) ( i2 + pitch - i1 ) < (float) ( L_frameTCX >> 1 ) )
498 : {
499 0 : pitch = i2 + pitch - i1;
500 : }
501 : }
502 :
503 0 : pitch125 = (int16_t) floor( 0.5f + ( 1.25f * (float) pitch ) );
504 0 : Loverlap = pitch125 - pitch;
505 0 : mvr2r( outdata2 + L_frameTCX - pitch, pitch125_data, pitch );
506 0 : mvr2r( outx_new, pitch125_data + pitch, Loverlap );
507 0 : mvr2r( outx_new, sbuf, L_frameTCX );
508 :
509 0 : p_tmp = tmp_buf + 1;
510 0 : mvr2r( pitch125_data, p_tmp, pitch125 );
511 0 : p_tmp[-1] = outdata2[L_frameTCX - pitch - 1];
512 0 : p_tmp[pitch125] = outx_new[Loverlap];
513 0 : for ( i = 0; i < pitch125; i++ )
514 : {
515 0 : pitch125_data[i] = 0.18f * p_tmp[i - 1] + 0.64f * p_tmp[i] + 0.18f * p_tmp[i + 1];
516 : }
517 :
518 0 : n = 0;
519 0 : while ( n < L_frameTCX ) /* periodical extension */
520 : {
521 0 : n = OverlapAdd( pitch125_data, sbuf, n, pitch, L_frameTCX );
522 : }
523 :
524 : /* maximum pitch lag is 3/4 L_frameTCX; pitch125_data is reused for
525 : temporary storage, since outdata2 (holding the pcm data of the
526 : last good frame) is still needed and overlapbuf overlaps outdata2 */
527 0 : mvr2r( &sbuf[L_frameTCX / 4], pitch125_data, ( 3 * L_frameTCX ) / 4 );
528 :
529 0 : hPlcInfo->nsapp_gain = 0.0;
530 0 : hPlcInfo->nsapp_gain_n = 1.0f - voicing / 2;
531 :
532 : /* use last good signal for noise generation */
533 0 : add_noise( sbuf, &( hPlcInfo->outx_new_n1 ), outdata2, L_frameTCX, &( hPlcInfo->nsapp_gain ), &( hPlcInfo->nsapp_gain_n ), 1 );
534 :
535 : /* save current (noisy) output from IMDCT */
536 0 : mvr2r( outx_new, hPlcInfo->data_noise, L_frameTCX );
537 :
538 : /* overlapbuf can now be filled with sbuf, needed for subsequently lost frames */
539 0 : mvr2r( pitch125_data, &overlapbuf[L_frameTCX / 4], ( 3 * L_frameTCX ) / 4 );
540 :
541 0 : for ( i = 0; i < L_frameTCX; i++ )
542 : {
543 0 : outx_new[i] = sbuf[i];
544 : }
545 :
546 0 : return pitch;
547 : }
548 :
549 :
550 : /*-------------------------------------------------------------------*
551 : * waveform_adj2()
552 : *
553 : *-------------------------------------------------------------------*/
554 :
555 0 : void waveform_adj2(
556 : T_PLCInfo_HANDLE hPlcInfo,
557 : float *overlapbuf,
558 : float *outx_new,
559 : const int16_t delay,
560 : const int16_t bfi_cnt,
561 : const int16_t bfi )
562 : {
563 0 : int16_t i, n = 0;
564 : float ratio;
565 : float sbuf[L_FRAME_MAX];
566 : int16_t pitch, L_frameTCX;
567 :
568 0 : pitch = hPlcInfo->Pitch;
569 0 : L_frameTCX = hPlcInfo->L_frameTCX;
570 :
571 0 : if ( pitch > 0 )
572 : {
573 0 : while ( n < L_frameTCX )
574 : {
575 : /* periodical extension */
576 0 : for ( i = 0; i < min( pitch, L_frameTCX - n ); i++ )
577 : {
578 0 : sbuf[n + i] = overlapbuf[L_frameTCX - pitch + i];
579 : }
580 0 : n += pitch;
581 : }
582 0 : for ( i = 0; i < L_frameTCX; i++ )
583 : {
584 0 : overlapbuf[i] = sbuf[i];
585 : }
586 :
587 : /* use last (noisy) output from IMDCT for noise generation */
588 0 : add_noise( sbuf, &( hPlcInfo->outx_new_n1 ), hPlcInfo->data_noise, L_frameTCX, &( hPlcInfo->nsapp_gain ), &( hPlcInfo->nsapp_gain_n ), 0 );
589 :
590 0 : if ( bfi )
591 : {
592 : /* save current (noisy) output from IMDCT */
593 0 : mvr2r( outx_new, hPlcInfo->data_noise, L_frameTCX );
594 : }
595 :
596 0 : if ( bfi_cnt == 4 || bfi == 0 )
597 : {
598 0 : if ( bfi == 0 )
599 : {
600 0 : int16_t gain_zero_start = 10000;
601 : /* overlap-and-add */
602 0 : if ( hPlcInfo->step_concealgain > EPSILON )
603 : {
604 0 : gain_zero_start = (int16_t) min( (float) L_FRAME48k, ( hPlcInfo->recovery_gain / hPlcInfo->step_concealgain ) ) + 1;
605 : }
606 :
607 0 : if ( delay > 0 )
608 : {
609 0 : L_frameTCX -= delay;
610 : }
611 0 : for ( i = 0; i < min( gain_zero_start, L_frameTCX ); i++ )
612 : {
613 0 : ratio = (float) i / (float) L_frameTCX;
614 0 : outx_new[i] = ( 1 - ratio ) * sbuf[i] * hPlcInfo->recovery_gain + ratio * outx_new[i];
615 0 : hPlcInfo->recovery_gain -= hPlcInfo->step_concealgain;
616 : }
617 0 : for ( i = gain_zero_start; i < L_frameTCX; i++ )
618 : {
619 0 : ratio = (float) i / (float) L_frameTCX;
620 0 : outx_new[i] = ratio * outx_new[i];
621 : }
622 0 : if ( hPlcInfo->recovery_gain < 0.0f )
623 : {
624 0 : hPlcInfo->recovery_gain = 0.0f;
625 : }
626 : }
627 : else
628 : {
629 : /* overlap-and-add */
630 0 : for ( i = 0; i < L_frameTCX; i++ )
631 : {
632 0 : ratio = (float) i / (float) L_frameTCX;
633 0 : outx_new[i] = ( 1 - ratio ) * sbuf[i] + ratio * outx_new[i];
634 : }
635 : }
636 : }
637 : else
638 : {
639 0 : mvr2r( sbuf, outx_new, L_frameTCX );
640 : }
641 : }
642 :
643 0 : return;
644 : }
645 :
646 :
647 : /*-------------------------------------------------------------------*
648 : * set_state()
649 : *
650 : *
651 : *-------------------------------------------------------------------*/
652 :
653 0 : void set_state(
654 : int16_t *state,
655 : const int16_t num,
656 : const int16_t N )
657 : {
658 : int16_t i;
659 :
660 0 : for ( i = 0; i < N - 1; i++ )
661 : {
662 0 : state[i] = state[i + 1];
663 : }
664 0 : state[N - 1] = num;
665 :
666 0 : return;
667 : }
668 :
669 :
670 : /*-------------------------------------------------------------------*
671 : * concealment_init()
672 : *
673 : *
674 : *-------------------------------------------------------------------*/
675 :
676 0 : void concealment_init(
677 : const int16_t L_frameTCX,
678 : T_PLCInfo_HANDLE hPlcInfo )
679 : {
680 : int16_t i;
681 :
682 0 : hPlcInfo->L_frameTCX = L_frameTCX;
683 0 : hPlcInfo->Pitch = 0;
684 0 : hPlcInfo->T_bfi = 0;
685 0 : hPlcInfo->outx_new_n1 = 0.0f;
686 0 : hPlcInfo->nsapp_gain = 0.0f;
687 0 : hPlcInfo->nsapp_gain_n = 0.0f;
688 0 : hPlcInfo->ener_mean = 59.4260f;
689 0 : hPlcInfo->ener = 0.0f;
690 0 : hPlcInfo->zp = L_frameTCX;
691 0 : hPlcInfo->recovery_gain = 0.0f;
692 0 : hPlcInfo->step_concealgain = 0.0f;
693 0 : hPlcInfo->concealment_method = TCX_NONTONAL;
694 0 : hPlcInfo->subframe = 0;
695 0 : hPlcInfo->nbLostCmpt = 0;
696 0 : hPlcInfo->seed = RANDOM_INITSEED;
697 :
698 0 : for ( i = 0; i < TCX_TONALITY_INIT_CNT; i++ )
699 : {
700 0 : hPlcInfo->TCX_Tonality[i] = 1;
701 : }
702 0 : for ( i = TCX_TONALITY_INIT_CNT; i < DEC_STATE_LEN; i++ )
703 : {
704 0 : hPlcInfo->TCX_Tonality[i] = 0;
705 : }
706 0 : for ( i = 0; i < MAX_POST_LEN; i++ )
707 : {
708 0 : hPlcInfo->Transient[i] = 1;
709 : }
710 :
711 0 : for ( i = 0; i < L_FRAME_MAX; i++ )
712 : {
713 0 : hPlcInfo->data_reci2[i] = 0;
714 : }
715 :
716 0 : return;
717 : }
718 :
719 :
720 : /*-------------------------------------------------------------------*
721 : * concealment_decode()
722 : *
723 : *
724 : *-------------------------------------------------------------------*/
725 :
726 0 : void concealment_decode(
727 : const int16_t core,
728 : float *invkoef,
729 : T_PLCInfo_HANDLE hPlcInfo )
730 : {
731 : int16_t i;
732 0 : int16_t *seed = &( hPlcInfo->seed );
733 : int16_t sign;
734 :
735 0 : if ( hPlcInfo->concealment_method == TCX_NONTONAL )
736 : {
737 0 : if ( core == TCX_20_CORE )
738 : {
739 : /* copy the data of the last frame */
740 0 : mvr2r( hPlcInfo->data_reci2, invkoef, hPlcInfo->L_frameTCX );
741 :
742 : /* sign randomization */
743 0 : for ( i = 0; i < hPlcInfo->L_frameTCX; i++ )
744 : {
745 : int16_t rnd;
746 0 : rnd = own_random( seed );
747 0 : sign = ( rnd >= 0 ) - ( rnd < 0 );
748 0 : invkoef[i] *= sign;
749 : }
750 : }
751 : }
752 :
753 0 : return;
754 : }
755 :
756 :
757 : /*-------------------------------------------------------------------*
758 : * concealment_update()
759 : *
760 : *
761 : *-------------------------------------------------------------------*/
762 :
763 0 : void concealment_update(
764 : const int16_t bfi,
765 : const int16_t core,
766 : const int16_t tonality,
767 : float *invkoef,
768 : T_PLCInfo_HANDLE hPlcInfo )
769 : {
770 0 : float *data_reci2 = hPlcInfo->data_reci2;
771 0 : int16_t subframe = hPlcInfo->subframe;
772 : int16_t i;
773 :
774 0 : if ( core == TCX_20_CORE )
775 : {
776 0 : set_state( hPlcInfo->Transient, core, MAX_POST_LEN );
777 :
778 0 : for ( i = 0; i < hPlcInfo->L_frameTCX; i++ )
779 : {
780 0 : data_reci2[i] = invkoef[i];
781 : }
782 :
783 0 : if ( !bfi )
784 : {
785 0 : set_state( hPlcInfo->TCX_Tonality, tonality, DEC_STATE_LEN );
786 : }
787 : }
788 : else
789 : {
790 0 : if ( subframe == 0 )
791 : {
792 0 : set_state( hPlcInfo->Transient, core, MAX_POST_LEN );
793 :
794 0 : if ( !bfi )
795 : {
796 0 : set_state( hPlcInfo->TCX_Tonality, tonality, DEC_STATE_LEN );
797 : }
798 : }
799 : /* don't store the second subframe during frameloss; in
800 : pitch_search(), low_freq_rate is derived on the last good
801 : TCX-10 spectrum */
802 0 : if ( !bfi || subframe == 0 )
803 : {
804 0 : float *ptr = data_reci2 + subframe;
805 0 : for ( i = 0; i < ( hPlcInfo->L_frameTCX >> 1 ); i++ )
806 : {
807 0 : ptr[i] = invkoef[i];
808 : }
809 : }
810 : }
811 0 : return;
812 : }
813 :
814 :
815 : /*-------------------------------------------------------------------*
816 : * concealment_update2()
817 : *
818 : *
819 : *-------------------------------------------------------------------*/
820 :
821 0 : void concealment_update2(
822 : const float *outx_new,
823 : T_PLCInfo_HANDLE hPlcInfo,
824 : const int16_t L_frameTCX )
825 : {
826 0 : hPlcInfo->zp = zero_pass( outx_new, L_frameTCX );
827 0 : hPlcInfo->ener = dotp( outx_new, outx_new, L_frameTCX ) / L_frameTCX;
828 0 : hPlcInfo->ener = 10 * (float) log10( hPlcInfo->ener + EPSILON );
829 :
830 0 : if ( hPlcInfo->zp < 100 && hPlcInfo->ener > 50 )
831 : {
832 0 : hPlcInfo->ener_mean = 0.98f * hPlcInfo->ener_mean + 0.02f * hPlcInfo->ener;
833 : }
834 :
835 0 : return;
836 : }
837 :
838 :
839 : /*-------------------------------------------------------------------*
840 : * concealment_signal_tuning()
841 : *
842 : *
843 : *-------------------------------------------------------------------*/
844 :
845 0 : void concealment_signal_tuning(
846 : Decoder_State *st,
847 : const int16_t bfi,
848 : float *outx_new,
849 : const int16_t past_core )
850 : {
851 0 : float voicing = 0;
852 0 : T_PLCInfo_HANDLE hPlcInfo = st->hPlcInfo;
853 0 : float *OverlapBuf = st->hTonalMDCTConc->secondLastPcmOut;
854 0 : float *outdata2 = st->hTonalMDCTConc->lastPcmOut;
855 :
856 0 : if ( bfi )
857 : {
858 0 : if ( st->enablePlcWaveadjust && hPlcInfo->concealment_method == TCX_NONTONAL )
859 : {
860 0 : if ( st->nbLostCmpt == 1 )
861 : {
862 0 : hPlcInfo->Pitch = pitch_search( outdata2, outx_new, st->hPlcInfo->L_frameTCX, &voicing, &hPlcInfo->zp, &hPlcInfo->ener, hPlcInfo->ener_mean, st->hPlcInfo->data_reci2, st->core );
863 :
864 0 : if ( hPlcInfo->Pitch ) /* waveform adjustment for the first lost frame */
865 : {
866 0 : hPlcInfo->Pitch = waveform_adj( hPlcInfo, OverlapBuf, outdata2, outx_new, st->hPlcInfo->L_frameTCX, voicing, st->core );
867 : }
868 : }
869 0 : else if ( st->nbLostCmpt < 5 ) /* waveform adjustment for the 2nd~4th lost frame */
870 : {
871 0 : waveform_adj2( hPlcInfo, OverlapBuf, outx_new, 0, st->nbLostCmpt, bfi );
872 : }
873 : }
874 0 : hPlcInfo->T_bfi = 1;
875 : }
876 : else
877 : {
878 0 : if ( st->prev_bfi && past_core != ACELP_CORE && st->last_total_brate >= HQ_48k && st->last_codec_mode == MODE2 )
879 : {
880 0 : if ( hPlcInfo->concealment_method == TCX_NONTONAL )
881 : {
882 0 : if ( hPlcInfo->nbLostCmpt < 4 ) /* smoothing of the concealed signal with the good signal */
883 : {
884 0 : waveform_adj2( hPlcInfo, OverlapBuf, outx_new, 0, hPlcInfo->nbLostCmpt + 1, bfi );
885 : }
886 : }
887 : }
888 : else
889 : {
890 0 : hPlcInfo->T_bfi = 0;
891 : }
892 : }
893 :
894 0 : return;
895 : }
|