Coverage Report

Created: 2024-09-06 07:53

/src/opus/silk/PLC.c
Line
Count
Source (jump to first uncovered line)
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
***********************************************************************/
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
#ifdef ENABLE_DEEP_PLC
37
#include "lpcnet.h"
38
#endif
39
40
0
#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 */
44
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      */
48
);
49
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 */
58
);
59
60
61
void silk_PLC_Reset(
62
    silk_decoder_state                  *psDec              /* I/O Decoder state        */
63
)
64
0
{
65
0
    psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
66
0
    psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
67
0
    psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
68
0
    psDec->sPLC.subfr_length = 20;
69
0
    psDec->sPLC.nb_subfr = 2;
70
0
}
71
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  */
81
)
82
0
{
83
    /* PLC control function */
84
0
    if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
85
0
        silk_PLC_Reset( psDec );
86
0
        psDec->sPLC.fs_kHz = psDec->fs_kHz;
87
0
    }
88
89
0
    if( lost ) {
90
        /****************************/
91
        /* Generate Signal          */
92
        /****************************/
93
0
        silk_PLC_conceal( psDec, psDecCtrl, frame,
94
#ifdef ENABLE_DEEP_PLC
95
            lpcnet,
96
#endif
97
0
            arch );
98
99
0
        psDec->lossCnt++;
100
0
    } else {
101
        /****************************/
102
        /* Update state             */
103
        /****************************/
104
0
        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 );
110
            }
111
        }
112
#endif
113
0
    }
114
0
}
115
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      */
122
)
123
0
{
124
0
    opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
125
0
    opus_int   i, j;
126
0
    silk_PLC_struct *psPLC;
127
128
0
    psPLC = &psDec->sPLC;
129
130
    /* Update parameters used in case of packet loss */
131
0
    psDec->prevSignalType = psDec->indices.signalType;
132
0
    LTP_Gain_Q14 = 0;
133
0
    if( psDec->indices.signalType == TYPE_VOICED ) {
134
        /* Find the parameters for the last subframe which contains a pitch pulse */
135
0
        for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
136
0
            if( j == psDec->nb_subfr ) {
137
0
                break;
138
0
            }
139
0
            temp_LTP_Gain_Q14 = 0;
140
0
            for( i = 0; i < LTP_ORDER; i++ ) {
141
0
                temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER  + i ];
142
0
            }
143
0
            if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
144
0
                LTP_Gain_Q14 = temp_LTP_Gain_Q14;
145
0
                silk_memcpy( psPLC->LTPCoef_Q14,
146
0
                    &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
147
0
                    LTP_ORDER * sizeof( opus_int16 ) );
148
149
0
                psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
150
0
            }
151
0
        }
152
153
0
        silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
154
0
        psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
155
156
        /* Limit LT coefs */
157
0
        if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
158
0
            opus_int   scale_Q10;
159
0
            opus_int32 tmp;
160
161
0
            tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
162
0
            scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
163
0
            for( i = 0; i < LTP_ORDER; i++ ) {
164
0
                psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
165
0
            }
166
0
        } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
167
0
            opus_int   scale_Q14;
168
0
            opus_int32 tmp;
169
170
0
            tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
171
0
            scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
172
0
            for( i = 0; i < LTP_ORDER; i++ ) {
173
0
                psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
174
0
            }
175
0
        }
176
0
    } else {
177
0
        psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
178
0
        silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
179
0
    }
180
181
    /* Save LPC coeficients */
182
0
    silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
183
0
    psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
184
185
    /* Save last two gains */
186
0
    silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
187
188
0
    psPLC->subfr_length = psDec->subfr_length;
189
0
    psPLC->nb_subfr = psDec->nb_subfr;
190
0
}
191
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)
194
0
{
195
0
    int i, k;
196
0
    VARDECL( opus_int16, exc_buf );
197
0
    opus_int16 *exc_buf_ptr;
198
0
    SAVE_STACK;
199
0
    ALLOC( exc_buf, 2*subfr_length, opus_int16 );
200
    /* Find random noise component */
201
    /* Scale previous excitation signal */
202
0
    exc_buf_ptr = exc_buf;
203
0
    for( k = 0; k < 2; k++ ) {
204
0
        for( i = 0; i < subfr_length; i++ ) {
205
0
            exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT(
206
0
                silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) );
207
0
        }
208
0
        exc_buf_ptr += subfr_length;
209
0
    }
