Coverage Report

Created: 2026-09-14 08:00

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