cannam@154
|
1 /***********************************************************************
|
cannam@154
|
2 Copyright (c) 2006-2011, Skype Limited. All rights reserved.
|
cannam@154
|
3 Redistribution and use in source and binary forms, with or without
|
cannam@154
|
4 modification, are permitted provided that the following conditions
|
cannam@154
|
5 are met:
|
cannam@154
|
6 - Redistributions of source code must retain the above copyright notice,
|
cannam@154
|
7 this list of conditions and the following disclaimer.
|
cannam@154
|
8 - Redistributions in binary form must reproduce the above copyright
|
cannam@154
|
9 notice, this list of conditions and the following disclaimer in the
|
cannam@154
|
10 documentation and/or other materials provided with the distribution.
|
cannam@154
|
11 - Neither the name of Internet Society, IETF or IETF Trust, nor the
|
cannam@154
|
12 names of specific contributors, may be used to endorse or promote
|
cannam@154
|
13 products derived from this software without specific prior written
|
cannam@154
|
14 permission.
|
cannam@154
|
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
cannam@154
|
16 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
cannam@154
|
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
cannam@154
|
18 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
cannam@154
|
19 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
cannam@154
|
20 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
cannam@154
|
21 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
cannam@154
|
22 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
cannam@154
|
23 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
cannam@154
|
24 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
cannam@154
|
25 POSSIBILITY OF SUCH DAMAGE.
|
cannam@154
|
26 ***********************************************************************/
|
cannam@154
|
27
|
cannam@154
|
28 #ifdef HAVE_CONFIG_H
|
cannam@154
|
29 #include "config.h"
|
cannam@154
|
30 #endif
|
cannam@154
|
31
|
cannam@154
|
32 #include "SigProc_FLP.h"
|
cannam@154
|
33 #include "tuning_parameters.h"
|
cannam@154
|
34 #include "define.h"
|
cannam@154
|
35
|
cannam@154
|
36 #define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/
|
cannam@154
|
37
|
cannam@154
|
38 /* Compute reflection coefficients from input signal */
|
cannam@154
|
39 silk_float silk_burg_modified_FLP( /* O returns residual energy */
|
cannam@154
|
40 silk_float A[], /* O prediction coefficients (length order) */
|
cannam@154
|
41 const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */
|
cannam@154
|
42 const silk_float minInvGain, /* I minimum inverse prediction gain */
|
cannam@154
|
43 const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */
|
cannam@154
|
44 const opus_int nb_subfr, /* I number of subframes stacked in x */
|
cannam@154
|
45 const opus_int D /* I order */
|
cannam@154
|
46 )
|
cannam@154
|
47 {
|
cannam@154
|
48 opus_int k, n, s, reached_max_gain;
|
cannam@154
|
49 double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2;
|
cannam@154
|
50 const silk_float *x_ptr;
|
cannam@154
|
51 double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ];
|
cannam@154
|
52 double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ];
|
cannam@154
|
53 double Af[ SILK_MAX_ORDER_LPC ];
|
cannam@154
|
54
|
cannam@154
|
55 celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
|
cannam@154
|
56
|
cannam@154
|
57 /* Compute autocorrelations, added over subframes */
|
cannam@154
|
58 C0 = silk_energy_FLP( x, nb_subfr * subfr_length );
|
cannam@154
|
59 silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) );
|
cannam@154
|
60 for( s = 0; s < nb_subfr; s++ ) {
|
cannam@154
|
61 x_ptr = x + s * subfr_length;
|
cannam@154
|
62 for( n = 1; n < D + 1; n++ ) {
|
cannam@154
|
63 C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n );
|
cannam@154
|
64 }
|
cannam@154
|
65 }
|
cannam@154
|
66 silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) );
|
cannam@154
|
67
|
cannam@154
|
68 /* Initialize */
|
cannam@154
|
69 CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f;
|
cannam@154
|
70 invGain = 1.0f;
|
cannam@154
|
71 reached_max_gain = 0;
|
cannam@154
|
72 for( n = 0; n < D; n++ ) {
|
cannam@154
|
73 /* Update first row of correlation matrix (without first element) */
|
cannam@154
|
74 /* Update last row of correlation matrix (without last element, stored in reversed order) */
|
cannam@154
|
75 /* Update C * Af */
|
cannam@154
|
76 /* Update C * flipud(Af) (stored in reversed order) */
|
cannam@154
|
77 for( s = 0; s < nb_subfr; s++ ) {
|
cannam@154
|
78 x_ptr = x + s * subfr_length;
|
cannam@154
|
79 tmp1 = x_ptr[ n ];
|
cannam@154
|
80 tmp2 = x_ptr[ subfr_length - n - 1 ];
|
cannam@154
|
81 for( k = 0; k < n; k++ ) {
|
cannam@154
|
82 C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ];
|
cannam@154
|
83 C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ];
|
cannam@154
|
84 Atmp = Af[ k ];
|
cannam@154
|
85 tmp1 += x_ptr[ n - k - 1 ] * Atmp;
|
cannam@154
|
86 tmp2 += x_ptr[ subfr_length - n + k ] * Atmp;
|
cannam@154
|
87 }
|
cannam@154
|
88 for( k = 0; k <= n; k++ ) {
|
cannam@154
|
89 CAf[ k ] -= tmp1 * x_ptr[ n - k ];
|
cannam@154
|
90 CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ];
|
cannam@154
|
91 }
|
cannam@154
|
92 }
|
cannam@154
|
93 tmp1 = C_first_row[ n ];
|
cannam@154
|
94 tmp2 = C_last_row[ n ];
|
cannam@154
|
95 for( k = 0; k < n; k++ ) {
|
cannam@154
|
96 Atmp = Af[ k ];
|
cannam@154
|
97 tmp1 += C_last_row[ n - k - 1 ] * Atmp;
|
cannam@154
|
98 tmp2 += C_first_row[ n - k - 1 ] * Atmp;
|
cannam@154
|
99 }
|
cannam@154
|
100 CAf[ n + 1 ] = tmp1;
|
cannam@154
|
101 CAb[ n + 1 ] = tmp2;
|
cannam@154
|
102
|
cannam@154
|
103 /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
|
cannam@154
|
104 num = CAb[ n + 1 ];
|
cannam@154
|
105 nrg_b = CAb[ 0 ];
|
cannam@154
|
106 nrg_f = CAf[ 0 ];
|
cannam@154
|
107 for( k = 0; k < n; k++ ) {
|
cannam@154
|
108 Atmp = Af[ k ];
|
cannam@154
|
109 num += CAb[ n - k ] * Atmp;
|
cannam@154
|
110 nrg_b += CAb[ k + 1 ] * Atmp;
|
cannam@154
|
111 nrg_f += CAf[ k + 1 ] * Atmp;
|
cannam@154
|
112 }
|
cannam@154
|
113 silk_assert( nrg_f > 0.0 );
|
cannam@154
|
114 silk_assert( nrg_b > 0.0 );
|
cannam@154
|
115
|
cannam@154
|
116 /* Calculate the next order reflection (parcor) coefficient */
|
cannam@154
|
117 rc = -2.0 * num / ( nrg_f + nrg_b );
|
cannam@154
|
118 silk_assert( rc > -1.0 && rc < 1.0 );
|
cannam@154
|
119
|
cannam@154
|
120 /* Update inverse prediction gain */
|
cannam@154
|
121 tmp1 = invGain * ( 1.0 - rc * rc );
|
cannam@154
|
122 if( tmp1 <= minInvGain ) {
|
cannam@154
|
123 /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
|
cannam@154
|
124 rc = sqrt( 1.0 - minInvGain / invGain );
|
cannam@154
|
125 if( num > 0 ) {
|
cannam@154
|
126 /* Ensure adjusted reflection coefficients has the original sign */
|
cannam@154
|
127 rc = -rc;
|
cannam@154
|
128 }
|
cannam@154
|
129 invGain = minInvGain;
|
cannam@154
|
130 reached_max_gain = 1;
|
cannam@154
|
131 } else {
|
cannam@154
|
132 invGain = tmp1;
|
cannam@154
|
133 }
|
cannam@154
|
134
|
cannam@154
|
135 /* Update the AR coefficients */
|
cannam@154
|
136 for( k = 0; k < (n + 1) >> 1; k++ ) {
|
cannam@154
|
137 tmp1 = Af[ k ];
|
cannam@154
|
138 tmp2 = Af[ n - k - 1 ];
|
cannam@154
|
139 Af[ k ] = tmp1 + rc * tmp2;
|
cannam@154
|
140 Af[ n - k - 1 ] = tmp2 + rc * tmp1;
|
cannam@154
|
141 }
|
cannam@154
|
142 Af[ n ] = rc;
|
cannam@154
|
143
|
cannam@154
|
144 if( reached_max_gain ) {
|
cannam@154
|
145 /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
|
cannam@154
|
146 for( k = n + 1; k < D; k++ ) {
|
cannam@154
|
147 Af[ k ] = 0.0;
|
cannam@154
|
148 }
|
cannam@154
|
149 break;
|
cannam@154
|
150 }
|
cannam@154
|
151
|
cannam@154
|
152 /* Update C * Af and C * Ab */
|
cannam@154
|
153 for( k = 0; k <= n + 1; k++ ) {
|
cannam@154
|
154 tmp1 = CAf[ k ];
|
cannam@154
|
155 CAf[ k ] += rc * CAb[ n - k + 1 ];
|
cannam@154
|
156 CAb[ n - k + 1 ] += rc * tmp1;
|
cannam@154
|
157 }
|
cannam@154
|
158 }
|
cannam@154
|
159
|
cannam@154
|
160 if( reached_max_gain ) {
|
cannam@154
|
161 /* Convert to silk_float */
|
cannam@154
|
162 for( k = 0; k < D; k++ ) {
|
cannam@154
|
163 A[ k ] = (silk_float)( -Af[ k ] );
|
cannam@154
|
164 }
|
cannam@154
|
165 /* Subtract energy of preceding samples from C0 */
|
cannam@154
|
166 for( s = 0; s < nb_subfr; s++ ) {
|
cannam@154
|
167 C0 -= silk_energy_FLP( x + s * subfr_length, D );
|
cannam@154
|
168 }
|
cannam@154
|
169 /* Approximate residual energy */
|
cannam@154
|
170 nrg_f = C0 * invGain;
|
cannam@154
|
171 } else {
|
cannam@154
|
172 /* Compute residual energy and store coefficients as silk_float */
|
cannam@154
|
173 nrg_f = CAf[ 0 ];
|
cannam@154
|
174 tmp1 = 1.0;
|
cannam@154
|
175 for( k = 0; k < D; k++ ) {
|
cannam@154
|
176 Atmp = Af[ k ];
|
cannam@154
|
177 nrg_f += CAf[ k + 1 ] * Atmp;
|
cannam@154
|
178 tmp1 += Atmp * Atmp;
|
cannam@154
|
179 A[ k ] = (silk_float)(-Atmp);
|
cannam@154
|
180 }
|
cannam@154
|
181 nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1;
|
cannam@154
|
182 }
|
cannam@154
|
183
|
cannam@154
|
184 /* Return residual energy */
|
cannam@154
|
185 return (silk_float)nrg_f;
|
cannam@154
|
186 }
|