Bug 1891710: part 2) Enable <Element-outerHTML.html> WPT for Trusted Types. r=smaug
[gecko.git] / media / libopus / silk / PLC.c
blobb35bf750a0a891198b2b8ace3d7ff253771b8613
1 /***********************************************************************
2 Copyright (c) 2006-2011, Skype Limited. All rights reserved.
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions
5 are met:
6 - Redistributions of source code must retain the above copyright notice,
7 this list of conditions and the following disclaimer.
8 - Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 - Neither the name of Internet Society, IETF or IETF Trust, nor the
12 names of specific contributors, may be used to endorse or promote
13 products derived from this software without specific prior written
14 permission.
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 POSSIBILITY OF SUCH DAMAGE.
26 ***********************************************************************/
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
32 #include "main.h"
33 #include "stack_alloc.h"
34 #include "PLC.h"
36 #ifdef ENABLE_DEEP_PLC
37 #include "lpcnet.h"
38 #endif
40 #define NB_ATT 2
41 static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */
42 static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */
43 static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
45 static OPUS_INLINE void silk_PLC_update(
46 silk_decoder_state *psDec, /* I/O Decoder state */
47 silk_decoder_control *psDecCtrl /* I/O Decoder control */
50 static OPUS_INLINE void silk_PLC_conceal(
51 silk_decoder_state *psDec, /* I/O Decoder state */
52 silk_decoder_control *psDecCtrl, /* I/O Decoder control */
53 opus_int16 frame[], /* O LPC residual signal */
54 #ifdef ENABLE_DEEP_PLC
55 LPCNetPLCState *lpcnet,
56 #endif
57 int arch /* I Run-time architecture */
61 void silk_PLC_Reset(
62 silk_decoder_state *psDec /* I/O Decoder state */
65 psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
66 psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
67 psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
68 psDec->sPLC.subfr_length = 20;
69 psDec->sPLC.nb_subfr = 2;
72 void silk_PLC(
73 silk_decoder_state *psDec, /* I/O Decoder state */
74 silk_decoder_control *psDecCtrl, /* I/O Decoder control */
75 opus_int16 frame[], /* I/O signal */
76 opus_int lost, /* I Loss flag */
77 #ifdef ENABLE_DEEP_PLC
78 LPCNetPLCState *lpcnet,
79 #endif
80 int arch /* I Run-time architecture */
83 /* PLC control function */
84 if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
85 silk_PLC_Reset( psDec );
86 psDec->sPLC.fs_kHz = psDec->fs_kHz;
89 if( lost ) {
90 /****************************/
91 /* Generate Signal */
92 /****************************/
93 silk_PLC_conceal( psDec, psDecCtrl, frame,
94 #ifdef ENABLE_DEEP_PLC
95 lpcnet,
96 #endif
97 arch );
99 psDec->lossCnt++;
100 } else {
101 /****************************/
102 /* Update state */
103 /****************************/
104 silk_PLC_update( psDec, psDecCtrl );
105 #ifdef ENABLE_DEEP_PLC
106 if ( lpcnet != NULL && psDec->sPLC.fs_kHz == 16 ) {
107 int k;
108 for( k = 0; k < psDec->nb_subfr; k += 2 ) {
109 lpcnet_plc_update( lpcnet, frame + k * psDec->subfr_length );
112 #endif
116 /**************************************************/
117 /* Update state of PLC */
118 /**************************************************/
119 static OPUS_INLINE void silk_PLC_update(
120 silk_decoder_state *psDec, /* I/O Decoder state */
121 silk_decoder_control *psDecCtrl /* I/O Decoder control */
124 opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
125 opus_int i, j;
126 silk_PLC_struct *psPLC;
128 psPLC = &psDec->sPLC;
130 /* Update parameters used in case of packet loss */
131 psDec->prevSignalType = psDec->indices.signalType;
132 LTP_Gain_Q14 = 0;
133 if( psDec->indices.signalType == TYPE_VOICED ) {
134 /* Find the parameters for the last subframe which contains a pitch pulse */
135 for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
136 if( j == psDec->nb_subfr ) {
137 break;
139 temp_LTP_Gain_Q14 = 0;
140 for( i = 0; i < LTP_ORDER; i++ ) {
141 temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ];
143 if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
144 LTP_Gain_Q14 = temp_LTP_Gain_Q14;
145 silk_memcpy( psPLC->LTPCoef_Q14,
146 &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
147 LTP_ORDER * sizeof( opus_int16 ) );
149 psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
153 silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
154 psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
156 /* Limit LT coefs */
157 if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
158 opus_int scale_Q10;
159 opus_int32 tmp;
161 tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
162 scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
163 for( i = 0; i < LTP_ORDER; i++ ) {
164 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
166 } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
167 opus_int scale_Q14;
168 opus_int32 tmp;
170 tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
171 scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
172 for( i = 0; i < LTP_ORDER; i++ ) {
173 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
176 } else {
177 psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
178 silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
181 /* Save LPC coeficients */
182 silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
183 psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
185 /* Save last two gains */
186 silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
188 psPLC->subfr_length = psDec->subfr_length;
189 psPLC->nb_subfr = psDec->nb_subfr;
192 static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2,
193 const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr)
195 int i, k;
196 VARDECL( opus_int16, exc_buf );
197 opus_int16 *exc_buf_ptr;
198 SAVE_STACK;
199 ALLOC( exc_buf, 2*subfr_length, opus_int16 );
200 /* Find random noise component */
201 /* Scale previous excitation signal */
202 exc_buf_ptr = exc_buf;
203 for( k = 0; k < 2; k++ ) {
204 for( i = 0; i < subfr_length; i++ ) {
205 exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT(
206 silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) );
208 exc_buf_ptr += subfr_length;
210 /* Find the subframe with lowest energy of the last two and use that as random noise generator */
211 silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length );
212 silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length );
213 RESTORE_STACK;
216 static OPUS_INLINE void silk_PLC_conceal(
217 silk_decoder_state *psDec, /* I/O Decoder state */
218 silk_decoder_control *psDecCtrl, /* I/O Decoder control */
219 opus_int16 frame[], /* O LPC residual signal */
220 #ifdef ENABLE_DEEP_PLC
221 LPCNetPLCState *lpcnet,
222 #endif
223 int arch /* I Run-time architecture */
226 opus_int i, j, k;
227 opus_int lag, idx, sLTP_buf_idx, shift1, shift2;
228 opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
229 opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
230 opus_int32 LPC_pred_Q10, LTP_pred_Q12;
231 opus_int16 rand_scale_Q14;
232 opus_int16 *B_Q14;
233 opus_int32 *sLPC_Q14_ptr;
234 opus_int16 A_Q12[ MAX_LPC_ORDER ];
235 #ifdef SMALL_FOOTPRINT
236 opus_int16 *sLTP;
237 #else
238 VARDECL( opus_int16, sLTP );
239 #endif
240 VARDECL( opus_int32, sLTP_Q14 );
241 silk_PLC_struct *psPLC = &psDec->sPLC;
242 opus_int32 prevGain_Q10[2];
243 SAVE_STACK;
245 ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
246 #ifdef SMALL_FOOTPRINT
247 /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */
248 sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length;
249 #else
250 ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
251 #endif
253 prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
254 prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
256 if( psDec->first_frame_after_reset ) {
257 silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
260 silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr);
262 if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
263 /* First sub-frame has lowest energy */
264 rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
265 } else {
266 /* Second sub-frame has lowest energy */
267 rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
270 /* Set up Gain to random noise component */
271 B_Q14 = psPLC->LTPCoef_Q14;
272 rand_scale_Q14 = psPLC->randScale_Q14;
274 /* Set up attenuation gains */
275 harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
276 if( psDec->prevSignalType == TYPE_VOICED ) {
277 rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
278 } else {
279 rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
282 /* LPC concealment. Apply BWE to previous LPC */
283 silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
285 /* Preload LPC coeficients to array on stack. Gives small performance gain */
286 silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
288 /* First Lost frame */
289 if( psDec->lossCnt == 0 ) {
290 rand_scale_Q14 = 1 << 14;
292 /* Reduce random noise Gain for voiced frames */
293 if( psDec->prevSignalType == TYPE_VOICED ) {
294 for( i = 0; i < LTP_ORDER; i++ ) {
295 rand_scale_Q14 -= B_Q14[ i ];
297 rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
298 rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
299 } else {
300 /* Reduce random noise for unvoiced frames with high LPC gain */
301 opus_int32 invGain_Q30, down_scale_Q30;
303 invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch );
305 down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
306 down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
307 down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
309 rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
313 rand_seed = psPLC->rand_seed;
314 lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
315 sLTP_buf_idx = psDec->ltp_mem_length;
317 /* Rewhiten LTP state */
318 idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
319 celt_assert( idx > 0 );
320 silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch );
321 /* Scale LTP state */
322 inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
323 inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
324 for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
325 sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
328 /***************************/
329 /* LTP synthesis filtering */
330 /***************************/
331 for( k = 0; k < psDec->nb_subfr; k++ ) {
332 /* Set up pointer */
333 pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
334 for( i = 0; i < psDec->subfr_length; i++ ) {
335 /* Unrolled loop */
336 /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
337 LTP_pred_Q12 = 2;
338 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] );
339 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
340 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
341 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
342 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
343 pred_lag_ptr++;
345 /* Generate LPC excitation */
346 rand_seed = silk_RAND( rand_seed );
347 idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
348 sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
349 sLTP_buf_idx++;
352 /* Gradually reduce LTP gain */
353 for( j = 0; j < LTP_ORDER; j++ ) {
354 B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
356 /* Gradually reduce excitation gain */
357 rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
359 /* Slowly increase pitch lag */
360 psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
361 psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
362 lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
365 /***************************/
366 /* LPC synthesis filtering */
367 /***************************/
368 sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
370 /* Copy LPC state */
371 silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
373 celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
374 for( i = 0; i < psDec->frame_length; i++ ) {
375 /* partly unrolled */
376 /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
377 LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
378 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
379 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
380 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
381 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
382 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
383 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
384 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
385 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
386 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
387 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
388 for( j = 10; j < psDec->LPC_order; j++ ) {
389 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
392 /* Add prediction to LPC excitation */
393 sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
394 silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
396 /* Scale with Gain */
397 frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
399 #ifdef ENABLE_DEEP_PLC
400 if ( lpcnet != NULL && lpcnet->loaded && psDec->sPLC.fs_kHz == 16 ) {
401 int run_deep_plc = psDec->sPLC.enable_deep_plc || lpcnet->fec_fill_pos != 0;
402 if( run_deep_plc ) {
403 for( k = 0; k < psDec->nb_subfr; k += 2 ) {
404 lpcnet_plc_conceal( lpcnet, frame + k * psDec->subfr_length );
406 /* We *should* be able to copy only from psDec->frame_length-MAX_LPC_ORDER, i.e. the last MAX_LPC_ORDER samples. */
407 for( i = 0; i < psDec->frame_length; i++ ) {
408 sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = (int)floor(.5 + frame[ i ] * (float)(1 << 24) / prevGain_Q10[ 1 ] );
410 } else {
411 for( k = 0; k < psDec->nb_subfr; k += 2 ) {
412 lpcnet_plc_update( lpcnet, frame + k * psDec->subfr_length );
416 #endif
418 /* Save LPC state */
419 silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
421 /**************************************/
422 /* Update states */
423 /**************************************/
424 psPLC->rand_seed = rand_seed;
425 psPLC->randScale_Q14 = rand_scale_Q14;
426 for( i = 0; i < MAX_NB_SUBFR; i++ ) {
427 psDecCtrl->pitchL[ i ] = lag;
429 RESTORE_STACK;
432 /* Glues concealed frames with new good received frames */
433 void silk_PLC_glue_frames(
434 silk_decoder_state *psDec, /* I/O decoder state */
435 opus_int16 frame[], /* I/O signal */
436 opus_int length /* I length of signal */
439 opus_int i, energy_shift;
440 opus_int32 energy;
441 silk_PLC_struct *psPLC;
442 psPLC = &psDec->sPLC;
444 if( psDec->lossCnt ) {
445 /* Calculate energy in concealed residual */
446 silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
448 psPLC->last_frame_lost = 1;
449 } else {
450 if( psDec->sPLC.last_frame_lost ) {
451 /* Calculate residual in decoded signal if last frame was lost */
452 silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
454 /* Normalize energies */
455 if( energy_shift > psPLC->conc_energy_shift ) {
456 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
457 } else if( energy_shift < psPLC->conc_energy_shift ) {
458 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
461 /* Fade in the energy difference */
462 if( energy > psPLC->conc_energy ) {
463 opus_int32 frac_Q24, LZ;
464 opus_int32 gain_Q16, slope_Q16;
466 LZ = silk_CLZ32( psPLC->conc_energy );
467 LZ = LZ - 1;
468 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
469 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
471 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
473 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
474 slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
475 /* Make slope 4x steeper to avoid missing onsets after DTX */
476 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
477 #ifdef ENABLE_DEEP_PLC
478 if ( psDec->sPLC.fs_kHz != 16 )
479 #endif
481 for( i = 0; i < length; i++ ) {
482 frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
483 gain_Q16 += slope_Q16;
484 if( gain_Q16 > (opus_int32)1 << 16 ) {
485 break;
491 psPLC->last_frame_lost = 0;