blob: 34a94bc313e1206d802f4f7ffeb40b2314510a00 [file] [log] [blame]
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -08001/***********************************************************************
2Copyright (c) 2006-2011, Skype Limited. All rights reserved.
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions
5are met:
6- Redistributions of source code must retain the above copyright notice,
7this list of conditions and the following disclaimer.
8- Redistributions in binary form must reproduce the above copyright
9notice, this list of conditions and the following disclaimer in the
10documentation and/or other materials provided with the distribution.
11- Neither the name of Internet Society, IETF or IETF Trust, nor the
12names of specific contributors, may be used to endorse or promote
13products derived from this software without specific prior written
14permission.
15THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25POSSIBILITY OF SUCH DAMAGE.
26***********************************************************************/
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "main.h"
33#include "stack_alloc.h"
34#include "PLC.h"
35
36#define NB_ATT 2
37static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */
38static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */
39static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
40
41static OPUS_INLINE void silk_PLC_update(
42 silk_decoder_state *psDec, /* I/O Decoder state */
43 silk_decoder_control *psDecCtrl /* I/O Decoder control */
44);
45
46static OPUS_INLINE void silk_PLC_conceal(
47 silk_decoder_state *psDec, /* I/O Decoder state */
48 silk_decoder_control *psDecCtrl, /* I/O Decoder control */
flimc91ee5b2016-01-26 14:33:44 +010049 opus_int16 frame[], /* O LPC residual signal */
50 int arch /* I Run-time architecture */
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -080051);
52
53
54void silk_PLC_Reset(
55 silk_decoder_state *psDec /* I/O Decoder state */
56)
57{
58 psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
59 psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
60 psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
61 psDec->sPLC.subfr_length = 20;
62 psDec->sPLC.nb_subfr = 2;
63}
64
65void silk_PLC(
66 silk_decoder_state *psDec, /* I/O Decoder state */
67 silk_decoder_control *psDecCtrl, /* I/O Decoder control */
68 opus_int16 frame[], /* I/O signal */
flimc91ee5b2016-01-26 14:33:44 +010069 opus_int lost, /* I Loss flag */
70 int arch /* I Run-time architecture */
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -080071)
72{
73 /* PLC control function */
74 if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
75 silk_PLC_Reset( psDec );
76 psDec->sPLC.fs_kHz = psDec->fs_kHz;
77 }
78
79 if( lost ) {
80 /****************************/
81 /* Generate Signal */
82 /****************************/
flimc91ee5b2016-01-26 14:33:44 +010083 silk_PLC_conceal( psDec, psDecCtrl, frame, arch );
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -080084
85 psDec->lossCnt++;
86 } else {
87 /****************************/
88 /* Update state */
89 /****************************/
90 silk_PLC_update( psDec, psDecCtrl );
91 }
92}
93
94/**************************************************/
95/* Update state of PLC */
96/**************************************************/
97static OPUS_INLINE void silk_PLC_update(
98 silk_decoder_state *psDec, /* I/O Decoder state */
99 silk_decoder_control *psDecCtrl /* I/O Decoder control */
100)
101{
102 opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
103 opus_int i, j;
104 silk_PLC_struct *psPLC;
105
106 psPLC = &psDec->sPLC;
107
108 /* Update parameters used in case of packet loss */
109 psDec->prevSignalType = psDec->indices.signalType;
110 LTP_Gain_Q14 = 0;
111 if( psDec->indices.signalType == TYPE_VOICED ) {
112 /* Find the parameters for the last subframe which contains a pitch pulse */
113 for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
114 if( j == psDec->nb_subfr ) {
115 break;
116 }
117 temp_LTP_Gain_Q14 = 0;
118 for( i = 0; i < LTP_ORDER; i++ ) {
119 temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ];
120 }
121 if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
122 LTP_Gain_Q14 = temp_LTP_Gain_Q14;
123 silk_memcpy( psPLC->LTPCoef_Q14,
124 &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
125 LTP_ORDER * sizeof( opus_int16 ) );
126
127 psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
128 }
129 }
130
131 silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
132 psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
133
134 /* Limit LT coefs */
135 if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
136 opus_int scale_Q10;
137 opus_int32 tmp;
138
139 tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
140 scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
141 for( i = 0; i < LTP_ORDER; i++ ) {
142 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
143 }
144 } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
145 opus_int scale_Q14;
146 opus_int32 tmp;
147
148 tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
149 scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
150 for( i = 0; i < LTP_ORDER; i++ ) {
151 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
152 }
153 }
154 } else {
155 psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
156 silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
157 }
158
159 /* Save LPC coeficients */
160 silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
161 psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
162
163 /* Save last two gains */
164 silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
165
166 psPLC->subfr_length = psDec->subfr_length;
167 psPLC->nb_subfr = psDec->nb_subfr;
168}
169
flimc91ee5b2016-01-26 14:33:44 +0100170static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2,
171 const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr)
172{
173 int i, k;
174 VARDECL( opus_int16, exc_buf );
175 opus_int16 *exc_buf_ptr;
176 SAVE_STACK;
177 ALLOC( exc_buf, 2*subfr_length, opus_int16 );
178 /* Find random noise component */
179 /* Scale previous excitation signal */
180 exc_buf_ptr = exc_buf;
181 for( k = 0; k < 2; k++ ) {
182 for( i = 0; i < subfr_length; i++ ) {
183 exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT(
184 silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) );
185 }
186 exc_buf_ptr += subfr_length;
187 }
188 /* Find the subframe with lowest energy of the last two and use that as random noise generator */
189 silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length );
190 silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length );
191 RESTORE_STACK;
192}
193
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800194static OPUS_INLINE void silk_PLC_conceal(
195 silk_decoder_state *psDec, /* I/O Decoder state */
196 silk_decoder_control *psDecCtrl, /* I/O Decoder control */
flimc91ee5b2016-01-26 14:33:44 +0100197 opus_int16 frame[], /* O LPC residual signal */
198 int arch /* I Run-time architecture */
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800199)
200{
201 opus_int i, j, k;
202 opus_int lag, idx, sLTP_buf_idx, shift1, shift2;
203 opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
204 opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
205 opus_int32 LPC_pred_Q10, LTP_pred_Q12;
206 opus_int16 rand_scale_Q14;
flimc91ee5b2016-01-26 14:33:44 +0100207 opus_int16 *B_Q14;
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800208 opus_int32 *sLPC_Q14_ptr;
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800209 opus_int16 A_Q12[ MAX_LPC_ORDER ];
flimc91ee5b2016-01-26 14:33:44 +0100210#ifdef SMALL_FOOTPRINT
211 opus_int16 *sLTP;
212#else
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800213 VARDECL( opus_int16, sLTP );
flimc91ee5b2016-01-26 14:33:44 +0100214#endif
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800215 VARDECL( opus_int32, sLTP_Q14 );
216 silk_PLC_struct *psPLC = &psDec->sPLC;
217 opus_int32 prevGain_Q10[2];
218 SAVE_STACK;
219
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800220 ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
flimc91ee5b2016-01-26 14:33:44 +0100221#ifdef SMALL_FOOTPRINT
222 /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */
223 sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length;
224#else
225 ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
226#endif
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800227
228 prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
229 prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
230
231 if( psDec->first_frame_after_reset ) {
232 silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
233 }
234
flimc91ee5b2016-01-26 14:33:44 +0100235 silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr);
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800236
237 if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
238 /* First sub-frame has lowest energy */
239 rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
240 } else {
241 /* Second sub-frame has lowest energy */
242 rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
243 }
244
245 /* Set up Gain to random noise component */
246 B_Q14 = psPLC->LTPCoef_Q14;
247 rand_scale_Q14 = psPLC->randScale_Q14;
248
249 /* Set up attenuation gains */
250 harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
251 if( psDec->prevSignalType == TYPE_VOICED ) {
252 rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
253 } else {
254 rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
255 }
256
257 /* LPC concealment. Apply BWE to previous LPC */
258 silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
259
260 /* Preload LPC coeficients to array on stack. Gives small performance gain */
261 silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
262
263 /* First Lost frame */
264 if( psDec->lossCnt == 0 ) {
265 rand_scale_Q14 = 1 << 14;
266
267 /* Reduce random noise Gain for voiced frames */
268 if( psDec->prevSignalType == TYPE_VOICED ) {
269 for( i = 0; i < LTP_ORDER; i++ ) {
270 rand_scale_Q14 -= B_Q14[ i ];
271 }
272 rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
273 rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
274 } else {
275 /* Reduce random noise for unvoiced frames with high LPC gain */
276 opus_int32 invGain_Q30, down_scale_Q30;
277
278 invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order );
279
280 down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
281 down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
282 down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
283
284 rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
285 }
286 }
287
288 rand_seed = psPLC->rand_seed;
289 lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
290 sLTP_buf_idx = psDec->ltp_mem_length;
291
292 /* Rewhiten LTP state */
293 idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
294 silk_assert( idx > 0 );
flimc91ee5b2016-01-26 14:33:44 +0100295 silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch );
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800296 /* Scale LTP state */
297 inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
298 inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
299 for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
300 sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
301 }
302
303 /***************************/
304 /* LTP synthesis filtering */
305 /***************************/
306 for( k = 0; k < psDec->nb_subfr; k++ ) {
307 /* Set up pointer */
308 pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
309 for( i = 0; i < psDec->subfr_length; i++ ) {
310 /* Unrolled loop */
311 /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
312 LTP_pred_Q12 = 2;
313 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] );
314 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
315 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
316 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
317 LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
318 pred_lag_ptr++;
319
320 /* Generate LPC excitation */
321 rand_seed = silk_RAND( rand_seed );
322 idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
323 sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
324 sLTP_buf_idx++;
325 }
326
327 /* Gradually reduce LTP gain */
328 for( j = 0; j < LTP_ORDER; j++ ) {
329 B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
330 }
331 /* Gradually reduce excitation gain */
332 rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
333
334 /* Slowly increase pitch lag */
335 psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
336 psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
337 lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
338 }
339
340 /***************************/
341 /* LPC synthesis filtering */
342 /***************************/
343 sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
344
345 /* Copy LPC state */
346 silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
347
348 silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
349 for( i = 0; i < psDec->frame_length; i++ ) {
350 /* partly unrolled */
351 /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
352 LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
353 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
354 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
355 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
356 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
357 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
358 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
359 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
360 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
361 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
362 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
363 for( j = 10; j < psDec->LPC_order; j++ ) {
364 LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
365 }
366
367 /* Add prediction to LPC excitation */
368 sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
369
370 /* Scale with Gain */
371 frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
372 }
373
374 /* Save LPC state */
375 silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
376
377 /**************************************/
378 /* Update states */
379 /**************************************/
380 psPLC->rand_seed = rand_seed;
381 psPLC->randScale_Q14 = rand_scale_Q14;
382 for( i = 0; i < MAX_NB_SUBFR; i++ ) {
383 psDecCtrl->pitchL[ i ] = lag;
384 }
385 RESTORE_STACK;
386}
387
388/* Glues concealed frames with new good received frames */
389void silk_PLC_glue_frames(
390 silk_decoder_state *psDec, /* I/O decoder state */
391 opus_int16 frame[], /* I/O signal */
392 opus_int length /* I length of signal */
393)
394{
395 opus_int i, energy_shift;
396 opus_int32 energy;
397 silk_PLC_struct *psPLC;
398 psPLC = &psDec->sPLC;
399
400 if( psDec->lossCnt ) {
401 /* Calculate energy in concealed residual */
402 silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
403
404 psPLC->last_frame_lost = 1;
405 } else {
406 if( psDec->sPLC.last_frame_lost ) {
407 /* Calculate residual in decoded signal if last frame was lost */
408 silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
409
410 /* Normalize energies */
411 if( energy_shift > psPLC->conc_energy_shift ) {
412 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
413 } else if( energy_shift < psPLC->conc_energy_shift ) {
414 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
415 }
416
417 /* Fade in the energy difference */
418 if( energy > psPLC->conc_energy ) {
419 opus_int32 frac_Q24, LZ;
420 opus_int32 gain_Q16, slope_Q16;
421
422 LZ = silk_CLZ32( psPLC->conc_energy );
423 LZ = LZ - 1;
424 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
425 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
426
427 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
428
429 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
430 slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
431 /* Make slope 4x steeper to avoid missing onsets after DTX */
432 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
433
434 for( i = 0; i < length; i++ ) {
435 frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
436 gain_Q16 += slope_Q16;
437 if( gain_Q16 > (opus_int32)1 << 16 ) {
438 break;
439 }
440 }
441 }
442 }
443 psPLC->last_frame_lost = 0;
444 }
445}