/* Solve the normal equations using the Levinson-Durbin recursion */ silk_float silk_levinsondurbin_FLP( /* O prediction error energy */ silk_float A[], /* O prediction coefficients [order] */ const silk_float corr[], /* I input auto-correlations [order + 1] */ const int order /* I prediction order */ ) { int i, mHalf, m; silk_float min_nrg, nrg, t, km, Atmp1, Atmp2; min_nrg = 1e-12f * corr[0] + 1e-9f; nrg = corr[0]; nrg = silk_max_float(min_nrg, nrg); A[0] = corr[1] / nrg; nrg -= A[0] * corr[1]; nrg = silk_max_float(min_nrg, nrg); for (m = 1; m < order; m++) { t = corr[m + 1]; for (i = 0; i < m; i++) { t -= A[i] * corr[m - i]; } /* reflection coefficient */ km = t / nrg; /* residual energy */ nrg -= km * t; nrg = silk_max_float(min_nrg, nrg); mHalf = m >> 1; for (i = 0; i < mHalf; i++) { Atmp1 = A[i]; Atmp2 = A[m - i - 1]; A[m - i - 1] -= km * Atmp1; A[i] -= km * Atmp2; } if (m & 1) { A[mHalf] -= km * A[mHalf]; } A[m] = km; } /* return the residual energy */ return nrg; }
silk_float silk_schur_FLP( /* O returns residual energy */ silk_float refl_coef[], /* O reflection coefficients (length order) */ const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ int order /* I order */ ) { int k, n; silk_float C[SILK_MAX_ORDER_LPC + 1][2]; silk_float Ctmp1, Ctmp2, rc_tmp; assert(order == 6 || order == 8 || order == 10 || order == 12 || order == 14 || order == 16); /* Copy correlations */ for (k = 0; k < order + 1; k++) { C[k][0] = C[k][1] = auto_corr[k]; } for (k = 0; k < order; k++) { /* Get reflection coefficient */ rc_tmp = -C[k + 1][0] / silk_max_float(C[0][1], 1e-9f); /* Save the output */ refl_coef[k] = rc_tmp; /* Update correlations */ for (n = 0; n < order - k; n++) { Ctmp1 = C[n + k + 1][0]; Ctmp2 = C[n][1]; C[n + k + 1][0] = Ctmp1 + Ctmp2 * rc_tmp; C[n][1] = Ctmp2 + Ctmp1 * rc_tmp; } } /* Return residual energy */ return C[0][1]; }
silk_float silk_schur_FLP( /* O returns residual energy */ silk_float refl_coef[], /* O reflection coefficients (length order) */ const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ opus_int order /* I order */ ) { opus_int k, n; double C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; double Ctmp1, Ctmp2, rc_tmp; celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); /* Copy correlations */ k = 0; do { C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ]; } while( ++k <= order ); for( k = 0; k < order; k++ ) { /* Get reflection coefficient */ rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f ); /* Save the output */ refl_coef[ k ] = (silk_float)rc_tmp; /* Update correlations */ for( n = 0; n < order - k; n++ ) { Ctmp1 = C[ n + k + 1 ][ 0 ]; Ctmp2 = C[ n ][ 1 ]; C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp; C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp; } } /* Return residual energy */ return (silk_float)C[ 0 ][ 1 ]; }
void silk_find_pitch_lags_FLP( silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ silk_float res[], /* O Residual */ const silk_float x[], /* I Speech signal */ int arch /* I Run-time architecture */ ) { opus_int buf_len; silk_float thrhld, res_nrg; const silk_float *x_buf_ptr, *x_buf; silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; silk_float A[ MAX_FIND_PITCH_LPC_ORDER ]; silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ]; silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ]; silk_float *Wsig_ptr; /******************************************/ /* Set up buffer lengths etc based on Fs */ /******************************************/ buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; /* Safety check */ silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); x_buf = x - psEnc->sCmn.ltp_mem_length; /******************************************/ /* Estimate LPC AR coeficients */ /******************************************/ /* Calculate windowed signal */ /* First LA_LTP samples */ x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; Wsig_ptr = Wsig; silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); /* Middle non-windowed samples */ Wsig_ptr += psEnc->sCmn.la_pitch; x_buf_ptr += psEnc->sCmn.la_pitch; silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) ); /* Last LA_LTP samples */ Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); /* Calculate autocorrelation sequence */ silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); /* Add white noise, as a fraction of the energy */ auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1; /* Calculate the reflection coefficients using Schur */ res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); /* Prediction gain */ psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f ); /* Convert reflection coefficients to prediction coefficients */ silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder ); /* Bandwidth expansion */ silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION ); /*****************************************/ /* LPC analysis filtering */ /*****************************************/ silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { /* Threshold for pitch estimator */ thrhld = 0.6f; thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder; thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1); thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ); /*****************************************/ /* Call Pitch estimator */ /*****************************************/ if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f, thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, arch ) == 0 ) { psEnc->sCmn.indices.signalType = TYPE_VOICED; } else { psEnc->sCmn.indices.signalType = TYPE_UNVOICED; } } else {
void silk_find_LTP_FLP( silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ silk_float *LTPredCodGain, /* O LTP coding gain */ const silk_float r_lpc[], /* I LPC residual */ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */ const opus_int subfr_length, /* I Subframe length */ const opus_int nb_subfr, /* I number of subframes */ const opus_int mem_offset /* I Number of samples in LTP memory */ ) { opus_int i, k; silk_float *b_ptr, temp, *WLTP_ptr; silk_float LPC_res_nrg, LPC_LTP_res_nrg; silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ]; silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu; silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; const silk_float *r_ptr, *lag_ptr; b_ptr = b; WLTP_ptr = WLTP; r_ptr = &r_lpc[ mem_offset ]; for( k = 0; k < nb_subfr; k++ ) { lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr ); silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr ); rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length ); regu = 1.0f + rr[ k ] + matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) + matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ); regu *= LTP_DAMPING / 3; silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER ); silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr ); /* Calculate residual energy */ nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER ); temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER ); w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER ); r_ptr += subfr_length; b_ptr += LTP_ORDER; WLTP_ptr += LTP_ORDER * LTP_ORDER; } /* Compute LTP coding gain */ if( LTPredCodGain != NULL ) { LPC_LTP_res_nrg = 1e-6f; LPC_res_nrg = 0.0f; for( k = 0; k < nb_subfr; k++ ) { LPC_res_nrg += rr[ k ] * Wght[ k ]; LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ]; } silk_assert( LPC_LTP_res_nrg > 0 ); *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg ); } /* Smoothing */ /* d = sum( B, 1 ); */ b_ptr = b; for( k = 0; k < nb_subfr; k++ ) { d[ k ] = 0; for( i = 0; i < LTP_ORDER; i++ ) { d[ k ] += b_ptr[ i ]; } b_ptr += LTP_ORDER; } /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ temp = 1e-3f; for( k = 0; k < nb_subfr; k++ ) { temp += w[ k ]; } m = 0; for( k = 0; k < nb_subfr; k++ ) { m += d[ k ] * w[ k ]; } m = m / temp; b_ptr = b; for( k = 0; k < nb_subfr; k++ ) { g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] ); temp = 0; for( i = 0; i < LTP_ORDER; i++ ) { delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f ); temp += delta_b[ i ]; } temp = g / temp; for( i = 0; i < LTP_ORDER; i++ ) { b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp; } b_ptr += LTP_ORDER; } }