LCOV - code coverage report
Current view: top level - media/libopus/silk - PLC.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 176 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #define NB_ATT 2
      37             : static const opus_int16 HARM_ATT_Q15[NB_ATT]              = { 32440, 31130 }; /* 0.99, 0.95 */
      38             : static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT]  = { 31130, 26214 }; /* 0.95, 0.8 */
      39             : static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
      40             : 
      41             : static 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             : 
      46             : static OPUS_INLINE void silk_PLC_conceal(
      47             :     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
      48             :     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
      49             :     opus_int16                          frame[],            /* O LPC residual signal    */
      50             :     int                                 arch                /* I  Run-time architecture */
      51             : );
      52             : 
      53             : 
      54           0 : void silk_PLC_Reset(
      55             :     silk_decoder_state                  *psDec              /* I/O Decoder state        */
      56             : )
      57             : {
      58           0 :     psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
      59           0 :     psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
      60           0 :     psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
      61           0 :     psDec->sPLC.subfr_length = 20;
      62           0 :     psDec->sPLC.nb_subfr = 2;
      63           0 : }
      64             : 
      65           0 : void 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              */
      69             :     opus_int                            lost,               /* I Loss flag              */
      70             :     int                                 arch                /* I Run-time architecture  */
      71             : )
      72             : {
      73             :     /* PLC control function */
      74           0 :     if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
      75           0 :         silk_PLC_Reset( psDec );
      76           0 :         psDec->sPLC.fs_kHz = psDec->fs_kHz;
      77             :     }
      78             : 
      79           0 :     if( lost ) {
      80             :         /****************************/
      81             :         /* Generate Signal          */
      82             :         /****************************/
      83           0 :         silk_PLC_conceal( psDec, psDecCtrl, frame, arch );
      84             : 
      85           0 :         psDec->lossCnt++;
      86             :     } else {
      87             :         /****************************/
      88             :         /* Update state             */
      89             :         /****************************/
      90           0 :         silk_PLC_update( psDec, psDecCtrl );
      91             :     }
      92           0 : }
      93             : 
      94             : /**************************************************/
      95             : /* Update state of PLC                            */
      96             : /**************************************************/
      97           0 : static 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           0 :     psPLC = &psDec->sPLC;
     107             : 
     108             :     /* Update parameters used in case of packet loss */
     109           0 :     psDec->prevSignalType = psDec->indices.signalType;
     110           0 :     LTP_Gain_Q14 = 0;
     111           0 :     if( psDec->indices.signalType == TYPE_VOICED ) {
     112             :         /* Find the parameters for the last subframe which contains a pitch pulse */
     113           0 :         for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
     114           0 :             if( j == psDec->nb_subfr ) {
     115           0 :                 break;
     116             :             }
     117           0 :             temp_LTP_Gain_Q14 = 0;
     118           0 :             for( i = 0; i < LTP_ORDER; i++ ) {
     119           0 :                 temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER  + i ];
     120             :             }
     121           0 :             if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
     122           0 :                 LTP_Gain_Q14 = temp_LTP_Gain_Q14;
     123           0 :                 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           0 :                 psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
     128             :             }
     129             :         }
     130             : 
     131           0 :         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
     132           0 :         psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
     133             : 
     134             :         /* Limit LT coefs */
     135           0 :         if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
     136             :             opus_int   scale_Q10;
     137             :             opus_int32 tmp;
     138             : 
     139           0 :             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
     140           0 :             scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
     141           0 :             for( i = 0; i < LTP_ORDER; i++ ) {
     142           0 :                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
     143             :             }
     144           0 :         } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
     145             :             opus_int   scale_Q14;
     146             :             opus_int32 tmp;
     147             : 
     148           0 :             tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
     149           0 :             scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
     150           0 :             for( i = 0; i < LTP_ORDER; i++ ) {
     151           0 :                 psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
     152             :             }
     153             :         }
     154             :     } else {
     155           0 :         psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
     156           0 :         silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
     157             :     }
     158             : 
     159             :     /* Save LPC coeficients */
     160           0 :     silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
     161           0 :     psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
     162             : 
     163             :     /* Save last two gains */
     164           0 :     silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
     165             : 
     166           0 :     psPLC->subfr_length = psDec->subfr_length;
     167           0 :     psPLC->nb_subfr = psDec->nb_subfr;
     168           0 : }
     169             : 
     170           0 : static 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           0 :     ALLOC( exc_buf, 2*subfr_length, opus_int16 );
     178             :     /* Find random noise component */
     179             :     /* Scale previous excitation signal */
     180           0 :     exc_buf_ptr = exc_buf;
     181           0 :     for( k = 0; k < 2; k++ ) {
     182           0 :         for( i = 0; i < subfr_length; i++ ) {
     183           0 :             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           0 :         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           0 :     silk_sum_sqr_shift( energy1, shift1, exc_buf,                  subfr_length );
     190           0 :     silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length );
     191             :     RESTORE_STACK;
     192           0 : }
     193             : 
     194           0 : static OPUS_INLINE void silk_PLC_conceal(
     195             :     silk_decoder_state                  *psDec,             /* I/O Decoder state        */
     196             :     silk_decoder_control                *psDecCtrl,         /* I/O Decoder control      */
     197             :     opus_int16                          frame[],            /* O LPC residual signal    */
     198             :     int                                 arch                /* I Run-time architecture  */
     199             : )
     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;
     207             :     opus_int16 *B_Q14;
     208             :     opus_int32 *sLPC_Q14_ptr;
     209             :     opus_int16 A_Q12[ MAX_LPC_ORDER ];
     210             : #ifdef SMALL_FOOTPRINT
     211             :     opus_int16 *sLTP;
     212             : #else
     213             :     VARDECL( opus_int16, sLTP );
     214             : #endif
     215             :     VARDECL( opus_int32, sLTP_Q14 );
     216           0 :     silk_PLC_struct *psPLC = &psDec->sPLC;
     217             :     opus_int32 prevGain_Q10[2];
     218             :     SAVE_STACK;
     219             : 
     220           0 :     ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
     221             : #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           0 :     ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
     226             : #endif
     227             : 
     228           0 :     prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
     229           0 :     prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
     230             : 
     231           0 :     if( psDec->first_frame_after_reset ) {
     232           0 :        silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
     233             :     }
     234             : 
     235           0 :     silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr);
     236             : 
     237           0 :     if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
     238             :         /* First sub-frame has lowest energy */
     239           0 :         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           0 :         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           0 :     B_Q14          = psPLC->LTPCoef_Q14;
     247           0 :     rand_scale_Q14 = psPLC->randScale_Q14;
     248             : 
     249             :     /* Set up attenuation gains */
     250           0 :     harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
     251           0 :     if( psDec->prevSignalType == TYPE_VOICED ) {
     252           0 :         rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[  silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
     253             :     } else {
     254           0 :         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           0 :     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           0 :     silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
     262             : 
     263             :     /* First Lost frame */
     264           0 :     if( psDec->lossCnt == 0 ) {
     265           0 :         rand_scale_Q14 = 1 << 14;
     266             : 
     267             :         /* Reduce random noise Gain for voiced frames */
     268           0 :         if( psDec->prevSignalType == TYPE_VOICED ) {
     269           0 :             for( i = 0; i < LTP_ORDER; i++ ) {
     270           0 :                 rand_scale_Q14 -= B_Q14[ i ];
     271             :             }
     272           0 :             rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
     273           0 :             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           0 :             invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch );
     279             : 
     280           0 :             down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
     281           0 :             down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
     282           0 :             down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
     283             : 
     284           0 :             rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
     285             :         }
     286             :     }
     287             : 
     288           0 :     rand_seed    = psPLC->rand_seed;
     289           0 :     lag          = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
     290           0 :     sLTP_buf_idx = psDec->ltp_mem_length;
     291             : 
     292             :     /* Rewhiten LTP state */
     293           0 :     idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
     294           0 :     silk_assert( idx > 0 );
     295           0 :     silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch );
     296             :     /* Scale LTP state */
     297           0 :     inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
     298           0 :     inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
     299           0 :     for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
     300           0 :         sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
     301             :     }
     302             : 
     303             :     /***************************/
     304             :     /* LTP synthesis filtering */
     305             :     /***************************/
     306           0 :     for( k = 0; k < psDec->nb_subfr; k++ ) {
     307             :         /* Set up pointer */
     308           0 :         pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
     309           0 :         for( i = 0; i < psDec->subfr_length; i++ ) {
     310             :             /* Unrolled loop */
     311             :             /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
     312           0 :             LTP_pred_Q12 = 2;
     313           0 :             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[  0 ], B_Q14[ 0 ] );
     314           0 :             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
     315           0 :             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
     316           0 :             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
     317           0 :             LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
     318           0 :             pred_lag_ptr++;
     319             : 
     320             :             /* Generate LPC excitation */
     321           0 :             rand_seed = silk_RAND( rand_seed );
     322           0 :             idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
     323           0 :             sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
     324           0 :             sLTP_buf_idx++;
     325             :         }
     326             : 
     327             :         /* Gradually reduce LTP gain */
     328           0 :         for( j = 0; j < LTP_ORDER; j++ ) {
     329           0 :             B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
     330             :         }
     331           0 :         if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) {
     332             :             /* Gradually reduce excitation gain */
     333           0 :             rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
     334             :         }
     335             : 
     336             :         /* Slowly increase pitch lag */
     337           0 :         psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
     338           0 :         psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
     339           0 :         lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
     340             :     }
     341             : 
     342             :     /***************************/
     343             :     /* LPC synthesis filtering */
     344             :     /***************************/
     345           0 :     sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
     346             : 
     347             :     /* Copy LPC state */
     348           0 :     silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
     349             : 
     350           0 :     silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
     351           0 :     for( i = 0; i < psDec->frame_length; i++ ) {
     352             :         /* partly unrolled */
     353             :         /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
     354           0 :         LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
     355           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
     356           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
     357           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
     358           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
     359           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
     360           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
     361           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
     362           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
     363           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
     364           0 :         LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
     365           0 :         for( j = 10; j < psDec->LPC_order; j++ ) {
     366           0 :             LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
     367             :         }
     368             : 
     369             :         /* Add prediction to LPC excitation */
     370           0 :         sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
     371             :                                             silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
     372             : 
     373             :         /* Scale with Gain */
     374           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 ) ) );
     375             :     }
     376             : 
     377             :     /* Save LPC state */
     378           0 :     silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
     379             : 
     380             :     /**************************************/
     381             :     /* Update states                      */
     382             :     /**************************************/
     383           0 :     psPLC->rand_seed     = rand_seed;
     384           0 :     psPLC->randScale_Q14 = rand_scale_Q14;
     385           0 :     for( i = 0; i < MAX_NB_SUBFR; i++ ) {
     386           0 :         psDecCtrl->pitchL[ i ] = lag;
     387             :     }
     388             :     RESTORE_STACK;
     389           0 : }
     390             : 
     391             : /* Glues concealed frames with new good received frames */
     392           0 : void silk_PLC_glue_frames(
     393             :     silk_decoder_state                  *psDec,             /* I/O decoder state        */
     394             :     opus_int16                          frame[],            /* I/O signal               */
     395             :     opus_int                            length              /* I length of signal       */
     396             : )
     397             : {
     398             :     opus_int   i, energy_shift;
     399             :     opus_int32 energy;
     400             :     silk_PLC_struct *psPLC;
     401           0 :     psPLC = &psDec->sPLC;
     402             : 
     403           0 :     if( psDec->lossCnt ) {
     404             :         /* Calculate energy in concealed residual */
     405           0 :         silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
     406             : 
     407           0 :         psPLC->last_frame_lost = 1;
     408             :     } else {
     409           0 :         if( psDec->sPLC.last_frame_lost ) {
     410             :             /* Calculate residual in decoded signal if last frame was lost */
     411           0 :             silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
     412             : 
     413             :             /* Normalize energies */
     414           0 :             if( energy_shift > psPLC->conc_energy_shift ) {
     415           0 :                 psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
     416           0 :             } else if( energy_shift < psPLC->conc_energy_shift ) {
     417           0 :                 energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
     418             :             }
     419             : 
     420             :             /* Fade in the energy difference */
     421           0 :             if( energy > psPLC->conc_energy ) {
     422             :                 opus_int32 frac_Q24, LZ;
     423             :                 opus_int32 gain_Q16, slope_Q16;
     424             : 
     425           0 :                 LZ = silk_CLZ32( psPLC->conc_energy );
     426           0 :                 LZ = LZ - 1;
     427           0 :                 psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
     428           0 :                 energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
     429             : 
     430           0 :                 frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
     431             : 
     432           0 :                 gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
     433           0 :                 slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
     434             :                 /* Make slope 4x steeper to avoid missing onsets after DTX */
     435           0 :                 slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
     436             : 
     437           0 :                 for( i = 0; i < length; i++ ) {
     438           0 :                     frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
     439           0 :                     gain_Q16 += slope_Q16;
     440           0 :                     if( gain_Q16 > (opus_int32)1 << 16 ) {
     441           0 :                         break;
     442             :                     }
     443             :                 }
     444             :             }
     445             :         }
     446           0 :         psPLC->last_frame_lost = 0;
     447             :     }
     448           0 : }

Generated by: LCOV version 1.13