Chris@69
|
1 /***********************************************************************
|
Chris@69
|
2 Copyright (c) 2006-2011, Skype Limited. All rights reserved.
|
Chris@69
|
3 Redistribution and use in source and binary forms, with or without
|
Chris@69
|
4 modification, are permitted provided that the following conditions
|
Chris@69
|
5 are met:
|
Chris@69
|
6 - Redistributions of source code must retain the above copyright notice,
|
Chris@69
|
7 this list of conditions and the following disclaimer.
|
Chris@69
|
8 - Redistributions in binary form must reproduce the above copyright
|
Chris@69
|
9 notice, this list of conditions and the following disclaimer in the
|
Chris@69
|
10 documentation and/or other materials provided with the distribution.
|
Chris@69
|
11 - Neither the name of Internet Society, IETF or IETF Trust, nor the
|
Chris@69
|
12 names of specific contributors, may be used to endorse or promote
|
Chris@69
|
13 products derived from this software without specific prior written
|
Chris@69
|
14 permission.
|
Chris@69
|
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
Chris@69
|
16 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
Chris@69
|
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
Chris@69
|
18 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
Chris@69
|
19 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
Chris@69
|
20 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
Chris@69
|
21 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
Chris@69
|
22 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
Chris@69
|
23 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
Chris@69
|
24 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
Chris@69
|
25 POSSIBILITY OF SUCH DAMAGE.
|
Chris@69
|
26 ***********************************************************************/
|
Chris@69
|
27
|
Chris@69
|
28 /* Conversion between prediction filter coefficients and NLSFs */
|
Chris@69
|
29 /* Requires the order to be an even number */
|
Chris@69
|
30 /* A piecewise linear approximation maps LSF <-> cos(LSF) */
|
Chris@69
|
31 /* Therefore the result is not accurate NLSFs, but the two */
|
Chris@69
|
32 /* functions are accurate inverses of each other */
|
Chris@69
|
33
|
Chris@69
|
34 #ifdef HAVE_CONFIG_H
|
Chris@69
|
35 #include "config.h"
|
Chris@69
|
36 #endif
|
Chris@69
|
37
|
Chris@69
|
38 #include "SigProc_FIX.h"
|
Chris@69
|
39 #include "tables.h"
|
Chris@69
|
40
|
Chris@69
|
41 /* Number of binary divisions, when not in low complexity mode */
|
Chris@69
|
42 #define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */
|
Chris@69
|
43 #define MAX_ITERATIONS_A2NLSF_FIX 16
|
Chris@69
|
44
|
Chris@69
|
45 /* Helper function for A2NLSF(..) */
|
Chris@69
|
46 /* Transforms polynomials from cos(n*f) to cos(f)^n */
|
Chris@69
|
47 static OPUS_INLINE void silk_A2NLSF_trans_poly(
|
Chris@69
|
48 opus_int32 *p, /* I/O Polynomial */
|
Chris@69
|
49 const opus_int dd /* I Polynomial order (= filter order / 2 ) */
|
Chris@69
|
50 )
|
Chris@69
|
51 {
|
Chris@69
|
52 opus_int k, n;
|
Chris@69
|
53
|
Chris@69
|
54 for( k = 2; k <= dd; k++ ) {
|
Chris@69
|
55 for( n = dd; n > k; n-- ) {
|
Chris@69
|
56 p[ n - 2 ] -= p[ n ];
|
Chris@69
|
57 }
|
Chris@69
|
58 p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 );
|
Chris@69
|
59 }
|
Chris@69
|
60 }
|
Chris@69
|
61 /* Helper function for A2NLSF(..) */
|
Chris@69
|
62 /* Polynomial evaluation */
|
Chris@69
|
63 static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */
|
Chris@69
|
64 opus_int32 *p, /* I Polynomial, Q16 */
|
Chris@69
|
65 const opus_int32 x, /* I Evaluation point, Q12 */
|
Chris@69
|
66 const opus_int dd /* I Order */
|
Chris@69
|
67 )
|
Chris@69
|
68 {
|
Chris@69
|
69 opus_int n;
|
Chris@69
|
70 opus_int32 x_Q16, y32;
|
Chris@69
|
71
|
Chris@69
|
72 y32 = p[ dd ]; /* Q16 */
|
Chris@69
|
73 x_Q16 = silk_LSHIFT( x, 4 );
|
Chris@69
|
74
|
Chris@69
|
75 if ( opus_likely( 8 == dd ) )
|
Chris@69
|
76 {
|
Chris@69
|
77 y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 );
|
Chris@69
|
78 y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 );
|
Chris@69
|
79 y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 );
|
Chris@69
|
80 y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 );
|
Chris@69
|
81 y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 );
|
Chris@69
|
82 y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 );
|
Chris@69
|
83 y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 );
|
Chris@69
|
84 y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 );
|
Chris@69
|
85 }
|
Chris@69
|
86 else
|
Chris@69
|
87 {
|
Chris@69
|
88 for( n = dd - 1; n >= 0; n-- ) {
|
Chris@69
|
89 y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */
|
Chris@69
|
90 }
|
Chris@69
|
91 }
|
Chris@69
|
92 return y32;
|
Chris@69
|
93 }
|
Chris@69
|
94
|
Chris@69
|
95 static OPUS_INLINE void silk_A2NLSF_init(
|
Chris@69
|
96 const opus_int32 *a_Q16,
|
Chris@69
|
97 opus_int32 *P,
|
Chris@69
|
98 opus_int32 *Q,
|
Chris@69
|
99 const opus_int dd
|
Chris@69
|
100 )
|
Chris@69
|
101 {
|
Chris@69
|
102 opus_int k;
|
Chris@69
|
103
|
Chris@69
|
104 /* Convert filter coefs to even and odd polynomials */
|
Chris@69
|
105 P[dd] = silk_LSHIFT( 1, 16 );
|
Chris@69
|
106 Q[dd] = silk_LSHIFT( 1, 16 );
|
Chris@69
|
107 for( k = 0; k < dd; k++ ) {
|
Chris@69
|
108 P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */
|
Chris@69
|
109 Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */
|
Chris@69
|
110 }
|
Chris@69
|
111
|
Chris@69
|
112 /* Divide out zeros as we have that for even filter orders, */
|
Chris@69
|
113 /* z = 1 is always a root in Q, and */
|
Chris@69
|
114 /* z = -1 is always a root in P */
|
Chris@69
|
115 for( k = dd; k > 0; k-- ) {
|
Chris@69
|
116 P[ k - 1 ] -= P[ k ];
|
Chris@69
|
117 Q[ k - 1 ] += Q[ k ];
|
Chris@69
|
118 }
|
Chris@69
|
119
|
Chris@69
|
120 /* Transform polynomials from cos(n*f) to cos(f)^n */
|
Chris@69
|
121 silk_A2NLSF_trans_poly( P, dd );
|
Chris@69
|
122 silk_A2NLSF_trans_poly( Q, dd );
|
Chris@69
|
123 }
|
Chris@69
|
124
|
Chris@69
|
125 /* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */
|
Chris@69
|
126 /* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
|
Chris@69
|
127 void silk_A2NLSF(
|
Chris@69
|
128 opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
|
Chris@69
|
129 opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */
|
Chris@69
|
130 const opus_int d /* I Filter order (must be even) */
|
Chris@69
|
131 )
|
Chris@69
|
132 {
|
Chris@69
|
133 opus_int i, k, m, dd, root_ix, ffrac;
|
Chris@69
|
134 opus_int32 xlo, xhi, xmid;
|
Chris@69
|
135 opus_int32 ylo, yhi, ymid, thr;
|
Chris@69
|
136 opus_int32 nom, den;
|
Chris@69
|
137 opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ];
|
Chris@69
|
138 opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
|
Chris@69
|
139 opus_int32 *PQ[ 2 ];
|
Chris@69
|
140 opus_int32 *p;
|
Chris@69
|
141
|
Chris@69
|
142 /* Store pointers to array */
|
Chris@69
|
143 PQ[ 0 ] = P;
|
Chris@69
|
144 PQ[ 1 ] = Q;
|
Chris@69
|
145
|
Chris@69
|
146 dd = silk_RSHIFT( d, 1 );
|
Chris@69
|
147
|
Chris@69
|
148 silk_A2NLSF_init( a_Q16, P, Q, dd );
|
Chris@69
|
149
|
Chris@69
|
150 /* Find roots, alternating between P and Q */
|
Chris@69
|
151 p = P; /* Pointer to polynomial */
|
Chris@69
|
152
|
Chris@69
|
153 xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
|
Chris@69
|
154 ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
|
Chris@69
|
155
|
Chris@69
|
156 if( ylo < 0 ) {
|
Chris@69
|
157 /* Set the first NLSF to zero and move on to the next */
|
Chris@69
|
158 NLSF[ 0 ] = 0;
|
Chris@69
|
159 p = Q; /* Pointer to polynomial */
|
Chris@69
|
160 ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
|
Chris@69
|
161 root_ix = 1; /* Index of current root */
|
Chris@69
|
162 } else {
|
Chris@69
|
163 root_ix = 0; /* Index of current root */
|
Chris@69
|
164 }
|
Chris@69
|
165 k = 1; /* Loop counter */
|
Chris@69
|
166 i = 0; /* Counter for bandwidth expansions applied */
|
Chris@69
|
167 thr = 0;
|
Chris@69
|
168 while( 1 ) {
|
Chris@69
|
169 /* Evaluate polynomial */
|
Chris@69
|
170 xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */
|
Chris@69
|
171 yhi = silk_A2NLSF_eval_poly( p, xhi, dd );
|
Chris@69
|
172
|
Chris@69
|
173 /* Detect zero crossing */
|
Chris@69
|
174 if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) {
|
Chris@69
|
175 if( yhi == 0 ) {
|
Chris@69
|
176 /* If the root lies exactly at the end of the current */
|
Chris@69
|
177 /* interval, look for the next root in the next interval */
|
Chris@69
|
178 thr = 1;
|
Chris@69
|
179 } else {
|
Chris@69
|
180 thr = 0;
|
Chris@69
|
181 }
|
Chris@69
|
182 /* Binary division */
|
Chris@69
|
183 ffrac = -256;
|
Chris@69
|
184 for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) {
|
Chris@69
|
185 /* Evaluate polynomial */
|
Chris@69
|
186 xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 );
|
Chris@69
|
187 ymid = silk_A2NLSF_eval_poly( p, xmid, dd );
|
Chris@69
|
188
|
Chris@69
|
189 /* Detect zero crossing */
|
Chris@69
|
190 if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) {
|
Chris@69
|
191 /* Reduce frequency */
|
Chris@69
|
192 xhi = xmid;
|
Chris@69
|
193 yhi = ymid;
|
Chris@69
|
194 } else {
|
Chris@69
|
195 /* Increase frequency */
|
Chris@69
|
196 xlo = xmid;
|
Chris@69
|
197 ylo = ymid;
|
Chris@69
|
198 ffrac = silk_ADD_RSHIFT( ffrac, 128, m );
|
Chris@69
|
199 }
|
Chris@69
|
200 }
|
Chris@69
|
201
|
Chris@69
|
202 /* Interpolate */
|
Chris@69
|
203 if( silk_abs( ylo ) < 65536 ) {
|
Chris@69
|
204 /* Avoid dividing by zero */
|
Chris@69
|
205 den = ylo - yhi;
|
Chris@69
|
206 nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 );
|
Chris@69
|
207 if( den != 0 ) {
|
Chris@69
|
208 ffrac += silk_DIV32( nom, den );
|
Chris@69
|
209 }
|
Chris@69
|
210 } else {
|
Chris@69
|
211 /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */
|
Chris@69
|
212 ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) );
|
Chris@69
|
213 }
|
Chris@69
|
214 NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX );
|
Chris@69
|
215
|
Chris@69
|
216 silk_assert( NLSF[ root_ix ] >= 0 );
|
Chris@69
|
217
|
Chris@69
|
218 root_ix++; /* Next root */
|
Chris@69
|
219 if( root_ix >= d ) {
|
Chris@69
|
220 /* Found all roots */
|
Chris@69
|
221 break;
|
Chris@69
|
222 }
|
Chris@69
|
223 /* Alternate pointer to polynomial */
|
Chris@69
|
224 p = PQ[ root_ix & 1 ];
|
Chris@69
|
225
|
Chris@69
|
226 /* Evaluate polynomial */
|
Chris@69
|
227 xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/
|
Chris@69
|
228 ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 );
|
Chris@69
|
229 } else {
|
Chris@69
|
230 /* Increment loop counter */
|
Chris@69
|
231 k++;
|
Chris@69
|
232 xlo = xhi;
|
Chris@69
|
233 ylo = yhi;
|
Chris@69
|
234 thr = 0;
|
Chris@69
|
235
|
Chris@69
|
236 if( k > LSF_COS_TAB_SZ_FIX ) {
|
Chris@69
|
237 i++;
|
Chris@69
|
238 if( i > MAX_ITERATIONS_A2NLSF_FIX ) {
|
Chris@69
|
239 /* Set NLSFs to white spectrum and exit */
|
Chris@69
|
240 NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 );
|
Chris@69
|
241 for( k = 1; k < d; k++ ) {
|
Chris@69
|
242 NLSF[ k ] = (opus_int16)silk_ADD16( NLSF[ k-1 ], NLSF[ 0 ] );
|
Chris@69
|
243 }
|
Chris@69
|
244 return;
|
Chris@69
|
245 }
|
Chris@69
|
246
|
Chris@69
|
247 /* Error: Apply progressively more bandwidth expansion and run again */
|
Chris@69
|
248 silk_bwexpander_32( a_Q16, d, 65536 - silk_LSHIFT( 1, i ) );
|
Chris@69
|
249
|
Chris@69
|
250 silk_A2NLSF_init( a_Q16, P, Q, dd );
|
Chris@69
|
251 p = P; /* Pointer to polynomial */
|
Chris@69
|
252 xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
|
Chris@69
|
253 ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
|
Chris@69
|
254 if( ylo < 0 ) {
|
Chris@69
|
255 /* Set the first NLSF to zero and move on to the next */
|
Chris@69
|
256 NLSF[ 0 ] = 0;
|
Chris@69
|
257 p = Q; /* Pointer to polynomial */
|
Chris@69
|
258 ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
|
Chris@69
|
259 root_ix = 1; /* Index of current root */
|
Chris@69
|
260 } else {
|
Chris@69
|
261 root_ix = 0; /* Index of current root */
|
Chris@69
|
262 }
|
Chris@69
|
263 k = 1; /* Reset loop counter */
|
Chris@69
|
264 }
|
Chris@69
|
265 }
|
Chris@69
|
266 }
|
Chris@69
|
267 }
|