/* Limit, stabilize, convert and quantize NLSFs */
void SKP_Silk_process_NLSFs_FLP(
    SKP_Silk_encoder_state_FLP      *psEnc,             /* I/O  Encoder state FLP                       */
    SKP_Silk_encoder_control_FLP    *psEncCtrl,         /* I/O  Encoder control FLP                     */
    SKP_float                       *pNLSF              /* I/O  NLSFs (quantized output)                */
)
{
    SKP_int     doInterpolate;
    SKP_float   pNLSFW[ MAX_LPC_ORDER ];
    SKP_float   NLSF_mu, NLSF_mu_fluc_red, i_sqr, NLSF_interpolation_factor = 0.0f;
    const SKP_Silk_NLSF_CB_FLP *psNLSF_CB_FLP;

    /* Used only for NLSF interpolation */
    SKP_float   pNLSF0_temp[  MAX_LPC_ORDER ];
    SKP_float   pNLSFW0_temp[ MAX_LPC_ORDER ];
    SKP_int     i;

    SKP_assert( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED || psEncCtrl->sCmn.sigtype == SIG_TYPE_UNVOICED );

    /***********************/
    /* Calculate mu values */
    /***********************/
    if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) {
        NLSF_mu          = 0.002f - 0.001f * psEnc->speech_activity;
        NLSF_mu_fluc_red = 0.1f   - 0.05f  * psEnc->speech_activity;
    } else { 
        NLSF_mu          = 0.005f - 0.004f * psEnc->speech_activity;
        NLSF_mu_fluc_red = 0.2f   - 0.1f   * ( psEnc->speech_activity + psEncCtrl->sparseness );
    }

    /* Calculate NLSF weights */
    SKP_Silk_NLSF_VQ_weights_laroia_FLP( pNLSFW, pNLSF, psEnc->sCmn.predictLPCOrder );

    /* Update NLSF weights for interpolated NLSFs */
    doInterpolate = ( psEnc->sCmn.useInterpolatedNLSFs == 1 ) && ( psEncCtrl->sCmn.NLSFInterpCoef_Q2 < ( 1 << 2 ) );
    if( doInterpolate ) {

        /* Calculate the interpolated NLSF vector for the first half */
        NLSF_interpolation_factor = 0.25f * psEncCtrl->sCmn.NLSFInterpCoef_Q2;
        SKP_Silk_interpolate_wrapper_FLP( pNLSF0_temp, psEnc->sPred.prev_NLSFq, pNLSF, 
            NLSF_interpolation_factor, psEnc->sCmn.predictLPCOrder );

        /* Calculate first half NLSF weights for the interpolated NLSFs */
        SKP_Silk_NLSF_VQ_weights_laroia_FLP( pNLSFW0_temp, pNLSF0_temp, psEnc->sCmn.predictLPCOrder );

        /* Update NLSF weights with contribution from first half */
        i_sqr = NLSF_interpolation_factor * NLSF_interpolation_factor;
        for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) {
            pNLSFW[ i ] = 0.5f * ( pNLSFW[ i ] + i_sqr * pNLSFW0_temp[ i ] );
        }
    }

    /* Set pointer to the NLSF codebook for the current signal type and LPC order */
    psNLSF_CB_FLP = psEnc->psNLSF_CB_FLP[ psEncCtrl->sCmn.sigtype ];

    /* Quantize NLSF parameters given the trained NLSF codebooks */
    SKP_Silk_NLSF_MSVQ_encode_FLP( psEncCtrl->sCmn.NLSFIndices, pNLSF, psNLSF_CB_FLP, psEnc->sPred.prev_NLSFq, pNLSFW, NLSF_mu, 
        NLSF_mu_fluc_red, psEnc->sCmn.NLSF_MSVQ_Survivors, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.first_frame_after_reset );

    /* Convert quantized NLSFs back to LPC coefficients */
    SKP_Silk_NLSF2A_stable_FLP( psEncCtrl->PredCoef[ 1 ], pNLSF, psEnc->sCmn.predictLPCOrder );

    if( doInterpolate ) {
        /* Calculate the interpolated, quantized NLSF vector for the first half */
        SKP_Silk_interpolate_wrapper_FLP( pNLSF0_temp, psEnc->sPred.prev_NLSFq, pNLSF, 
            NLSF_interpolation_factor, psEnc->sCmn.predictLPCOrder );

        /* Convert back to LPC coefficients */
        SKP_Silk_NLSF2A_stable_FLP( psEncCtrl->PredCoef[ 0 ], pNLSF0_temp, psEnc->sCmn.predictLPCOrder );

    } else {
        /* Copy LPC coefficients for first half from second half */
        SKP_memcpy( psEncCtrl->PredCoef[ 0 ], psEncCtrl->PredCoef[ 1 ], psEnc->sCmn.predictLPCOrder * sizeof( SKP_float ) );
    }
}
void SKP_Silk_find_LPC_FLP(
          SKP_float                 NLSF[],             /* O    NLSFs                                   */
          SKP_int                   *interpIndex,       /* O    NLSF interp. index for NLSF interp.     */
    const SKP_float                 prev_NLSFq[],       /* I    Previous NLSFs, for NLSF interpolation  */
    const SKP_int                   useInterpNLSFs,     /* I    Flag                                    */
    const SKP_int                   LPC_order,          /* I    LPC order                               */
    const SKP_float                 x[],                /* I    Input signal                            */
    const SKP_int                   subfr_length        /* I    Subframe length incl preceeding samples */
)
{
    SKP_int     k;
    SKP_float   a[ MAX_LPC_ORDER ];

    /* Used only for NLSF interpolation */
    double      res_nrg, res_nrg_2nd, res_nrg_interp;
    SKP_float   a_tmp[ MAX_LPC_ORDER ], NLSF0[ MAX_LPC_ORDER ];
    SKP_float   LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ];

    /* Default: No interpolation */
    *interpIndex = 4;

    /* Burg AR analysis for the full frame */
    res_nrg = SKP_Silk_burg_modified_FLP( a, x, subfr_length, NB_SUBFR, FIND_LPC_COND_FAC, LPC_order );

	SKP_Silk_bwexpander_FLP( a, LPC_order, FIND_LPC_CHIRP );

    if( useInterpNLSFs == 1 ) {

        /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than        */
        /* adding it to the residual energy of the first 10 ms in each iteration of the search below    */
        res_nrg -= SKP_Silk_burg_modified_FLP( a_tmp, x + ( NB_SUBFR / 2 ) * subfr_length, 
            subfr_length, NB_SUBFR / 2, FIND_LPC_COND_FAC, LPC_order );

        SKP_Silk_bwexpander_FLP( a_tmp, LPC_order, FIND_LPC_CHIRP );

        /* Convert to NLSFs */
        SKP_Silk_A2NLSF_FLP( NLSF, a_tmp, LPC_order );

        /* Search over interpolation indices to find the one with lowest residual energy */
        res_nrg_2nd = SKP_float_MAX;
        for( k = 3; k >= 0; k-- ) {
            /* Interpolate NLSFs for first half */
            SKP_Silk_interpolate_wrapper_FLP( NLSF0, prev_NLSFq, NLSF, 0.25f * k, LPC_order );

            /* Convert to LPC for residual energy evaluation */
            SKP_Silk_NLSF2A_stable_FLP( a_tmp, NLSF0, LPC_order );

            /* Calculate residual energy with LSF interpolation */
            SKP_Silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, LPC_order );
            res_nrg_interp = 
                SKP_Silk_energy_FLP( LPC_res + LPC_order,                subfr_length - LPC_order ) + 
                SKP_Silk_energy_FLP( LPC_res + LPC_order + subfr_length, subfr_length - LPC_order );

            /* Determine whether current interpolated NLSFs are best so far */
            if( res_nrg_interp < res_nrg ) {
                /* Interpolation has lower residual energy */
                res_nrg = res_nrg_interp;
                *interpIndex = k;
            } else if( res_nrg_interp > res_nrg_2nd ) {
                /* No reason to continue iterating - residual energies will continue to climb */
                break;
            }
            res_nrg_2nd = res_nrg_interp;
        }
    }

    if( *interpIndex == 4 ) {
        /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
        SKP_Silk_A2NLSF_FLP( NLSF, a, LPC_order );
    }

}