michael@0: /*********************************************************************** michael@0: Copyright (c) 2006-2011, Skype Limited. All rights reserved. michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions michael@0: are met: michael@0: - Redistributions of source code must retain the above copyright notice, michael@0: this list of conditions and the following disclaimer. michael@0: - Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: - Neither the name of Internet Society, IETF or IETF Trust, nor the michael@0: names of specific contributors, may be used to endorse or promote michael@0: products derived from this software without specific prior written michael@0: permission. michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" michael@0: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE michael@0: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE michael@0: ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE michael@0: LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR michael@0: CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF michael@0: SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS michael@0: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN michael@0: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) michael@0: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE michael@0: POSSIBILITY OF SUCH DAMAGE. michael@0: ***********************************************************************/ michael@0: michael@0: #ifdef HAVE_CONFIG_H michael@0: #include "config.h" michael@0: #endif michael@0: michael@0: #include "SigProc_FLP.h" michael@0: #include "tuning_parameters.h" michael@0: #include "define.h" michael@0: michael@0: #define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/ michael@0: michael@0: /* Compute reflection coefficients from input signal */ michael@0: silk_float silk_burg_modified_FLP( /* O returns residual energy */ michael@0: silk_float A[], /* O prediction coefficients (length order) */ michael@0: const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ michael@0: const silk_float minInvGain, /* I minimum inverse prediction gain */ michael@0: const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ michael@0: const opus_int nb_subfr, /* I number of subframes stacked in x */ michael@0: const opus_int D /* I order */ michael@0: ) michael@0: { michael@0: opus_int k, n, s, reached_max_gain; michael@0: double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; michael@0: const silk_float *x_ptr; michael@0: double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ]; michael@0: double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ]; michael@0: double Af[ SILK_MAX_ORDER_LPC ]; michael@0: michael@0: silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); michael@0: michael@0: /* Compute autocorrelations, added over subframes */ michael@0: C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); michael@0: silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) ); michael@0: for( s = 0; s < nb_subfr; s++ ) { michael@0: x_ptr = x + s * subfr_length; michael@0: for( n = 1; n < D + 1; n++ ) { michael@0: C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); michael@0: } michael@0: } michael@0: silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) ); michael@0: michael@0: /* Initialize */ michael@0: CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f; michael@0: invGain = 1.0f; michael@0: reached_max_gain = 0; michael@0: for( n = 0; n < D; n++ ) { michael@0: /* Update first row of correlation matrix (without first element) */ michael@0: /* Update last row of correlation matrix (without last element, stored in reversed order) */ michael@0: /* Update C * Af */ michael@0: /* Update C * flipud(Af) (stored in reversed order) */ michael@0: for( s = 0; s < nb_subfr; s++ ) { michael@0: x_ptr = x + s * subfr_length; michael@0: tmp1 = x_ptr[ n ]; michael@0: tmp2 = x_ptr[ subfr_length - n - 1 ]; michael@0: for( k = 0; k < n; k++ ) { michael@0: C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; michael@0: C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; michael@0: Atmp = Af[ k ]; michael@0: tmp1 += x_ptr[ n - k - 1 ] * Atmp; michael@0: tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; michael@0: } michael@0: for( k = 0; k <= n; k++ ) { michael@0: CAf[ k ] -= tmp1 * x_ptr[ n - k ]; michael@0: CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; michael@0: } michael@0: } michael@0: tmp1 = C_first_row[ n ]; michael@0: tmp2 = C_last_row[ n ]; michael@0: for( k = 0; k < n; k++ ) { michael@0: Atmp = Af[ k ]; michael@0: tmp1 += C_last_row[ n - k - 1 ] * Atmp; michael@0: tmp2 += C_first_row[ n - k - 1 ] * Atmp; michael@0: } michael@0: CAf[ n + 1 ] = tmp1; michael@0: CAb[ n + 1 ] = tmp2; michael@0: michael@0: /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ michael@0: num = CAb[ n + 1 ]; michael@0: nrg_b = CAb[ 0 ]; michael@0: nrg_f = CAf[ 0 ]; michael@0: for( k = 0; k < n; k++ ) { michael@0: Atmp = Af[ k ]; michael@0: num += CAb[ n - k ] * Atmp; michael@0: nrg_b += CAb[ k + 1 ] * Atmp; michael@0: nrg_f += CAf[ k + 1 ] * Atmp; michael@0: } michael@0: silk_assert( nrg_f > 0.0 ); michael@0: silk_assert( nrg_b > 0.0 ); michael@0: michael@0: /* Calculate the next order reflection (parcor) coefficient */ michael@0: rc = -2.0 * num / ( nrg_f + nrg_b ); michael@0: silk_assert( rc > -1.0 && rc < 1.0 ); michael@0: michael@0: /* Update inverse prediction gain */ michael@0: tmp1 = invGain * ( 1.0 - rc * rc ); michael@0: if( tmp1 <= minInvGain ) { michael@0: /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ michael@0: rc = sqrt( 1.0 - minInvGain / invGain ); michael@0: if( num > 0 ) { michael@0: /* Ensure adjusted reflection coefficients has the original sign */ michael@0: rc = -rc; michael@0: } michael@0: invGain = minInvGain; michael@0: reached_max_gain = 1; michael@0: } else { michael@0: invGain = tmp1; michael@0: } michael@0: michael@0: /* Update the AR coefficients */ michael@0: for( k = 0; k < (n + 1) >> 1; k++ ) { michael@0: tmp1 = Af[ k ]; michael@0: tmp2 = Af[ n - k - 1 ]; michael@0: Af[ k ] = tmp1 + rc * tmp2; michael@0: Af[ n - k - 1 ] = tmp2 + rc * tmp1; michael@0: } michael@0: Af[ n ] = rc; michael@0: michael@0: if( reached_max_gain ) { michael@0: /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ michael@0: for( k = n + 1; k < D; k++ ) { michael@0: Af[ k ] = 0.0; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: /* Update C * Af and C * Ab */ michael@0: for( k = 0; k <= n + 1; k++ ) { michael@0: tmp1 = CAf[ k ]; michael@0: CAf[ k ] += rc * CAb[ n - k + 1 ]; michael@0: CAb[ n - k + 1 ] += rc * tmp1; michael@0: } michael@0: } michael@0: michael@0: if( reached_max_gain ) { michael@0: /* Convert to silk_float */ michael@0: for( k = 0; k < D; k++ ) { michael@0: A[ k ] = (silk_float)( -Af[ k ] ); michael@0: } michael@0: /* Subtract energy of preceding samples from C0 */ michael@0: for( s = 0; s < nb_subfr; s++ ) { michael@0: C0 -= silk_energy_FLP( x + s * subfr_length, D ); michael@0: } michael@0: /* Approximate residual energy */ michael@0: nrg_f = C0 * invGain; michael@0: } else { michael@0: /* Compute residual energy and store coefficients as silk_float */ michael@0: nrg_f = CAf[ 0 ]; michael@0: tmp1 = 1.0; michael@0: for( k = 0; k < D; k++ ) { michael@0: Atmp = Af[ k ]; michael@0: nrg_f += CAf[ k + 1 ] * Atmp; michael@0: tmp1 += Atmp * Atmp; michael@0: A[ k ] = (silk_float)(-Atmp); michael@0: } michael@0: nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1; michael@0: } michael@0: michael@0: /* Return residual energy */ michael@0: return (silk_float)nrg_f; michael@0: }