media/libopus/silk/CNG.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libopus/silk/CNG.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,172 @@
     1.4 +/***********************************************************************
     1.5 +Copyright (c) 2006-2011, Skype Limited. All rights reserved.
     1.6 +Redistribution and use in source and binary forms, with or without
     1.7 +modification, are permitted provided that the following conditions
     1.8 +are met:
     1.9 +- Redistributions of source code must retain the above copyright notice,
    1.10 +this list of conditions and the following disclaimer.
    1.11 +- Redistributions in binary form must reproduce the above copyright
    1.12 +notice, this list of conditions and the following disclaimer in the
    1.13 +documentation and/or other materials provided with the distribution.
    1.14 +- Neither the name of Internet Society, IETF or IETF Trust, nor the
    1.15 +names of specific contributors, may be used to endorse or promote
    1.16 +products derived from this software without specific prior written
    1.17 +permission.
    1.18 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    1.19 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    1.20 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.21 +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    1.22 +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    1.23 +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    1.24 +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    1.25 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    1.26 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1.27 +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    1.28 +POSSIBILITY OF SUCH DAMAGE.
    1.29 +***********************************************************************/
    1.30 +
    1.31 +#ifdef HAVE_CONFIG_H
    1.32 +#include "config.h"
    1.33 +#endif
    1.34 +
    1.35 +#include "main.h"
    1.36 +#include "stack_alloc.h"
    1.37 +
    1.38 +/* Generates excitation for CNG LPC synthesis */
    1.39 +static OPUS_INLINE void silk_CNG_exc(
    1.40 +    opus_int32                       residual_Q10[],     /* O    CNG residual signal Q10                     */
    1.41 +    opus_int32                       exc_buf_Q14[],      /* I    Random samples buffer Q10                   */
    1.42 +    opus_int32                       Gain_Q16,           /* I    Gain to apply                               */
    1.43 +    opus_int                         length,             /* I    Length                                      */
    1.44 +    opus_int32                       *rand_seed          /* I/O  Seed to random index generator              */
    1.45 +)
    1.46 +{
    1.47 +    opus_int32 seed;
    1.48 +    opus_int   i, idx, exc_mask;
    1.49 +
    1.50 +    exc_mask = CNG_BUF_MASK_MAX;
    1.51 +    while( exc_mask > length ) {
    1.52 +        exc_mask = silk_RSHIFT( exc_mask, 1 );
    1.53 +    }
    1.54 +
    1.55 +    seed = *rand_seed;
    1.56 +    for( i = 0; i < length; i++ ) {
    1.57 +        seed = silk_RAND( seed );
    1.58 +        idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask );
    1.59 +        silk_assert( idx >= 0 );
    1.60 +        silk_assert( idx <= CNG_BUF_MASK_MAX );
    1.61 +        residual_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) );
    1.62 +    }
    1.63 +    *rand_seed = seed;
    1.64 +}
    1.65 +
    1.66 +void silk_CNG_Reset(
    1.67 +    silk_decoder_state          *psDec                          /* I/O  Decoder state                               */
    1.68 +)
    1.69 +{
    1.70 +    opus_int i, NLSF_step_Q15, NLSF_acc_Q15;
    1.71 +
    1.72 +    NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 );
    1.73 +    NLSF_acc_Q15 = 0;
    1.74 +    for( i = 0; i < psDec->LPC_order; i++ ) {
    1.75 +        NLSF_acc_Q15 += NLSF_step_Q15;
    1.76 +        psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15;
    1.77 +    }
    1.78 +    psDec->sCNG.CNG_smth_Gain_Q16 = 0;
    1.79 +    psDec->sCNG.rand_seed = 3176576;
    1.80 +}
    1.81 +
    1.82 +/* Updates CNG estimate, and applies the CNG when packet was lost   */
    1.83 +void silk_CNG(
    1.84 +    silk_decoder_state          *psDec,                         /* I/O  Decoder state                               */
    1.85 +    silk_decoder_control        *psDecCtrl,                     /* I/O  Decoder control                             */
    1.86 +    opus_int16                  frame[],                        /* I/O  Signal                                      */
    1.87 +    opus_int                    length                          /* I    Length of residual                          */
    1.88 +)
    1.89 +{
    1.90 +    opus_int   i, subfr;
    1.91 +    opus_int32 sum_Q6, max_Gain_Q16;
    1.92 +    opus_int16 A_Q12[ MAX_LPC_ORDER ];
    1.93 +    silk_CNG_struct *psCNG = &psDec->sCNG;
    1.94 +    SAVE_STACK;
    1.95 +
    1.96 +    if( psDec->fs_kHz != psCNG->fs_kHz ) {
    1.97 +        /* Reset state */
    1.98 +        silk_CNG_Reset( psDec );
    1.99 +
   1.100 +        psCNG->fs_kHz = psDec->fs_kHz;
   1.101 +    }
   1.102 +    if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) {
   1.103 +        /* Update CNG parameters */
   1.104 +
   1.105 +        /* Smoothing of LSF's  */
   1.106 +        for( i = 0; i < psDec->LPC_order; i++ ) {
   1.107 +            psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 );
   1.108 +        }
   1.109 +        /* Find the subframe with the highest gain */
   1.110 +        max_Gain_Q16 = 0;
   1.111 +        subfr        = 0;
   1.112 +        for( i = 0; i < psDec->nb_subfr; i++ ) {
   1.113 +            if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) {
   1.114 +                max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ];
   1.115 +                subfr        = i;
   1.116 +            }
   1.117 +        }
   1.118 +        /* Update CNG excitation buffer with excitation from this subframe */
   1.119 +        silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) );
   1.120 +        silk_memcpy(   psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) );
   1.121 +
   1.122 +        /* Smooth gains */
   1.123 +        for( i = 0; i < psDec->nb_subfr; i++ ) {
   1.124 +            psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 );
   1.125 +        }
   1.126 +    }
   1.127 +
   1.128 +    /* Add CNG when packet is lost or during DTX */
   1.129 +    if( psDec->lossCnt ) {
   1.130 +        VARDECL( opus_int32, CNG_sig_Q10 );
   1.131 +
   1.132 +        ALLOC( CNG_sig_Q10, length + MAX_LPC_ORDER, opus_int32 );
   1.133 +
   1.134 +        /* Generate CNG excitation */
   1.135 +        silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed );
   1.136 +
   1.137 +        /* Convert CNG NLSF to filter representation */
   1.138 +        silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
   1.139 +
   1.140 +        /* Generate CNG signal, by synthesis filtering */
   1.141 +        silk_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
   1.142 +        for( i = 0; i < length; i++ ) {
   1.143 +            silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
   1.144 +            /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
   1.145 +            sum_Q6 = silk_RSHIFT( psDec->LPC_order, 1 );
   1.146 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  1 ], A_Q12[ 0 ] );
   1.147 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  2 ], A_Q12[ 1 ] );
   1.148 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  3 ], A_Q12[ 2 ] );
   1.149 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  4 ], A_Q12[ 3 ] );
   1.150 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  5 ], A_Q12[ 4 ] );
   1.151 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  6 ], A_Q12[ 5 ] );
   1.152 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  7 ], A_Q12[ 6 ] );
   1.153 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  8 ], A_Q12[ 7 ] );
   1.154 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i -  9 ], A_Q12[ 8 ] );
   1.155 +            sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
   1.156 +            if( psDec->LPC_order == 16 ) {
   1.157 +                sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] );
   1.158 +                sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] );
   1.159 +                sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] );
   1.160 +                sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] );
   1.161 +                sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] );
   1.162 +                sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] );
   1.163 +            }
   1.164 +
   1.165 +            /* Update states */
   1.166 +            CNG_sig_Q10[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 );
   1.167 +
   1.168 +            frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( sum_Q6, 6 ) );
   1.169 +        }
   1.170 +        silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
   1.171 +    } else {
   1.172 +        silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order *  sizeof( opus_int32 ) );
   1.173 +    }
   1.174 +    RESTORE_STACK;
   1.175 +}

mercurial