Eliminate some unreachable cases from the cwrs code and fixup the
[opus.git] / silk / silk_PLC.c
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, (subject to the limitations in the disclaimer below)
5 are permitted provided that the following conditions 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 Skype Limited, nor the names of specific
12 contributors, may be used to endorse or promote products derived from
13 this software without specific prior written permission.
14 NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
15 BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
16 CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
17 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 ***********************************************************************/
27
28 #include "silk_main.h"
29 #include "silk_PLC.h"
30
31 #define NB_ATT 2
32 static const opus_int16 HARM_ATT_Q15[NB_ATT]              = { 32440, 31130 }; /* 0.99, 0.95 */
33 static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT]  = { 31130, 26214 }; /* 0.95, 0.8 */
34 static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
35
36 void silk_PLC_Reset(
37     silk_decoder_state      *psDec              /* I/O Decoder state        */
38 )
39 {
40     psDec->sPLC.pitchL_Q8 = SKP_RSHIFT( psDec->frame_length, 1 );
41 }
42
43 void silk_PLC(
44     silk_decoder_state          *psDec,             /* I Decoder state          */
45     silk_decoder_control        *psDecCtrl,         /* I Decoder control        */
46     opus_int16                   signal[],           /* O Concealed signal       */
47     opus_int                     length,             /* I length of residual     */
48     opus_int                     lost                /* I Loss flag              */
49 )
50 {
51     /* PLC control function */
52     if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
53         silk_PLC_Reset( psDec );
54         psDec->sPLC.fs_kHz = psDec->fs_kHz;
55     }
56
57     if( lost ) {
58         /****************************/
59         /* Generate Signal          */
60         /****************************/
61         silk_PLC_conceal( psDec, psDecCtrl, signal, length );
62
63         psDec->lossCnt++;
64     } else {
65         /****************************/
66         /* Update state             */
67         /****************************/
68         silk_PLC_update( psDec, psDecCtrl, signal, length );
69     }
70 }
71
72 /**************************************************/
73 /* Update state of PLC                            */
74 /**************************************************/
75 void silk_PLC_update(
76     silk_decoder_state          *psDec,             /* (I/O) Decoder state          */
77     silk_decoder_control        *psDecCtrl,         /* (I/O) Decoder control        */
78     opus_int16                   signal[],
79     opus_int                     length
80 )
81 {
82     opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
83     opus_int   i, j;
84     silk_PLC_struct *psPLC;
85
86     psPLC = &psDec->sPLC;
87
88     /* Update parameters used in case of packet loss */
89     psDec->prevSignalType = psDec->indices.signalType;
90     LTP_Gain_Q14 = 0;
91     if( psDec->indices.signalType == TYPE_VOICED ) {
92         /* Find the parameters for the last subframe which contains a pitch pulse */
93         for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
94             if( j == psDec->nb_subfr ){
95                 break;
96             }
97             temp_LTP_Gain_Q14 = 0;
98             for( i = 0; i < LTP_ORDER; i++ ) {
99                 temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER  + i ];
100             }
101             if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
102                 LTP_Gain_Q14 = temp_LTP_Gain_Q14;
103                 SKP_memcpy( psPLC->LTPCoef_Q14,
104                     &psDecCtrl->LTPCoef_Q14[ SKP_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
105                     LTP_ORDER * sizeof( opus_int16 ) );
106
107                 psPLC->pitchL_Q8 = SKP_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
108             }
109         }
110
111 #if USE_SINGLE_TAP
112         SKP_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
113         psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
114 #endif
115
116         /* Limit LT coefs */
117         if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
118             opus_int   scale_Q10;
119             opus_int32 tmp;
120
121             tmp = SKP_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
122             scale_Q10 = SKP_DIV32( tmp, SKP_max( LTP_Gain_Q14, 1 ) );
123             for( i = 0; i < LTP_ORDER; i++ ) {
124                 psPLC->LTPCoef_Q14[ i ] = SKP_RSHIFT( SKP_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
125             }
126         } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
127             opus_int   scale_Q14;
128             opus_int32 tmp;
129
130             tmp = SKP_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
131             scale_Q14 = SKP_DIV32( tmp, SKP_max( LTP_Gain_Q14, 1 ) );
132             for( i = 0; i < LTP_ORDER; i++ ) {
133                 psPLC->LTPCoef_Q14[ i ] = SKP_RSHIFT( SKP_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
134             }
135         }
136     } else {
137         psPLC->pitchL_Q8 = SKP_LSHIFT( SKP_SMULBB( psDec->fs_kHz, 18 ), 8 );
138         SKP_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
139     }
140
141     /* Save LPC coeficients */
142     SKP_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
143     psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
144
145     /* Save Gains */
146     SKP_memcpy( psPLC->prevGain_Q16, psDecCtrl->Gains_Q16, psDec->nb_subfr * sizeof( opus_int32 ) );
147 }
148
149 void silk_PLC_conceal(
150     silk_decoder_state          *psDec,             /* I/O Decoder state */
151     silk_decoder_control        *psDecCtrl,         /* I/O Decoder control */
152     opus_int16                   signal[],           /* O concealed signal */
153     opus_int                     length              /* I length of residual */
154 )
155 {
156     opus_int   i, j, k;
157     opus_int16 *B_Q14, exc_buf[ MAX_FRAME_LENGTH ], *exc_buf_ptr;
158     opus_int16 rand_scale_Q14, A_Q12_tmp[ MAX_LPC_ORDER ];
159     opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15;
160     opus_int   lag, idx, sLTP_buf_idx, shift1, shift2;
161     opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
162     opus_int32 sig_Q10[ MAX_FRAME_LENGTH ], *sig_Q10_ptr, LPC_exc_Q10, LPC_pred_Q10,  LTP_pred_Q14;
163     silk_PLC_struct *psPLC;
164     psPLC = &psDec->sPLC;
165
166     /* Update LTP buffer */
167     SKP_memmove( psDec->sLTP_Q16, &psDec->sLTP_Q16[ psDec->frame_length ], psDec->ltp_mem_length * sizeof( opus_int32 ) );
168
169     /* LPC concealment. Apply BWE to previous LPC */
170     silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
171
172     /* Find random noise component */
173     /* Scale previous excitation signal */
174     exc_buf_ptr = exc_buf;
175     /* FIXME: JMV: Is this the right fix? */
176     for (i=0;i<MAX_FRAME_LENGTH;i++)
177         exc_buf[i] = 0;
178     for( k = ( psDec->nb_subfr >> 1 ); k < psDec->nb_subfr; k++ ) {
179         for( i = 0; i < psDec->subfr_length; i++ ) {
180             exc_buf_ptr[ i ] = ( opus_int16 )SKP_RSHIFT(
181                 SKP_SMULWW( psDec->exc_Q10[ i + k * psDec->subfr_length ], psPLC->prevGain_Q16[ k ] ), 10 );
182         }
183         exc_buf_ptr += psDec->subfr_length;
184     }
185     /* Find the subframe with lowest energy of the last two and use that as random noise generator */
186     silk_sum_sqr_shift( &energy1, &shift1, exc_buf,                         psDec->subfr_length );
187     silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psDec->subfr_length ], psDec->subfr_length );
188
189     if( SKP_RSHIFT( energy1, shift2 ) < SKP_RSHIFT( energy2, shift1 ) ) {
190         /* First sub-frame has lowest energy */
191         rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, 3 * psDec->subfr_length - RAND_BUF_SIZE ) ];
192     } else {
193         /* Second sub-frame has lowest energy */
194         rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, psDec->frame_length - RAND_BUF_SIZE ) ];
195     }
196
197     /* Setup Gain to random noise component */
198     B_Q14          = psPLC->LTPCoef_Q14;
199     rand_scale_Q14 = psPLC->randScale_Q14;
200
201     /* Setup attenuation gains */
202     harm_Gain_Q15 = HARM_ATT_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ];
203     if( psDec->prevSignalType == TYPE_VOICED ) {
204         rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ];
205     } else {
206         rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ];
207     }
208
209     /* First Lost frame */
210     if( psDec->lossCnt == 0 ) {
211         rand_scale_Q14 = 1 << 14;
212
213         /* Reduce random noise Gain for voiced frames */
214         if( psDec->prevSignalType == TYPE_VOICED ) {
215             for( i = 0; i < LTP_ORDER; i++ ) {
216                 rand_scale_Q14 -= B_Q14[ i ];
217             }
218             rand_scale_Q14 = SKP_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
219             rand_scale_Q14 = ( opus_int16 )SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
220         } else {
221             /* Reduce random noise for unvoiced frames with high LPC gain */
222             opus_int32 invGain_Q30, down_scale_Q30;
223
224             silk_LPC_inverse_pred_gain( &invGain_Q30, psPLC->prevLPC_Q12, psDec->LPC_order );
225
226             down_scale_Q30 = SKP_min_32( SKP_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
227             down_scale_Q30 = SKP_max_32( SKP_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
228             down_scale_Q30 = SKP_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
229
230             rand_Gain_Q15 = SKP_RSHIFT( SKP_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
231         }
232     }
233
234     rand_seed    = psPLC->rand_seed;
235     lag          = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
236     sLTP_buf_idx = psDec->ltp_mem_length;
237
238     /***************************/
239     /* LTP synthesis filtering */
240     /***************************/
241     sig_Q10_ptr = sig_Q10;
242     for( k = 0; k < psDec->nb_subfr; k++ ) {
243         /* Setup pointer */
244         pred_lag_ptr = &psDec->sLTP_Q16[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
245         for( i = 0; i < psDec->subfr_length; i++ ) {
246             rand_seed = SKP_RAND( rand_seed );
247             idx = SKP_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
248
249             /* Unrolled loop */
250             LTP_pred_Q14 = SKP_SMULWB(               pred_lag_ptr[  0 ], B_Q14[ 0 ] );
251             LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
252             LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
253             LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
254             LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
255             pred_lag_ptr++;
256
257             /* Generate LPC residual */
258             LPC_exc_Q10 = SKP_LSHIFT( SKP_SMULWB( rand_ptr[ idx ], rand_scale_Q14 ), 2 ); /* Random noise part */
259             LPC_exc_Q10 = SKP_ADD32( LPC_exc_Q10, SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) );  /* Harmonic part */
260
261             /* Update states */
262             psDec->sLTP_Q16[ sLTP_buf_idx ] = SKP_LSHIFT( LPC_exc_Q10, 6 );
263             sLTP_buf_idx++;
264
265             /* Save LPC residual */
266             sig_Q10_ptr[ i ] = LPC_exc_Q10;
267         }
268         sig_Q10_ptr += psDec->subfr_length;
269         /* Gradually reduce LTP gain */
270         for( j = 0; j < LTP_ORDER; j++ ) {
271             B_Q14[ j ] = SKP_RSHIFT( SKP_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
272         }
273         /* Gradually reduce excitation gain */
274         rand_scale_Q14 = SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
275
276         /* Slowly increase pitch lag */
277         psPLC->pitchL_Q8 += SKP_SMULWB( psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
278         psPLC->pitchL_Q8 = SKP_min_32( psPLC->pitchL_Q8, SKP_LSHIFT( SKP_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
279         lag = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
280     }
281
282     /***************************/
283     /* LPC synthesis filtering */
284     /***************************/
285     sig_Q10_ptr = sig_Q10;
286     /* Preload LPC coeficients to array on stack. Gives small performance gain */
287     SKP_memcpy( A_Q12_tmp, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
288     SKP_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
289     for( k = 0; k < psDec->nb_subfr; k++ ) {
290         for( i = 0; i < psDec->subfr_length; i++ ){
291             /* partly unrolled */
292             LPC_pred_Q10 = SKP_SMULWB(               psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  1 ], A_Q12_tmp[ 0 ] );
293             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  2 ], A_Q12_tmp[ 1 ] );
294             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  3 ], A_Q12_tmp[ 2 ] );
295             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  4 ], A_Q12_tmp[ 3 ] );
296             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  5 ], A_Q12_tmp[ 4 ] );
297             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  6 ], A_Q12_tmp[ 5 ] );
298             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  7 ], A_Q12_tmp[ 6 ] );
299             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  8 ], A_Q12_tmp[ 7 ] );
300             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i -  9 ], A_Q12_tmp[ 8 ] );
301             LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] );
302
303             for( j = 10; j < psDec->LPC_order; j++ ) {
304                 LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - j - 1 ], A_Q12_tmp[ j ] );
305             }
306
307             /* Add prediction to LPC residual */
308             sig_Q10_ptr[ i ] = SKP_ADD32( sig_Q10_ptr[ i ], LPC_pred_Q10 );
309
310             /* Update states */
311             psDec->sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT( sig_Q10_ptr[ i ], 4 );
312         }
313         sig_Q10_ptr += psDec->subfr_length;
314         /* Update LPC filter state */
315         SKP_memcpy( psDec->sLPC_Q14, &psDec->sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
316     }
317
318     /* Scale with Gain */
319     for( i = 0; i < psDec->frame_length; i++ ) {
320         signal[ i ] = ( opus_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( sig_Q10[ i ], psPLC->prevGain_Q16[ psDec->nb_subfr - 1 ] ), 10 ) );
321     }
322
323     /**************************************/
324     /* Update states                      */
325     /**************************************/
326     psPLC->rand_seed     = rand_seed;
327     psPLC->randScale_Q14 = rand_scale_Q14;
328     for( i = 0; i < MAX_NB_SUBFR; i++ ) {
329         psDecCtrl->pitchL[ i ] = lag;
330     }
331 }
332
333 /* Glues concealed frames with new good recieved frames             */
334 void silk_PLC_glue_frames(
335     silk_decoder_state          *psDec,             /* I/O decoder state    */
336     silk_decoder_control        *psDecCtrl,         /* I/O Decoder control  */
337     opus_int16                   signal[],           /* I/O signal           */
338     opus_int                     length              /* I length of residual */
339 )
340 {
341     opus_int   i, energy_shift;
342     opus_int32 energy;
343     silk_PLC_struct *psPLC;
344     psPLC = &psDec->sPLC;
345
346     if( psDec->lossCnt ) {
347         /* Calculate energy in concealed residual */
348         silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, signal, length );
349
350         psPLC->last_frame_lost = 1;
351     } else {
352         if( psDec->sPLC.last_frame_lost ) {
353             /* Calculate residual in decoded signal if last frame was lost */
354             silk_sum_sqr_shift( &energy, &energy_shift, signal, length );
355
356             /* Normalize energies */
357             if( energy_shift > psPLC->conc_energy_shift ) {
358                 psPLC->conc_energy = SKP_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
359             } else if( energy_shift < psPLC->conc_energy_shift ) {
360                 energy = SKP_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
361             }
362
363             /* Fade in the energy difference */
364             if( energy > psPLC->conc_energy ) {
365                 opus_int32 frac_Q24, LZ;
366                 opus_int32 gain_Q16, slope_Q16;
367
368                 LZ = silk_CLZ32( psPLC->conc_energy );
369                 LZ = LZ - 1;
370                 psPLC->conc_energy = SKP_LSHIFT( psPLC->conc_energy, LZ );
371                 energy = SKP_RSHIFT( energy, SKP_max_32( 24 - LZ, 0 ) );
372
373                 frac_Q24 = SKP_DIV32( psPLC->conc_energy, SKP_max( energy, 1 ) );
374
375                 gain_Q16 = SKP_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
376                 slope_Q16 = SKP_DIV32_16( ( 1 << 16 ) - gain_Q16, length );
377                 /* Make slope 4x steeper to avoid missing onsets after DTX */
378                 slope_Q16 = SKP_LSHIFT( slope_Q16, 2 );
379
380                 for( i = 0; i < length; i++ ) {
381                     signal[ i ] = SKP_SMULWB( gain_Q16, signal[ i ] );
382                     gain_Q16 += slope_Q16;
383                     if( gain_Q16 > 1 << 16 ) {
384                         break;
385                     }
386                 }
387             }
388         }
389         psPLC->last_frame_lost = 0;
390     }
391 }