/* Calculates correlation matrix X'*X */ void SKP_Silk_corrMatrix_FLP( const SKP_float *x, /* I x vector [ L+order-1 ] used to create X */ const SKP_int L, /* I Length of vectors */ const SKP_int Order, /* I Max lag for correlation */ SKP_float *XX /* O X'*X correlation matrix [order x order] */ ) { SKP_int j, lag; double energy; const SKP_float *ptr1, *ptr2; ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */ energy = SKP_Silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */ matrix_ptr( XX, 0, 0, Order ) = ( SKP_float )energy; for( j = 1; j < Order; j++ ) { /* Calculate X[:,j]'*X[:,j] */ energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ]; matrix_ptr( XX, j, j, Order ) = ( SKP_float )energy; } ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */ for( lag = 1; lag < Order; lag++ ) { /* Calculate X[:,0]'*X[:,lag] */ energy = SKP_Silk_inner_product_FLP( ptr1, ptr2, L ); matrix_ptr( XX, lag, 0, Order ) = ( SKP_float )energy; matrix_ptr( XX, 0, lag, Order ) = ( SKP_float )energy; /* Calculate X[:,j]'*X[:,j + lag] */ for( j = 1; j < ( Order - lag ); j++ ) { energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ]; matrix_ptr( XX, lag + j, j, Order ) = ( SKP_float )energy; matrix_ptr( XX, j, lag + j, Order ) = ( SKP_float )energy; } ptr2--; /* Next column of X */ } }
/* Compute reflection coefficients from input signal */ SKP_float SKP_Silk_burg_modified_FLP( /* O returns residual energy */ SKP_float A[], /* O prediction coefficients (length order) */ const SKP_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ const SKP_int subfr_length, /* I input signal subframe length (including D preceeding samples) */ const SKP_int nb_subfr, /* I number of subframes stacked in x */ const SKP_float WhiteNoiseFrac, /* I fraction added to zero-lag autocorrelation */ const SKP_int D /* I order */ ) { SKP_int k, n, s; double C0, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; const SKP_float *x_ptr; double C_first_row[ SKP_Silk_MAX_ORDER_LPC ], C_last_row[ SKP_Silk_MAX_ORDER_LPC ]; double CAf[ SKP_Silk_MAX_ORDER_LPC + 1 ], CAb[ SKP_Silk_MAX_ORDER_LPC + 1 ]; double Af[ SKP_Silk_MAX_ORDER_LPC ]; SKP_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); SKP_assert( nb_subfr <= MAX_NB_SUBFR ); /* Compute autocorrelations, added over subframes */ C0 = SKP_Silk_energy_FLP( x, nb_subfr * subfr_length ); SKP_memset( C_first_row, 0, SKP_Silk_MAX_ORDER_LPC * sizeof( double ) ); for( s = 0; s < nb_subfr; s++ ) { x_ptr = x + s * subfr_length; for( n = 1; n < D + 1; n++ ) { C_first_row[ n - 1 ] += SKP_Silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); } } SKP_memcpy( C_last_row, C_first_row, SKP_Silk_MAX_ORDER_LPC * sizeof( double ) ); /* Initialize */ CAb[ 0 ] = CAf[ 0 ] = C0 + WhiteNoiseFrac * C0 + 1e-9f; for( n = 0; n < D; n++ ) { /* Update first row of correlation matrix (without first element) */ /* Update last row of correlation matrix (without last element, stored in reversed order) */ /* Update C * Af */ /* Update C * flipud(Af) (stored in reversed order) */ for( s = 0; s < nb_subfr; s++ ) { x_ptr = x + s * subfr_length; tmp1 = x_ptr[ n ]; tmp2 = x_ptr[ subfr_length - n - 1 ]; for( k = 0; k < n; k++ ) { C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; Atmp = Af[ k ]; SKP_assert( subfr_length - n + k + s * subfr_length >= 0 ); SKP_assert( subfr_length - n + k + s * subfr_length < nb_subfr * subfr_length ); tmp1 += x_ptr[ n - k - 1 ] * Atmp; tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; } for( k = 0; k <= n; k++ ) { CAf[ k ] -= tmp1 * x_ptr[ n - k ]; CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; } } tmp1 = C_first_row[ n ]; tmp2 = C_last_row[ n ]; for( k = 0; k < n; k++ ) { Atmp = Af[ k ]; tmp1 += C_last_row[ n - k - 1 ] * Atmp; tmp2 += C_first_row[ n - k - 1 ] * Atmp; } CAf[ n + 1 ] = tmp1; CAb[ n + 1 ] = tmp2; /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ num = CAb[ n + 1 ]; nrg_b = CAb[ 0 ]; nrg_f = CAf[ 0 ]; for( k = 0; k < n; k++ ) { Atmp = Af[ k ]; num += CAb[ n - k ] * Atmp; nrg_b += CAb[ k + 1 ] * Atmp; nrg_f += CAf[ k + 1 ] * Atmp; } SKP_assert( nrg_f > 0.0 ); SKP_assert( nrg_b > 0.0 ); /* Calculate the next order reflection (parcor) coefficient */ rc = -2.0 * num / ( nrg_f + nrg_b ); SKP_assert( rc > -1.0 && rc < 1.0 ); /* Update the AR coefficients */ for( k = 0; k < (n + 1) >> 1; k++ ) { tmp1 = Af[ k ]; tmp2 = Af[ n - k - 1 ]; Af[ k ] = tmp1 + rc * tmp2; Af[ n - k - 1 ] = tmp2 + rc * tmp1; } Af[ n ] = rc; /* Update C * Af and C * Ab */ for( k = 0; k <= n + 1; k++ ) { tmp1 = CAf[ k ]; CAf[ k ] += rc * CAb[ n - k + 1 ]; CAb[ n - k + 1 ] += rc * tmp1; } } /* Return residual energy */ nrg_f = CAf[ 0 ]; tmp1 = 1.0; for( k = 0; k < D; k++ ) { Atmp = Af[ k ]; nrg_f += CAf[ k + 1 ] * Atmp; tmp1 += Atmp * Atmp; A[ k ] = (SKP_float)(-Atmp); } nrg_f -= WhiteNoiseFrac * C0 * tmp1; return (SKP_float)nrg_f; }
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 ); } }