210
    /* Find the subframe with lowest energy of the last two and use that as random noise generator */
211
0
    silk_sum_sqr_shift( energy1, shift1, exc_buf,                  subfr_length );
212
0
    silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length );
213
0
    RESTORE_STACK;
214
0
}
215
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  */
224
)
225
0
{
226
0
    opus_int   i, j, k;
227
0
    opus_int   lag, idx, sLTP_buf_idx, shift1, shift2;
228
0
    opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
229
0
    opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
230
0
    opus_int32 LPC_pred_Q10, LTP_pred_Q12;
231
0
    opus_int16 rand_scale_Q14;
232
0
    opus_int16 *B_Q14;
233
0
    opus_int32 *sLPC_Q14_ptr;
234
0
    opus_int16 A_Q12[ MAX_LPC_ORDER ];
235
#ifdef SMALL_FOOTPRINT
236
    opus_int16 *sLTP;
237
#else
238
0
    VARDECL( opus_int16, sLTP );
239
0
#endif
240
0
    VARDECL( opus_int32, sLTP_Q14 );
241
0
    silk_PLC_struct *psPLC = &psDec->sPLC;
242
0
    opus_int32 prevGain_Q10[2];
243
0
    SAVE_STACK;
244
245
0
    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
0
    ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
251
0
#endif
252
253
0
    prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
254
0
    prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
255
256
0
    if( psDec->first_frame_after_reset ) {
257
0
       silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
258
0
    }
259
260
0
    silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr);
261
262
0
    if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
263
        /* First sub-frame has lowest energy */
264
0
        rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
265
0
    } else {
266
        /* Second sub-frame has lowest energy */
267
0
        rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
268
0
    }
269
270
    /* Set up Gain to random noise component */
271
0
    B_Q14          = psPLC->LTPCoef_Q14;
272
0
    rand_scale_Q14 = psPLC->randScale_Q14;
273
274
    /* Set up attenuation gains */
275
0
    harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
276
0
    if( psDec->prevSignalType == TYPE_VOICED ) {
277
0
        rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
278
0
    } else {
279
0
        rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
280
0
    }
281
282
    /* LPC concealment. Apply BWE to previous LPC */
283
0
    silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
284
285
    /* Preload LPC coeficients to array on stack. Gives small performance gain */
286
0
    silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
287
288
    /* First Lost frame */
289
0
    if( psDec->lossCnt == 0 ) {
290
0
        rand_scale_Q14 = 1 << 14;
291
292
        /* Reduce random noise Gain for voiced frames */
293
0
        if( psDec->prevSignalType == TYPE_VOICED ) {
294
0
            for( i = 0; i < LTP_ORDER; i++ ) {
295
0
                rand_scale_Q14 -= B_Q14[ i ];
296
0
            }
297
0
            rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
298
0
            rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
299
0
        } else {
300
            /* Reduce random noise for unvoiced frames with high LPC gain */
301
0
            opus_int32 invGain_Q30, down_scale_Q30;
302
303
0
            invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch );
304
305
0
            down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
306
0
            down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
307
0
            down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
308
309
0
            rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
310
0
        }
311
0
    }
312
313
0
    rand_seed    = psPLC->rand_seed;
314
0
    lag          = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
315
0
    sLTP_buf_idx = psDec->ltp_mem_length;
316
317
    /* Rewhiten LTP state */
318
0
    idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
319
0
    celt_assert( idx > 0 );
320
0
    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
0
    inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
323
0
    inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
324
0
    for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
325
0
        sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
326
0
    }
327
328
    /***************************/
329
    /* LTP synthesis filtering */
330
    /***************************/
331
0
    for( k = 0; k < psDec->nb_subfr; k++ ) {
332
        /* Set up pointer */
333
0
        pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
334
0
        for( i = 0; i < psDec->subfr_length; i++ ) {
335
            /* Unrolled loop */
336
            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
337
0
            LTP_pred_Q12 = 2;
338
0
            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[  0 ], B_Q14[ 0 ] );
339
0
            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
340
0
            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
341
0
            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
342
0
            LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
343
0
            pred_lag_ptr++;
344
345
            /* Generate LPC excitation */
346
0
            rand_seed = silk_RAND( rand_seed );
347
0
            idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
348
0
            sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
349
0
            sLTP_buf_idx++;
350
0
        }
