/* Gains scalar dequantization, uniform on log scale */
void SKP_Silk_gains_dequant(
    SKP_int32                       gain_Q16[ MAX_NB_SUBFR ],   /* O    quantized gains                         */
    const SKP_int8                  ind[ MAX_NB_SUBFR ],        /* I    gain indices                            */
    SKP_int8                        *prev_ind,                  /* I/O  last index in previous frame            */
    const SKP_int                   conditional,                /* I    first gain is delta coded if 1          */
    const SKP_int                   nb_subfr                    /* I    number of subframes                     */
)
{
    SKP_int   k, ind_tmp, double_step_size_threshold;

    for( k = 0; k < nb_subfr; k++ ) {
        if( k == 0 && conditional == 0 ) {
            *prev_ind = ind[ k ];
        } else {
            /* Delta index */
            ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT;

            /* Accumulate deltas */
            double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
            if( ind_tmp > double_step_size_threshold ) {
                *prev_ind += SKP_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold;
            } else {
                *prev_ind += ind_tmp;
            }
        }

        /* Convert to linear scale and scale */
        gain_Q16[ k ] = SKP_Silk_log2lin( SKP_min_32( SKP_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
    }
}
/* Gain scalar quantization with hysteresis, uniform on log scale */
void SKP_Silk_gains_quant(
    SKP_int8                        ind[ MAX_NB_SUBFR ],        /* O    gain indices                            */
    SKP_int32                       gain_Q16[ MAX_NB_SUBFR ],   /* I/O  gains (quantized out)                   */
    SKP_int8                        *prev_ind,                  /* I/O  last index in previous frame            */
    const SKP_int                   conditional,                /* I    first gain is delta coded if 1          */
    const SKP_int                   nb_subfr                    /* I    number of subframes                     */
)
{
    SKP_int k, double_step_size_threshold;

    for( k = 0; k < nb_subfr; k++ ) {
        /* Add half of previous quantization error, convert to log scale, scale, floor() */
        ind[ k ] = SKP_SMULWB( SCALE_Q16, SKP_Silk_lin2log( gain_Q16[ k ] ) - OFFSET );

        /* Round towards previous quantized gain (hysteresis) */
        if( ind[ k ] < *prev_ind ) {
            ind[ k ]++;
        }
        ind[ k ] = SKP_max_int( ind[ k ], 0 );

        /* Compute delta indices and limit */
        if( k == 0 && conditional == 0 ) {
            /* Full index */
            ind[ k ] = SKP_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 );
            *prev_ind = ind[ k ];
        } else {
            /* Delta index */
            ind[ k ] = ind[ k ] - *prev_ind;

            /* Double the quantization step size for large gain increases, so that the max gain level can be reached */
            double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
            if( ind[ k ] > double_step_size_threshold ) {
                ind[ k ] = double_step_size_threshold + SKP_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 );
            }

            ind[ k ] = SKP_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT );

            /* Accumulate deltas */
            if( ind[ k ] > double_step_size_threshold ) {
                *prev_ind += SKP_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold;
            } else {
                *prev_ind += ind[ k ];
            }

            /* Shift to make non-negative */
            ind[ k ] -= MIN_DELTA_GAIN_QUANT;
        }

        /* Convert to linear scale and scale */
        gain_Q16[ k ] = SKP_Silk_log2lin( SKP_min_32( SKP_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
    }
}
/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
void SKP_Silk_HP_variable_cutoff_FIX(
    SKP_Silk_encoder_state_FIX      *psEnc,             /* I/O  Encoder state FIX                           */
    SKP_Silk_encoder_control_FIX    *psEncCtrl,         /* I/O  Encoder control FIX                         */
    SKP_int16                       *out,               /* O    high-pass filtered output signal            */
    const SKP_int16                 *in                 /* I    input signal                                */
)
{
    SKP_int   quality_Q15;
    SKP_int32 B_Q28[ 3 ], A_Q28[ 2 ];
    SKP_int32 Fc_Q19, r_Q28, r_Q22;
    SKP_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7;

    /*********************************************/
    /* Estimate Low End of Pitch Frequency Range */
    /*********************************************/
    if( psEnc->sCmn.prev_sigtype == SIG_TYPE_VOICED ) {
        /* difference, in log domain */
        pitch_freq_Hz_Q16 = SKP_DIV32_16( SKP_LSHIFT( SKP_MUL( psEnc->sCmn.fs_kHz, 1000 ), 16 ), psEnc->sCmn.prevLag );
        pitch_freq_log_Q7 = SKP_Silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); //0x70

        /* adjustment based on quality */
        quality_Q15 = psEncCtrl->input_quality_bands_Q15[ 0 ];
        pitch_freq_log_Q7 = SKP_SUB32( pitch_freq_log_Q7, SKP_SMULWB( SKP_SMULWB( SKP_LSHIFT( quality_Q15, 2 ), quality_Q15 ), 
            pitch_freq_log_Q7 - SKP_LOG2_VARIABLE_HP_MIN_FREQ_Q7 ) );
        pitch_freq_log_Q7 = SKP_ADD32( pitch_freq_log_Q7, SKP_RSHIFT( SKP_FIX_CONST( 0.6, 15 ) - quality_Q15, 9 ) );

        //delta_freq = pitch_freq_log - psEnc->variable_HP_smth1;
        delta_freq_Q7 = pitch_freq_log_Q7 - SKP_RSHIFT( psEnc->variable_HP_smth1_Q15, 8 );
        if( delta_freq_Q7 < 0 ) {
            /* less smoothing for decreasing pitch frequency, to track something close to the minimum */
            delta_freq_Q7 = SKP_MUL( delta_freq_Q7, 3 );
        }

        /* limit delta, to reduce impact of outliers */
        delta_freq_Q7 = SKP_LIMIT_32( delta_freq_Q7, -SKP_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SKP_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) );

        /* update smoother */
        psEnc->variable_HP_smth1_Q15 = SKP_SMLAWB( psEnc->variable_HP_smth1_Q15, 
            SKP_MUL( SKP_LSHIFT( psEnc->speech_activity_Q8, 1 ), delta_freq_Q7 ), SKP_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) );
    }
    /* second smoother */
    psEnc->variable_HP_smth2_Q15 = SKP_SMLAWB( psEnc->variable_HP_smth2_Q15, 
        psEnc->variable_HP_smth1_Q15 - psEnc->variable_HP_smth2_Q15, SKP_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) );

    /* convert from log scale to Hertz */
    psEncCtrl->pitch_freq_low_Hz = SKP_Silk_log2lin( SKP_RSHIFT( psEnc->variable_HP_smth2_Q15, 8 ) );

    /* limit frequency range */
    psEncCtrl->pitch_freq_low_Hz = SKP_LIMIT_32( psEncCtrl->pitch_freq_low_Hz, 
        SKP_FIX_CONST( VARIABLE_HP_MIN_FREQ, 0 ), SKP_FIX_CONST( VARIABLE_HP_MAX_FREQ, 0 ) );

    /********************************/
    /* Compute Filter Coefficients  */
    /********************************/
    /* compute cut-off frequency, in radians */
    //Fc_num   = (SKP_float)( 0.45f * 2.0f * 3.14159265359 * psEncCtrl->pitch_freq_low_Hz );
    //Fc_denom = (SKP_float)( 1e3f * psEnc->sCmn.fs_kHz );
    SKP_assert( psEncCtrl->pitch_freq_low_Hz <= SKP_int32_MAX / SKP_RADIANS_CONSTANT_Q19 );
    Fc_Q19 = SKP_DIV32_16( SKP_SMULBB( SKP_RADIANS_CONSTANT_Q19, psEncCtrl->pitch_freq_low_Hz ), psEnc->sCmn.fs_kHz ); // range: 3704 - 27787, 11-15 bits
    SKP_assert( Fc_Q19 >=  3704 );
    SKP_assert( Fc_Q19 <= 27787 );

    r_Q28 = SKP_FIX_CONST( 1.0, 28 ) - SKP_MUL( SKP_FIX_CONST( 0.92, 9 ), Fc_Q19 );
    SKP_assert( r_Q28 >= 255347779 );
    SKP_assert( r_Q28 <= 266690872 );

    /* b = r * [ 1; -2; 1 ]; */
    /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */
    B_Q28[ 0 ] = r_Q28;
    B_Q28[ 1 ] = SKP_LSHIFT( -r_Q28, 1 );
    B_Q28[ 2 ] = r_Q28;
    
    // -r * ( 2 - Fc * Fc );
    r_Q22  = SKP_RSHIFT( r_Q28, 6 );
    A_Q28[ 0 ] = SKP_SMULWW( r_Q22, SKP_SMULWW( Fc_Q19, Fc_Q19 ) - SKP_FIX_CONST( 2.0,  22 ) );
    A_Q28[ 1 ] = SKP_SMULWW( r_Q22, r_Q22 );

    /********************************/
    /* High-Pass Filter             */
    /********************************/
    SKP_Silk_biquad_alt( in, B_Q28, A_Q28, psEnc->sCmn.In_HP_State, out, psEnc->sCmn.frame_length );
}
        /* Convert to monic warped prediction coefficients and limit absolute values */
        limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SKP_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );

        /* Convert from Q24 to Q13 and store in int16 */
        for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
            psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) );
            psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) );
        }
    }

    /*****************/
    /* Gain tweaking */
    /*****************/
    /* Increase gains during low speech activity and put lower limit on gains */
    gain_mult_Q16 = SKP_Silk_log2lin( -SKP_SMLAWB( -SKP_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7,                            SKP_FIX_CONST( 0.16, 16 ) ) );
    gain_add_Q16  = SKP_Silk_log2lin(  SKP_SMLAWB(  SKP_FIX_CONST( 16.0, 7 ), SKP_FIX_CONST( NOISE_FLOOR_dB, 7 ),       SKP_FIX_CONST( 0.16, 16 ) ) );
    tmp32         = SKP_Silk_log2lin(  SKP_SMLAWB(  SKP_FIX_CONST( 16.0, 7 ), SKP_FIX_CONST( RELATIVE_MIN_GAIN_dB, 7 ), SKP_FIX_CONST( 0.16, 16 ) ) );
    tmp32 = SKP_SMULWW( psEnc->avgGain_Q16, tmp32 );
    gain_add_Q16 = SKP_ADD_SAT32( gain_add_Q16, tmp32 );
    SKP_assert( gain_mult_Q16 >= 0 );

    for( k = 0; k < NB_SUBFR; k++ ) {
        psEncCtrl->Gains_Q16[ k ] = SKP_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
        if( psEncCtrl->Gains_Q16[ k ] < 0 ) {
            psEncCtrl->Gains_Q16[ k ] = SKP_int32_MAX;
        }
    }

    for( k = 0; k < NB_SUBFR; k++ ) {
        psEncCtrl->Gains_Q16[ k ] = SKP_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
/* Processing of gains */
void SKP_Silk_process_gains_FIX(
    SKP_Silk_encoder_state_FIX      *psEnc,         /* I/O  Encoder state_FIX                           */
    SKP_Silk_encoder_control_FIX    *psEncCtrl      /* I/O  Encoder control_FIX                         */
)
{
    SKP_Silk_shape_state_FIX    *psShapeSt = &psEnc->sShape;
    SKP_int     k;
    SKP_int32   s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart;

    /* Gain reduction when LTP coding gain is high */
    if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) {
        /*s = -0.5f * SKP_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */
        s_Q16 = -SKP_Silk_sigm_Q15( SKP_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - (12 << 7), 4 ) );
        for( k = 0; k < NB_SUBFR; k++ ) {
            psEncCtrl->Gains_Q16[ k ] = SKP_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 );
        }
    }

    /* Limit the quantized signal */
    /*  69 = 21.0f + 16/0.33    */
    InvMaxSqrVal_Q16 = SKP_DIV32_16( SKP_Silk_log2lin( 
        SKP_SMULWB( (69 << 7) - psEncCtrl->current_SNR_dB_Q7, SKP_FIX_CONST( 0.33, 16 )) ), psEnc->sCmn.subfr_length );

    for( k = 0; k < NB_SUBFR; k++ ) {
        /* Soft limit on ratio residual energy and squared gains */
        ResNrg     = psEncCtrl->ResNrg[ k ];
        ResNrgPart = SKP_SMULWW( ResNrg, InvMaxSqrVal_Q16 );
        if( psEncCtrl->ResNrgQ[ k ] > 0 ) {
            if( psEncCtrl->ResNrgQ[ k ] < 32 ) {
                ResNrgPart = SKP_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] );
            } else {
                ResNrgPart = 0;
            }
        } else if( psEncCtrl->ResNrgQ[k] != 0 ) {
            if( ResNrgPart > SKP_RSHIFT( SKP_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) {
                ResNrgPart = SKP_int32_MAX;
            } else {
                ResNrgPart = SKP_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] );
            }
        }
        gain = psEncCtrl->Gains_Q16[ k ];
        gain_squared = SKP_ADD_SAT32( ResNrgPart, SKP_SMMUL( gain, gain ) );
        if( gain_squared < SKP_int16_MAX ) {
            /* recalculate with higher precision */
            gain_squared = SKP_SMLAWW( SKP_LSHIFT( ResNrgPart, 16 ), gain, gain );
            SKP_assert( gain_squared > 0 );
            gain = SKP_Silk_SQRT_APPROX( gain_squared );                  /* Q8   */
            psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( gain, 8 );        /* Q16  */
        } else {
            gain = SKP_Silk_SQRT_APPROX( gain_squared );                  /* Q0   */
            psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( gain, 16 );       /* Q16  */
        }
    }

    /* Noise shaping quantization */
    SKP_Silk_gains_quant( psEncCtrl->sCmn.GainsIndices, psEncCtrl->Gains_Q16, 
        &psShapeSt->LastGainIndex, psEnc->sCmn.nFramesInPayloadBuf );
    /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
    if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) {
        if( psEncCtrl->LTPredCodGain_Q7 + SKP_RSHIFT( psEncCtrl->input_tilt_Q15, 8 ) > ( 1 << 7 ) ) {
            psEncCtrl->sCmn.QuantOffsetType = 0;
        } else {
            psEncCtrl->sCmn.QuantOffsetType = 1;
        }
    }

    /* Quantizer boundary adjustment */
    if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) {
        psEncCtrl->Lambda_Q10 = SKP_FIX_CONST( 1.3, 10 )
                  - SKP_SMULWB( SKP_FIX_CONST( 0.5, 18 ), psEnc->speech_activity_Q8       )
                  - SKP_SMULWB( SKP_FIX_CONST( 0.3, 12 ), psEncCtrl->input_quality_Q14    )
                  + SKP_SMULBB( SKP_FIX_CONST( 0.2, 10 ), psEncCtrl->sCmn.QuantOffsetType )
                  - SKP_SMULWB( SKP_FIX_CONST( 0.1, 12 ), psEncCtrl->coding_quality_Q14   );
    } else {
        psEncCtrl->Lambda_Q10 = SKP_FIX_CONST( 1.3, 10 )
                  - SKP_SMULWB( SKP_FIX_CONST( 0.5, 18 ), psEnc->speech_activity_Q8       )
                  - SKP_SMULWB( SKP_FIX_CONST( 0.4, 12 ), psEncCtrl->input_quality_Q14    )
                  + SKP_SMULBB( SKP_FIX_CONST( 0.4, 10 ), psEncCtrl->sCmn.QuantOffsetType )
                  - SKP_SMULWB( SKP_FIX_CONST( 0.1, 12 ), psEncCtrl->coding_quality_Q14   );
    }
    SKP_assert( psEncCtrl->Lambda_Q10 >= 0 );
    SKP_assert( psEncCtrl->Lambda_Q10 < SKP_FIX_CONST( 2, 10 ) );
    
}
        psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( tmp32, 16 - Qnrg );
        /* Ratio of prediction gains, in energy domain */
        SKP_Silk_LPC_inverse_pred_gain_Q13( &pre_nrg_Q30, &psEncCtrl->AR2_Q13[ k * SHAPE_LPC_ORDER_MAX ], psEnc->sCmn.shapingLPCOrder );
        SKP_Silk_LPC_inverse_pred_gain_Q13( &nrg,         &psEncCtrl->AR1_Q13[ k * SHAPE_LPC_ORDER_MAX ], psEnc->sCmn.shapingLPCOrder );

        lz = SKP_min_32( SKP_Silk_CLZ32( pre_nrg_Q30 ) - 1, 19 );
        pre_nrg_Q30 = SKP_DIV32( SKP_LSHIFT( pre_nrg_Q30, lz ), SKP_RSHIFT( nrg, 20 - lz ) + 1 ); // Q20
        pre_nrg_Q30 = SKP_RSHIFT( SKP_LSHIFT_SAT32( pre_nrg_Q30, 9 ), 1 );  /* Q28 */
        psEncCtrl->GainsPre_Q14[ k ] = ( SKP_int )SKP_Silk_SQRT_APPROX( pre_nrg_Q30 );
    }

    /*****************/
    /* Gain tweaking */
    /*****************/
    /* Increase gains during low speech activity and put lower limit on gains */
    gain_mult_Q16 = SKP_Silk_log2lin( -SKP_SMLAWB( -16 << 7, SNR_adj_dB_Q7,           10486 ) ); // 10486_Q16 = 0.16_Q0
    gain_add_Q16  = SKP_Silk_log2lin(  SKP_SMLAWB(  16 << 7, NOISE_FLOOR_dB_Q7,       10486 ) ); // 10486_Q16 = 0.16_Q0
    tmp32         = SKP_Silk_log2lin(  SKP_SMLAWB(  16 << 7, RELATIVE_MIN_GAIN_dB_Q7, 10486 ) ); // 10486_Q16 = 0.16_Q0
    tmp32 = SKP_SMULWW( psEnc->avgGain_Q16, tmp32 );
    gain_add_Q16 = SKP_ADD_SAT32( gain_add_Q16, tmp32 );
    SKP_assert( gain_mult_Q16 >= 0 );

    for( k = 0; k < NB_SUBFR; k++ ) {
        psEncCtrl->Gains_Q16[ k ] = SKP_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
        SKP_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
    }

    for( k = 0; k < NB_SUBFR; k++ ) {
        psEncCtrl->Gains_Q16[ k ] = SKP_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
        psEnc->avgGain_Q16 = SKP_ADD_SAT32( 
            psEnc->avgGain_Q16,