/* LPC analysis */ void silk_find_LPC_FLP( silk_encoder_state *psEncC, /* I/O Encoder state */ opus_int16 NLSF_Q15[], /* O NLSFs */ const silk_float x[], /* I Input signal */ const silk_float minInvGain /* I Inverse of max prediction gain */ ) { opus_int k, subfr_length; silk_float a[ MAX_LPC_ORDER ]; /* Used only for NLSF interpolation */ silk_float res_nrg, res_nrg_2nd, res_nrg_interp; opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; silk_float a_tmp[ MAX_LPC_ORDER ]; silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; /* Default: No interpolation */ psEncC->indices.NLSFInterpCoef_Q2 = 4; /* Burg AR analysis for the full frame */ res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { /* 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 -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder ); /* Convert to NLSFs */ silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder ); /* Search over interpolation indices to find the one with lowest residual energy */ res_nrg_2nd = silk_float_MAX; for( k = 3; k >= 0; k-- ) { /* Interpolate NLSFs for first half */ silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); /* Convert to LPC for residual energy evaluation */ silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder ); /* Calculate residual energy with LSF interpolation */ silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder ); res_nrg_interp = (silk_float)( silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) ); /* 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; psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)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( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder ); } silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); }
/* Limit, stabilize, convert and quantize NLSFs */ void silk_process_NLSFs( silk_encoder_state *psEncC, /* I/O Encoder state */ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ ) { opus_int i, doInterpolate; opus_int NLSF_mu_Q20; opus_int32 i_sqr_Q15; opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ]; opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ]; silk_assert(psEncC->speech_activity_Q8 >= 0); silk_assert(psEncC->speech_activity_Q8 <= SILK_FIX_CONST(1.0, 8)); silk_assert(psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == (1 << 2)); /***********************/ /* Calculate mu values */ /***********************/ /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */ NLSF_mu_Q20 = silk_SMLAWB(SILK_FIX_CONST(0.003, 20), SILK_FIX_CONST(-0.001, 28), psEncC->speech_activity_Q8); if(psEncC->nb_subfr == 2) { /* Multiply by 1.5 for 10 ms packets */ NLSF_mu_Q20 = silk_ADD_RSHIFT(NLSF_mu_Q20, NLSF_mu_Q20, 1); } silk_assert(NLSF_mu_Q20 > 0); silk_assert(NLSF_mu_Q20 <= SILK_FIX_CONST(0.005, 20)); /* Calculate NLSF weights */ silk_NLSF_VQ_weights_laroia(pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder); /* Update NLSF weights for interpolated NLSFs */ doInterpolate = (psEncC->useInterpolatedNLSFs == 1) && (psEncC->indices.NLSFInterpCoef_Q2 < 4); if(doInterpolate) { /* Calculate the interpolated NLSF vector for the first half */ silk_interpolate(pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder); /* Calculate first half NLSF weights for the interpolated NLSFs */ silk_NLSF_VQ_weights_laroia(pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder); /* Update NLSF weights with contribution from first half */ i_sqr_Q15 = silk_LSHIFT(silk_SMULBB(psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2), 11); for(i = 0; i < psEncC->predictLPCOrder; i++) { pNLSFW_QW[ i ] = silk_SMLAWB(silk_RSHIFT(pNLSFW_QW[ i ], 1), (opus_int32)pNLSFW0_temp_QW[ i ], i_sqr_Q15); silk_assert(pNLSFW_QW[ i ] >= 1); } } silk_NLSF_encode(psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType); /* Convert quantized NLSFs back to LPC coefficients */ silk_NLSF2A(PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder); if(doInterpolate) { /* Calculate the interpolated, quantized LSF vector for the first half */ silk_interpolate(pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder); /* Convert back to LPC coefficients */ silk_NLSF2A(PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder); } else { /* Copy LPC coefficients for first half from second half */ silk_memcpy(PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof(opus_int16)); } }
/* Finds LPC vector from correlations, and converts to NLSF */ void silk_find_LPC_FIX( silk_encoder_state *psEncC, /* I/O Encoder state */ opus_int16 NLSF_Q15[], /* O NLSFs */ const opus_int16 x[], /* I Input signal */ const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ ) { opus_int k, subfr_length; opus_int32 a_Q16[ MAX_LPC_ORDER ]; opus_int isInterpLower, shift; opus_int32 res_nrg0, res_nrg1; opus_int rshift0, rshift1; /* Used only for LSF interpolation */ opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; SAVE_STACK; subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; /* Default: no interpolation */ psEncC->indices.NLSFInterpCoef_Q2 = 4; /* Burg AR analysis for the full frame */ silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch ); if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { VARDECL( opus_int16, LPC_res ); /* Optimal solution for last 10 ms */ silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch ); /* 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 */ shift = res_tmp_nrg_Q - res_nrg_Q; if( shift >= 0 ) { if( shift < 32 ) { res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift ); } } else { silk_assert( shift > -32 ); res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; res_nrg_Q = res_tmp_nrg_Q; } /* Convert to NLSFs */ silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder ); ALLOC( LPC_res, 2 * subfr_length, opus_int16 ); /* Search over interpolation indices to find the one with lowest residual energy */ for( k = 3; k >= 0; k-- ) { /* Interpolate NLSFs for first half */ silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); /* Convert to LPC for residual energy evaluation */ silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder ); /* Calculate residual energy with NLSF interpolation */ silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder ); silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ); silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ); /* Add subframe energies from first half frame */ shift = rshift0 - rshift1; if( shift >= 0 ) { res_nrg1 = silk_RSHIFT( res_nrg1, shift ); res_nrg_interp_Q = -rshift0; } else { res_nrg0 = silk_RSHIFT( res_nrg0, -shift ); res_nrg_interp_Q = -rshift1; } res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 ); /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ shift = res_nrg_interp_Q - res_nrg_Q; if( shift >= 0 ) { if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { isInterpLower = silk_TRUE; } else { isInterpLower = silk_FALSE; } } else { if( -shift < 32 ) { if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) { isInterpLower = silk_TRUE; } else { isInterpLower = silk_FALSE; } } else { isInterpLower = silk_FALSE; } } /* Determine whether current interpolated NLSFs are best so far */ if( isInterpLower == silk_TRUE ) { /* Interpolation has lower residual energy */ res_nrg = res_nrg_interp; res_nrg_Q = res_nrg_interp_Q; psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; } } } if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder ); } silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); RESTORE_STACK; }