/* Interpolation function with fixed point rounding */ void SKP_Silk_interpolate_wrapper_FLP( SKP_float xi[], /* O Interpolated vector */ const SKP_float x0[], /* I First vector */ const SKP_float x1[], /* I Second vector */ const SKP_float ifact, /* I Interp. factor, weight on second vector */ const SKP_int d /* I Number of parameters */ ) { SKP_int x0_int[ MAX_LPC_ORDER ], x1_int[ MAX_LPC_ORDER ], xi_int[ MAX_LPC_ORDER ]; SKP_int ifact_Q2 = ( SKP_int )( ifact * 4.0f ); SKP_int i; /* Convert input from flp to fix */ for( i = 0; i < d; i++ ) { x0_int[ i ] = SKP_float2int( x0[ i ] * 32768.0f ); x1_int[ i ] = SKP_float2int( x1[ i ] * 32768.0f ); } /* Interpolate two vectors */ SKP_Silk_interpolate( xi_int, x0_int, x1_int, ifact_Q2, d ); /* Convert output from fix to flp */ for( i = 0; i < d; i++ ) { xi[ i ] = ( SKP_float )xi_int[ i ] * ( 1.0f / 32768.0f ); } }
/* Finds LPC vector from correlations, and converts to NLSF */ void SKP_Silk_find_LPC_FIX( SKP_int NLSF_Q15[], /* O NLSFs */ SKP_int *interpIndex, /* O NLSF interpolation index, only used for NLSF interpolation */ const SKP_int prev_NLSFq_Q15[], /* I previous NLSFs, only used for NLSF interpolation */ const SKP_int useInterpolatedNLSFs, /* I Flag */ const SKP_int LPC_order, /* I LPC order */ const SKP_int16 x[], /* I Input signal */ const SKP_int subfr_length /* I Input signal subframe length including preceeding samples */ ) { SKP_int k; SKP_int32 a_Q16[ MAX_LPC_ORDER ]; SKP_int isInterpLower, shift; SKP_int16 S[ MAX_LPC_ORDER ]; SKP_int32 res_nrg0, res_nrg1; SKP_int rshift0, rshift1; /* Used only for LSF interpolation */ SKP_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; SKP_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; SKP_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; SKP_int NLSF0_Q15[ MAX_LPC_ORDER ]; SKP_int16 LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; /* Default: no interpolation */ *interpIndex = 4; /* Burg AR analysis for the full frame */ SKP_Silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, subfr_length, NB_SUBFR, SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); SKP_Silk_bwexpander_32( a_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); if( useInterpolatedNLSFs == 1 ) { /* Optimal solution for last 10 ms */ SKP_Silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + ( NB_SUBFR >> 1 ) * subfr_length, subfr_length, ( NB_SUBFR >> 1 ), SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); SKP_Silk_bwexpander_32( a_tmp_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); /* 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 - SKP_RSHIFT( res_tmp_nrg, shift ); } } else { SKP_assert( shift > -32 ); res_nrg = SKP_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; res_nrg_Q = res_tmp_nrg_Q; } /* Convert to NLSFs */ SKP_Silk_A2NLSF( NLSF_Q15, a_tmp_Q16, LPC_order ); /* Search over interpolation indices to find the one with lowest residual energy */ for( k = 3; k >= 0; k-- ) { /* Interpolate NLSFs for first half */ SKP_Silk_interpolate( NLSF0_Q15, prev_NLSFq_Q15, NLSF_Q15, k, LPC_order ); /* Convert to LPC for residual energy evaluation */ SKP_Silk_NLSF2A_stable( a_tmp_Q12, NLSF0_Q15, LPC_order ); /* Calculate residual energy with NLSF interpolation */ SKP_memset( S, 0, LPC_order * sizeof( SKP_int16 ) ); SKP_Silk_LPC_analysis_filter( x, a_tmp_Q12, S, LPC_res, 2 * subfr_length, LPC_order ); SKP_Silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + LPC_order, subfr_length - LPC_order ); SKP_Silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + LPC_order + subfr_length, subfr_length - LPC_order ); /* Add subframe energies from first half frame */ shift = rshift0 - rshift1; if( shift >= 0 ) { res_nrg1 = SKP_RSHIFT( res_nrg1, shift ); res_nrg_interp_Q = -rshift0; } else { res_nrg0 = SKP_RSHIFT( res_nrg0, -shift ); res_nrg_interp_Q = -rshift1; } res_nrg_interp = SKP_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( SKP_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { isInterpLower = SKP_TRUE; } else { isInterpLower = SKP_FALSE; } } else { if( -shift < 32 ) { if( res_nrg_interp < SKP_RSHIFT( res_nrg, -shift ) ) { isInterpLower = SKP_TRUE; } else { isInterpLower = SKP_FALSE; } } else { isInterpLower = SKP_FALSE; } } /* Determine whether current interpolated NLSFs are best so far */ if( isInterpLower == SKP_TRUE ) { /* Interpolation has lower residual energy */ res_nrg = res_nrg_interp; res_nrg_Q = res_nrg_interp_Q; *interpIndex = k; } } }
/* Limit, stabilize, convert and quantize NLSFs. */ void SKP_Silk_process_NLSFs_FIX( SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ SKP_int *pNLSF_Q15 /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ ) { SKP_int doInterpolate; SKP_int pNLSFW_Q6[ MAX_LPC_ORDER ]; SKP_int NLSF_mu_Q15, NLSF_mu_fluc_red_Q16; SKP_int32 i_sqr_Q15; const SKP_Silk_NLSF_CB_struct *psNLSF_CB; /* Used only for NLSF interpolation */ SKP_int pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; SKP_int pNLSFW0_temp_Q6[ MAX_LPC_ORDER ]; SKP_int i; SKP_assert( psEnc->speech_activity_Q8 >= 0 ); SKP_assert( psEnc->speech_activity_Q8 <= 256 ); SKP_assert( psEncCtrl->sparseness_Q8 >= 0 ); SKP_assert( psEncCtrl->sparseness_Q8 <= 256 ); 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; */ NLSF_mu_Q15 = SKP_SMLAWB( 66, -8388, psEnc->speech_activity_Q8 ); NLSF_mu_fluc_red_Q16 = SKP_SMLAWB( 6554, -838848, psEnc->speech_activity_Q8 ); } else { /* NLSF_mu = 0.005f - 0.004f * psEnc->speech_activity; */ /* NLSF_mu_fluc_red = 0.2f - 0.1f * psEnc->speech_activity - 0.1f * psEncCtrl->sparseness; */ NLSF_mu_Q15 = SKP_SMLAWB( 164, -33554, psEnc->speech_activity_Q8 ); NLSF_mu_fluc_red_Q16 = SKP_SMLAWB( 13107, -1677696, psEnc->speech_activity_Q8 + psEncCtrl->sparseness_Q8 ); } SKP_assert( NLSF_mu_Q15 >= 0 ); SKP_assert( NLSF_mu_Q15 <= 164 ); SKP_assert( NLSF_mu_fluc_red_Q16 >= 0 ); SKP_assert( NLSF_mu_fluc_red_Q16 <= 13107 ); NLSF_mu_Q15 = SKP_max( NLSF_mu_Q15, 1 ); /* Calculate NLSF weights */ TIC(NLSF_weights_FIX) SKP_Silk_NLSF_VQ_weights_laroia( pNLSFW_Q6, pNLSF_Q15, psEnc->sCmn.predictLPCOrder ); TOC(NLSF_weights_FIX) /* 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 */ SKP_Silk_interpolate( pNLSF0_temp_Q15, psEnc->sPred.prev_NLSFq_Q15, pNLSF_Q15, psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sCmn.predictLPCOrder ); /* Calculate first half NLSF weights for the interpolated NLSFs */ TIC(NLSF_weights_FIX) SKP_Silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_Q6, pNLSF0_temp_Q15, psEnc->sCmn.predictLPCOrder ); TOC(NLSF_weights_FIX) /* Update NLSF weights with contribution from first half */ i_sqr_Q15 = SKP_LSHIFT( SKP_SMULBB( psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEncCtrl->sCmn.NLSFInterpCoef_Q2 ), 11 ); for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { pNLSFW_Q6[ i ] = SKP_SMLAWB( SKP_RSHIFT( pNLSFW_Q6[ i ], 1 ), pNLSFW0_temp_Q6[ i ], i_sqr_Q15 ); SKP_assert( pNLSFW_Q6[ i ] <= SKP_int16_MAX ); SKP_assert( pNLSFW_Q6[ i ] >= 1 ); } } /* Set pointer to the NLSF codebook for the current signal type and LPC order */ psNLSF_CB = psEnc->sCmn.psNLSF_CB[ psEncCtrl->sCmn.sigtype ]; /* Quantize NLSF parameters given the trained NLSF codebooks */ TIC(MSVQ_encode_FIX) SKP_Silk_NLSF_MSVQ_encode_FIX( psEncCtrl->sCmn.NLSFIndices, pNLSF_Q15, psNLSF_CB, psEnc->sPred.prev_NLSFq_Q15, pNLSFW_Q6, NLSF_mu_Q15, NLSF_mu_fluc_red_Q16, psEnc->sCmn.NLSF_MSVQ_Survivors, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.first_frame_after_reset ); TOC(MSVQ_encode_FIX) /* Convert quantized NLSFs back to LPC coefficients */ SKP_Silk_NLSF2A_stable( psEncCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psEnc->sCmn.predictLPCOrder ); if( doInterpolate ) { /* Calculate the interpolated, quantized LSF vector for the first half */ SKP_Silk_interpolate( pNLSF0_temp_Q15, psEnc->sPred.prev_NLSFq_Q15, pNLSF_Q15, psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sCmn.predictLPCOrder ); /* Convert back to LPC coefficients */ SKP_Silk_NLSF2A_stable( psEncCtrl->PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEnc->sCmn.predictLPCOrder ); } else { /* Copy LPC coefficients for first half from second half */ SKP_memcpy( psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->PredCoef_Q12[ 1 ], psEnc->sCmn.predictLPCOrder * sizeof( SKP_int16 ) ); } }