351
352
        /* Gradually reduce LTP gain */
353
0
        for( j = 0; j < LTP_ORDER; j++ ) {
354
0
            B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
355
0
        }
356
        /* Gradually reduce excitation gain */
357
0
        rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
358
359
        /* Slowly increase pitch lag */
360
0
        psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
361
0
        psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
362
0
        lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
363
0
    }
364
365
    /***************************/
366
    /* LPC synthesis filtering */
367
    /***************************/
368
0
    sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
369
370
    /* Copy LPC state */
371
0
    silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
372
373
0
    celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
374
0
    for( i = 0; i < psDec->frame_length; i++ ) {
375
        /* partly unrolled */
376
        /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
377
0
        LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
378
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
379
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
380
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
381
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
382
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
383
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
384
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
385
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
386
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
387
0
        LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
388
0
        for( j = 10; j < psDec->LPC_order; j++ ) {
389
0
            LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
390
0
        }
391
392
        /* Add prediction to LPC excitation */
393
0
        sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
394
0
                                            silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
395
396
        /* Scale with Gain */
397
0
        frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
398
0
    }
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 );
405
            }
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 ] );
409
            }
410
        } else {
411
          for( k = 0; k < psDec->nb_subfr; k += 2 ) {
412
              lpcnet_plc_update( lpcnet, frame + k * psDec->subfr_length );
413
          }
414
        }
415
    }
416
#endif
417
418
    /* Save LPC state */
419
0
    silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
420
421
    /**************************************/
422
    /* Update states                      */
423
    /**************************************/
424
0
    psPLC->rand_seed     = rand_seed;
425
0
    psPLC->randScale_Q14 = rand_scale_Q14;
426
0
    for( i = 0; i < MAX_NB_SUBFR; i++ ) {
427
0
        psDecCtrl->pitchL[ i ] = lag;
428
0
    }
429
0
    RESTORE_STACK;
430
0
}
431
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       */
437
)
438
0
{
439
0
    opus_int   i, energy_shift;
440
0
    opus_int32 energy;
441
0
    silk_PLC_struct *psPLC;
442
0
    psPLC = &psDec->sPLC;
443
444
0
    if( psDec->lossCnt ) {
445
        /* Calculate energy in concealed residual */
446
0
        silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
447
448
0
        psPLC->last_frame_lost = 1;
449
0
    } else {
450
0
        if( psDec->sPLC.last_frame_lost ) {
451
            /* Calculate residual in decoded signal if last frame was lost */
452
0
            silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
453
454
            /* Normalize energies */
455
0
            if( energy_shift > psPLC->conc_energy_shift ) {
456
0
                psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
457
0
            } else if( energy_shift < psPLC->conc_energy_shift ) {
458
0
                energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
459
0
            }
460
461
            /* Fade in the energy difference */
462
0
            if( energy > psPLC->conc_energy ) {
463
0
                opus_int32 frac_Q24, LZ;
464
0
                opus_int32 gain_Q16, slope_Q16;
465
466
0
                LZ = silk_CLZ32( psPLC->conc_energy );
467
0
                LZ = LZ - 1;
468
0
                psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
469
0
                energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
470
471
0
                frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
472
473
0
                gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
474
0
                slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
475
                /* Make slope 4x steeper to avoid missing onsets after DTX */
476
0
                slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
477
#ifdef ENABLE_DEEP_PLC
478
                if ( psDec->sPLC.fs_kHz != 16 )
479
#endif
480
0
                {
481
0
                    for( i = 0; i < length; i++ ) {
482
0
                        frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
483
0
                        gain_Q16 += slope_Q16;
484
0
                        if( gain_Q16 > (opus_int32)1 << 16 ) {
485
0
                            break;
486
0
                        }
487
0
                    }
488
0
                }
489
0
            }
490
0
        }
491
0
        psPLC->last_frame_lost = 0;
492
0
    }
493
0
}