diff options
author | Koen Vos <koenvos@users.noreply.github.com> | 2016-01-13 11:54:40 +0800 |
---|---|---|
committer | Jean-Marc Valin <jmvalin@jmvalin.ca> | 2016-05-22 00:59:25 -0400 |
commit | eae137c6952adae3c92d5dfe8de273e9557e3f12 (patch) | |
tree | d17915be41985ab0c6e10df8b0412ab79d2cf901 /silk/float/burg_modified_FLP.c | |
parent | da995f7d9fc52fd161f725824f909489acdfac01 (diff) | |
download | opus-eae137c6952adae3c92d5dfe8de273e9557e3f12.tar.gz |
faster Burg implementation
Diffstat (limited to 'silk/float/burg_modified_FLP.c')
-rw-r--r-- | silk/float/burg_modified_FLP.c | 162 |
1 files changed, 75 insertions, 87 deletions
diff --git a/silk/float/burg_modified_FLP.c b/silk/float/burg_modified_FLP.c index ea5dc25a..7ef4cac2 100644 --- a/silk/float/burg_modified_FLP.c +++ b/silk/float/burg_modified_FLP.c @@ -33,11 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "tuning_parameters.h" #include "define.h" -#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/ +/* This code implements the method from https://www.opus-codec.org/docs/vos_fastburg.pdf */ /* Compute reflection coefficients from input signal */ -silk_float silk_burg_modified_FLP( /* O returns residual energy */ - silk_float A[], /* O prediction coefficients (length order) */ +silk_float silk_burg_modified_FLP( + silk_float af[], /* O prediction coefficients (length order) */ const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ const silk_float minInvGain, /* I minimum inverse prediction gain */ const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ @@ -46,75 +46,81 @@ silk_float silk_burg_modified_FLP( /* O returns residual energy ) { opus_int k, n, s, reached_max_gain; - double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; + double invGain, num, nrg, rc, tmp1, tmp2, x1, x2, atmp; const silk_float *x_ptr; - double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ]; - double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ]; - double Af[ SILK_MAX_ORDER_LPC ]; - - silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + double c[ SILK_MAX_ORDER_LPC + 1 ]; + double g[ SILK_MAX_ORDER_LPC + 1 ]; + double a[ SILK_MAX_ORDER_LPC ]; /* Compute autocorrelations, added over subframes */ - C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); - silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) ); + silk_memset( c, 0, (D + 1) * 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 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); + for( n = 0; n < D + 1; n++ ) { + c[ n ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); } } - silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) ); + for( n = 0; n < D + 1; n++ ) { + c[ n ] *= 2.0; + } /* Initialize */ - CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f; - invGain = 1.0f; + c[ 0 ] += FIND_LPC_COND_FAC * c[ 0 ] + 1e-9f ; + g[ 0 ] = c[ 0 ]; + tmp1 = 0.0f; + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = x_ptr[ 0 ]; + x2 = x_ptr[ subfr_length - 1 ]; + tmp1 += x1 * x1 + x2 * x2; + } + g[ 0 ] -= tmp1; + g[ 1 ] = c[ 1 ]; + rc = - g[ 1 ] / g[ 0 ]; + silk_assert( rc > -1.0 && rc < 1.0 ); + a[ 0 ] = rc; + invGain = ( 1.0 - rc * rc ); reached_max_gain = 0; - 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( n = 1; n < D; n++ ) { + for( k = 0; k < (n >> 1) + 1; k++ ) { + tmp1 = g[ k ]; + tmp2 = g[ n - k ]; + g[ k ] = tmp1 + rc * tmp2; + g[ n - k ] = tmp2 + rc * tmp1; + } for( s = 0; s < nb_subfr; s++ ) { x_ptr = x + s * subfr_length; - tmp1 = x_ptr[ n ]; - tmp2 = x_ptr[ subfr_length - n - 1 ]; + x1 = x_ptr[ n ]; + x2 = x_ptr[ subfr_length - n - 1 ]; + tmp1 = x1; + tmp2 = x2; 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 ]; - tmp1 += x_ptr[ n - k - 1 ] * Atmp; - tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; + atmp = a[ k ]; + c[ k + 1 ] -= x1 * x_ptr[ n - k - 1 ] + x2 * x_ptr[ subfr_length - n + k ]; + 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 ]; + g[ k ] -= tmp1 * x_ptr[ n - 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 ]; + tmp1 = c[ n + 1 ]; + num = 0.0f; + nrg = g[ 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; + atmp = a[ k ]; + tmp1 += c[ n - k ] * atmp; + num += g[ n - k ] * atmp; + nrg += g[ k + 1 ] * atmp; } - silk_assert( nrg_f > 0.0 ); - silk_assert( nrg_b > 0.0 ); + g[ n + 1] = tmp1; + num += tmp1; + silk_assert( nrg > 0.0 ); /* Calculate the next order reflection (parcor) coefficient */ - rc = -2.0 * num / ( nrg_f + nrg_b ); + rc = -num / nrg; silk_assert( rc > -1.0 && rc < 1.0 ); /* Update inverse prediction gain */ @@ -123,7 +129,7 @@ silk_float silk_burg_modified_FLP( /* O returns residual energy /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ rc = sqrt( 1.0 - minInvGain / invGain ); if( num > 0 ) { - /* Ensure adjusted reflection coefficients has the original sign */ + /* Ensure adjusted reflection coefficient has the original sign */ rc = -rc; } invGain = minInvGain; @@ -134,53 +140,35 @@ silk_float silk_burg_modified_FLP( /* O returns residual energy /* 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; + tmp1 = a[ k ]; + tmp2 = a[ n - k - 1 ]; + a[ k ] = tmp1 + rc * tmp2; + a[ n - k - 1 ] = tmp2 + rc * tmp1; } - Af[ n ] = rc; + a[ n ] = rc; if( reached_max_gain ) { /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ for( k = n + 1; k < D; k++ ) { - Af[ k ] = 0.0; + a[ k ] = 0.0; } break; } - - /* 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; - } } - if( reached_max_gain ) { - /* Convert to silk_float */ - for( k = 0; k < D; k++ ) { - A[ k ] = (silk_float)( -Af[ k ] ); - } - /* Subtract energy of preceding samples from C0 */ - for( s = 0; s < nb_subfr; s++ ) { - C0 -= silk_energy_FLP( x + s * subfr_length, D ); - } - /* Approximate residual energy */ - nrg_f = C0 * invGain; - } else { - /* Compute residual energy and store coefficients as silk_float */ - 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 ] = (silk_float)(-Atmp); - } - nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1; + /* Convert to silk_float */ + for( k = 0; k < D; k++ ) { + af[ k ] = (silk_float)( -a[ k ] ); + } + + nrg = c[ 0 ] * 0.5 * (1.0 - FIND_LPC_COND_FAC); + /* Subtract energy of preceding samples from C0 */ + for( s = 0; s < nb_subfr; s++ ) { + nrg -= silk_energy_FLP( x + s * subfr_length, D ); } + /* Approximate residual energy */ + nrg *= invGain; - /* Return residual energy */ - return (silk_float)nrg_f; + /* Return approximate residual energy */ + return (silk_float)nrg; } |