/src/speex/libspeex/lsp.c
Line | Count | Source |
1 | | /*---------------------------------------------------------------------------*\ |
2 | | Original copyright |
3 | | FILE........: lsp.c |
4 | | AUTHOR......: David Rowe |
5 | | DATE CREATED: 24/2/93 |
6 | | |
7 | | Heavily modified by Jean-Marc Valin (c) 2002-2006 (fixed-point, |
8 | | optimizations, additional functions, ...) |
9 | | |
10 | | This file contains functions for converting Linear Prediction |
11 | | Coefficients (LPC) to Line Spectral Pair (LSP) and back. Note that the |
12 | | LSP coefficients are not in radians format but in the x domain of the |
13 | | unit circle. |
14 | | |
15 | | Speex License: |
16 | | |
17 | | Redistribution and use in source and binary forms, with or without |
18 | | modification, are permitted provided that the following conditions |
19 | | are met: |
20 | | |
21 | | - Redistributions of source code must retain the above copyright |
22 | | notice, this list of conditions and the following disclaimer. |
23 | | |
24 | | - Redistributions in binary form must reproduce the above copyright |
25 | | notice, this list of conditions and the following disclaimer in the |
26 | | documentation and/or other materials provided with the distribution. |
27 | | |
28 | | - Neither the name of the Xiph.org Foundation nor the names of its |
29 | | contributors may be used to endorse or promote products derived from |
30 | | this software without specific prior written permission. |
31 | | |
32 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
33 | | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
34 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
35 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
36 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
37 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
38 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
39 | | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
40 | | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
41 | | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
42 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
43 | | */ |
44 | | |
45 | | /*---------------------------------------------------------------------------*\ |
46 | | |
47 | | Introduction to Line Spectrum Pairs (LSPs) |
48 | | ------------------------------------------ |
49 | | |
50 | | LSPs are used to encode the LPC filter coefficients {ak} for |
51 | | transmission over the channel. LSPs have several properties (like |
52 | | less sensitivity to quantisation noise) that make them superior to |
53 | | direct quantisation of {ak}. |
54 | | |
55 | | A(z) is a polynomial of order lpcrdr with {ak} as the coefficients. |
56 | | |
57 | | A(z) is transformed to P(z) and Q(z) (using a substitution and some |
58 | | algebra), to obtain something like: |
59 | | |
60 | | A(z) = 0.5[P(z)(z+z^-1) + Q(z)(z-z^-1)] (1) |
61 | | |
62 | | As you can imagine A(z) has complex zeros all over the z-plane. P(z) |
63 | | and Q(z) have the very neat property of only having zeros _on_ the |
64 | | unit circle. So to find them we take a test point z=exp(jw) and |
65 | | evaluate P (exp(jw)) and Q(exp(jw)) using a grid of points between 0 |
66 | | and pi. |
67 | | |
68 | | The zeros (roots) of P(z) also happen to alternate, which is why we |
69 | | swap coefficients as we find roots. So the process of finding the |
70 | | LSP frequencies is basically finding the roots of 5th order |
71 | | polynomials. |
72 | | |
73 | | The root so P(z) and Q(z) occur in symmetrical pairs at +/-w, hence |
74 | | the name Line Spectrum Pairs (LSPs). |
75 | | |
76 | | To convert back to ak we just evaluate (1), "clocking" an impulse |
77 | | thru it lpcrdr times gives us the impulse response of A(z) which is |
78 | | {ak}. |
79 | | |
80 | | \*---------------------------------------------------------------------------*/ |
81 | | |
82 | | #ifdef HAVE_CONFIG_H |
83 | | #include "config.h" |
84 | | #endif |
85 | | |
86 | | #include <math.h> |
87 | | #include "lsp.h" |
88 | | #include "stack_alloc.h" |
89 | | #include "math_approx.h" |
90 | | |
91 | | #ifndef M_PI |
92 | | #define M_PI 3.14159265358979323846 /* pi */ |
93 | | #endif |
94 | | |
95 | | #ifndef NULL |
96 | | #define NULL 0 |
97 | | #endif |
98 | | |
99 | | #ifdef FIXED_POINT |
100 | | |
101 | 494k | #define FREQ_SCALE 16384 |
102 | | |
103 | | /*#define ANGLE2X(a) (32768*cos(((a)/8192.)))*/ |
104 | 1.66M | #define ANGLE2X(a) (SHL16(spx_cos(a),2)) |
105 | | |
106 | | /*#define X2ANGLE(x) (acos(.00006103515625*(x))*LSP_SCALING)*/ |
107 | 201k | #define X2ANGLE(x) (spx_acos(x)) |
108 | | |
109 | | #ifdef BFIN_ASM |
110 | | #include "lsp_bfin.h" |
111 | | #endif |
112 | | |
113 | | #else |
114 | | |
115 | | /*#define C1 0.99940307 |
116 | | #define C2 -0.49558072 |
117 | | #define C3 0.03679168*/ |
118 | | |
119 | | #define FREQ_SCALE 1. |
120 | | #define ANGLE2X(a) (spx_cos(a)) |
121 | | #define X2ANGLE(x) (acos(x)) |
122 | | |
123 | | #endif |
124 | | |
125 | | #ifndef DISABLE_ENCODER |
126 | | |
127 | | /*---------------------------------------------------------------------------*\ |
128 | | |
129 | | FUNCTION....: cheb_poly_eva() |
130 | | |
131 | | AUTHOR......: David Rowe |
132 | | DATE CREATED: 24/2/93 |
133 | | |
134 | | This function evaluates a series of Chebyshev polynomials |
135 | | |
136 | | \*---------------------------------------------------------------------------*/ |
137 | | |
138 | | #ifdef FIXED_POINT |
139 | | |
140 | | #ifndef OVERRIDE_CHEB_POLY_EVA |
141 | | static inline spx_word32_t cheb_poly_eva( |
142 | | spx_word16_t *coef, /* P or Q coefs in Q13 format */ |
143 | | spx_word16_t x, /* cos of freq (-1.0 to 1.0) in Q14 format */ |
144 | | int m, /* LPC order/2 */ |
145 | | char *stack |
146 | | ) |
147 | 2.88M | { |
148 | 2.88M | int i; |
149 | 2.88M | spx_word16_t b0, b1; |
150 | 2.88M | spx_word32_t sum; |
151 | | |
152 | | /*Prevents overflows*/ |
153 | 2.88M | if (x>16383) |
154 | 21.4k | x = 16383; |
155 | 2.88M | if (x<-16383) |
156 | 1.91k | x = -16383; |
157 | | |
158 | | /* Initialise values */ |
159 | 2.88M | b1=16384; |
160 | 2.88M | b0=x; |
161 | | |
162 | | /* Evaluate Chebyshev series formulation using an iterative approach */ |
163 | 2.88M | sum = ADD32(EXTEND32(coef[m]), EXTEND32(MULT16_16_P14(coef[m-1],x))); |
164 | 13.7M | for(i=2;i<=m;i++) |
165 | 10.9M | { |
166 | 10.9M | spx_word16_t tmp=b0; |
167 | 10.9M | b0 = SUB16(MULT16_16_Q13(x,b0), b1); |
168 | 10.9M | b1 = tmp; |
169 | 10.9M | sum = ADD32(sum, EXTEND32(MULT16_16_P14(coef[m-i],b0))); |
170 | 10.9M | } |
171 | | |
172 | 2.88M | return sum; |
173 | 2.88M | } |
174 | | #endif |
175 | | |
176 | | #else |
177 | | |
178 | | static float cheb_poly_eva(spx_word32_t *coef, spx_word16_t x, int m, char *stack) |
179 | | { |
180 | | int k; |
181 | | float b0, b1, tmp; |
182 | | |
183 | | /* Initial conditions */ |
184 | | b0=0; /* b_(m+1) */ |
185 | | b1=0; /* b_(m+2) */ |
186 | | |
187 | | x*=2; |
188 | | |
189 | | /* Calculate the b_(k) */ |
190 | | for(k=m;k>0;k--) |
191 | | { |
192 | | tmp=b0; /* tmp holds the previous value of b0 */ |
193 | | b0=x*b0-b1+coef[m-k]; /* b0 holds its new value based on b0 and b1 */ |
194 | | b1=tmp; /* b1 holds the previous value of b0 */ |
195 | | } |
196 | | |
197 | | return(-b1+.5*x*b0+coef[m]); |
198 | | } |
199 | | #endif |
200 | | |
201 | | /*---------------------------------------------------------------------------*\ |
202 | | |
203 | | FUNCTION....: lpc_to_lsp() |
204 | | |
205 | | AUTHOR......: David Rowe |
206 | | DATE CREATED: 24/2/93 |
207 | | |
208 | | This function converts LPC coefficients to LSP |
209 | | coefficients. |
210 | | |
211 | | \*---------------------------------------------------------------------------*/ |
212 | | |
213 | | #ifdef FIXED_POINT |
214 | 2.68M | #define SIGN_CHANGE(a,b) ((((a)^(b))&0x80000000)||(b==0)) |
215 | | #else |
216 | | #define SIGN_CHANGE(a,b) (((a)*(b))<0.0) |
217 | | #endif |
218 | | |
219 | | |
220 | | int lpc_to_lsp (spx_coef_t *a,int lpcrdr,spx_lsp_t *freq,int nb,spx_word16_t delta, char *stack) |
221 | | /* float *a lpc coefficients */ |
222 | | /* int lpcrdr order of LPC coefficients (10) */ |
223 | | /* float *freq LSP frequencies in the x domain */ |
224 | | /* int nb number of sub-intervals (4) */ |
225 | | /* float delta grid spacing interval (0.02) */ |
226 | | |
227 | | |
228 | 21.3k | { |
229 | 21.3k | spx_word16_t temp_xr,xl,xr,xm=0; |
230 | 21.3k | spx_word32_t psuml,psumr,psumm,temp_psumr/*,temp_qsumr*/; |
231 | 21.3k | int i,j,m,k; |
232 | 21.3k | VARDECL(spx_word32_t *Q); /* ptrs for memory allocation */ |
233 | 21.3k | VARDECL(spx_word32_t *P); |
234 | 21.3k | VARDECL(spx_word16_t *Q16); /* ptrs for memory allocation */ |
235 | 21.3k | VARDECL(spx_word16_t *P16); |
236 | 21.3k | spx_word32_t *px; /* ptrs of respective P'(z) & Q'(z) */ |
237 | 21.3k | spx_word32_t *qx; |
238 | 21.3k | spx_word32_t *p; |
239 | 21.3k | spx_word32_t *q; |
240 | 21.3k | spx_word16_t *pt; /* ptr used for cheb_poly_eval() |
241 | | whether P' or Q' */ |
242 | 21.3k | int roots=0; /* DR 8/2/94: number of roots found */ |
243 | 21.3k | m = lpcrdr/2; /* order of P'(z) & Q'(z) polynomials */ |
244 | | |
245 | | /* Allocate memory space for polynomials */ |
246 | 21.3k | ALLOC(Q, (m+1), spx_word32_t); |
247 | 21.3k | ALLOC(P, (m+1), spx_word32_t); |
248 | | |
249 | | /* determine P'(z)'s and Q'(z)'s coefficients where |
250 | | P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */ |
251 | | |
252 | 21.3k | px = P; /* initialise ptrs */ |
253 | 21.3k | qx = Q; |
254 | 21.3k | p = px; |
255 | 21.3k | q = qx; |
256 | | |
257 | 21.3k | #ifdef FIXED_POINT |
258 | 21.3k | *px++ = LPC_SCALING; |
259 | 21.3k | *qx++ = LPC_SCALING; |
260 | 122k | for(i=0;i<m;i++){ |
261 | 101k | *px++ = SUB32(ADD32(EXTEND32(a[i]),EXTEND32(a[lpcrdr-i-1])), *p++); |
262 | 101k | *qx++ = ADD32(SUB32(EXTEND32(a[i]),EXTEND32(a[lpcrdr-i-1])), *q++); |
263 | 101k | } |
264 | 21.3k | px = P; |
265 | 21.3k | qx = Q; |
266 | 122k | for(i=0;i<m;i++) |
267 | 101k | { |
268 | | /*if (fabs(*px)>=32768) |
269 | | speex_warning_int("px", *px); |
270 | | if (fabs(*qx)>=32768) |
271 | | speex_warning_int("qx", *qx);*/ |
272 | 101k | *px = PSHR32(*px,2); |
273 | 101k | *qx = PSHR32(*qx,2); |
274 | 101k | px++; |
275 | 101k | qx++; |
276 | 101k | } |
277 | | /* The reason for this lies in the way cheb_poly_eva() is implemented for fixed-point */ |
278 | 21.3k | P[m] = PSHR32(P[m],3); |
279 | 21.3k | Q[m] = PSHR32(Q[m],3); |
280 | | #else |
281 | | *px++ = LPC_SCALING; |
282 | | *qx++ = LPC_SCALING; |
283 | | for(i=0;i<m;i++){ |
284 | | *px++ = (a[i]+a[lpcrdr-1-i]) - *p++; |
285 | | *qx++ = (a[i]-a[lpcrdr-1-i]) + *q++; |
286 | | } |
287 | | px = P; |
288 | | qx = Q; |
289 | | for(i=0;i<m;i++){ |
290 | | *px = 2**px; |
291 | | *qx = 2**qx; |
292 | | px++; |
293 | | qx++; |
294 | | } |
295 | | #endif |
296 | | |
297 | 21.3k | px = P; /* re-initialise ptrs */ |
298 | 21.3k | qx = Q; |
299 | | |
300 | | /* now that we have computed P and Q convert to 16 bits to |
301 | | speed up cheb_poly_eval */ |
302 | | |
303 | 21.3k | ALLOC(P16, m+1, spx_word16_t); |
304 | 21.3k | ALLOC(Q16, m+1, spx_word16_t); |
305 | | |
306 | 144k | for (i=0;i<m+1;i++) |
307 | 122k | { |
308 | 122k | P16[i] = P[i]; |
309 | 122k | Q16[i] = Q[i]; |
310 | 122k | } |
311 | | |
312 | | /* Search for a zero in P'(z) polynomial first and then alternate to Q'(z). |
313 | | Keep alternating between the two polynomials as each zero is found */ |
314 | | |
315 | 21.3k | xr = 0; /* initialise xr to zero */ |
316 | 21.3k | xl = FREQ_SCALE; /* start at point xl = 1 */ |
317 | | |
318 | 223k | for(j=0;j<lpcrdr;j++){ |
319 | 202k | if(j&1) /* determines whether P' or Q' is eval. */ |
320 | 101k | pt = Q16; |
321 | 101k | else |
322 | 101k | pt = P16; |
323 | | |
324 | 202k | psuml = cheb_poly_eva(pt,xl,m,stack); /* evals poly. at xl */ |
325 | | |
326 | 473k | while(xr >= -FREQ_SCALE){ |
327 | 472k | spx_word16_t dd; |
328 | | /* Modified by JMV to provide smaller steps around x=+-1 */ |
329 | 472k | #ifdef FIXED_POINT |
330 | 472k | dd = MULT16_16_Q15(delta,SUB16(FREQ_SCALE, MULT16_16_Q14(MULT16_16_Q14(xl,xl),14000))); |
331 | 472k | if (psuml<512 && psuml>-512) |
332 | 91.4k | dd = PSHR16(dd,1); |
333 | | #else |
334 | | dd=delta*(1-.9*xl*xl); |
335 | | if (fabs(psuml)<.2) |
336 | | dd *= .5; |
337 | | #endif |
338 | 472k | xr = SUB16(xl, dd); /* interval spacing */ |
339 | 472k | psumr = cheb_poly_eva(pt,xr,m,stack);/* poly(xl-delta_x) */ |
340 | 472k | temp_psumr = psumr; |
341 | 472k | temp_xr = xr; |
342 | | |
343 | | /* if no sign change increment xr and re-evaluate poly(xr). Repeat til |
344 | | sign change. |
345 | | if a sign change has occurred the interval is bisected and then |
346 | | checked again for a sign change which determines in which |
347 | | interval the zero lies in. |
348 | | If there is no sign change between poly(xm) and poly(xl) set interval |
349 | | between xm and xr else set interval between xl and xr and repeat till |
350 | | root is located within the specified limits */ |
351 | | |
352 | 472k | if(SIGN_CHANGE(psumr,psuml)) |
353 | 201k | { |
354 | 201k | roots++; |
355 | | |
356 | 201k | psumm=psuml; |
357 | 2.41M | for(k=0;k<=nb;k++){ |
358 | 2.21M | #ifdef FIXED_POINT |
359 | 2.21M | xm = ADD16(PSHR16(xl,1),PSHR16(xr,1)); /* bisect the interval */ |
360 | | #else |
361 | | xm = .5*(xl+xr); /* bisect the interval */ |
362 | | #endif |
363 | 2.21M | psumm=cheb_poly_eva(pt,xm,m,stack); |
364 | | /*if(psumm*psuml>0.)*/ |
365 | 2.21M | if(!SIGN_CHANGE(psumm,psuml)) |
366 | 1.19M | { |
367 | 1.19M | psuml=psumm; |
368 | 1.19M | xl=xm; |
369 | 1.19M | } else { |
370 | 1.02M | psumr=psumm; |
371 | 1.02M | xr=xm; |
372 | 1.02M | } |
373 | 2.21M | } |
374 | | |
375 | | /* once zero is found, reset initial interval to xr */ |
376 | 201k | freq[j] = X2ANGLE(xm); |
377 | 201k | xl = xm; |
378 | 201k | break; |
379 | 201k | } |
380 | 270k | else{ |
381 | 270k | psuml=temp_psumr; |
382 | 270k | xl=temp_xr; |
383 | 270k | } |
384 | 472k | } |
385 | 202k | } |
386 | 21.3k | return(roots); |
387 | 21.3k | } |
388 | | |
389 | | #endif /* DISABLE_ENCODER */ |
390 | | /*---------------------------------------------------------------------------*\ |
391 | | |
392 | | FUNCTION....: lsp_to_lpc() |
393 | | |
394 | | AUTHOR......: David Rowe |
395 | | DATE CREATED: 24/2/93 |
396 | | |
397 | | Converts LSP coefficients to LPC coefficients. |
398 | | |
399 | | \*---------------------------------------------------------------------------*/ |
400 | | |
401 | | #ifdef FIXED_POINT |
402 | | |
403 | | void lsp_to_lpc(const spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) |
404 | | /* float *freq array of LSP frequencies in the x domain */ |
405 | | /* float *ak array of LPC coefficients */ |
406 | | /* int lpcrdr order of LPC coefficients */ |
407 | 174k | { |
408 | 174k | int i,j; |
409 | 174k | spx_word32_t xout1,xout2,xin; |
410 | 174k | spx_word32_t mult, a; |
411 | 174k | VARDECL(spx_word16_t *freqn); |
412 | 174k | VARDECL(spx_word32_t **xp); |
413 | 174k | VARDECL(spx_word32_t *xpmem); |
414 | 174k | VARDECL(spx_word32_t **xq); |
415 | 174k | VARDECL(spx_word32_t *xqmem); |
416 | 174k | int m = lpcrdr>>1; |
417 | | |
418 | | /* |
419 | | |
420 | | Reconstruct P(z) and Q(z) by cascading second order polynomials |
421 | | in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency. |
422 | | In the time domain this is: |
423 | | |
424 | | y(n) = x(n) - 2cos(w)x(n-1) + x(n-2) |
425 | | |
426 | | This is what the ALLOCS below are trying to do: |
427 | | |
428 | | int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP |
429 | | int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP |
430 | | |
431 | | These matrices store the output of each stage on each row. The |
432 | | final (m-th) row has the output of the final (m-th) cascaded |
433 | | 2nd order filter. The first row is the impulse input to the |
434 | | system (not written as it is known). |
435 | | |
436 | | The version below takes advantage of the fact that a lot of the |
437 | | outputs are zero or known, for example if we put an inpulse |
438 | | into the first section the "clock" it 10 times only the first 3 |
439 | | outputs samples are non-zero (it's an FIR filter). |
440 | | */ |
441 | | |
442 | 174k | ALLOC(xp, (m+1), spx_word32_t*); |
443 | 174k | ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t); |
444 | | |
445 | 174k | ALLOC(xq, (m+1), spx_word32_t*); |
446 | 174k | ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t); |
447 | | |
448 | 1.18M | for(i=0; i<=m; i++) { |
449 | 1.00M | xp[i] = xpmem + i*(lpcrdr+1+2); |
450 | 1.00M | xq[i] = xqmem + i*(lpcrdr+1+2); |
451 | 1.00M | } |
452 | | |
453 | | /* work out 2cos terms in Q14 */ |
454 | | |
455 | 174k | ALLOC(freqn, lpcrdr, spx_word16_t); |
456 | 1.84M | for (i=0;i<lpcrdr;i++) |
457 | 1.66M | freqn[i] = ANGLE2X(freq[i]); |
458 | | |
459 | 1.66M | #define QIMP 21 /* scaling for impulse */ |
460 | | |
461 | 174k | xin = SHL32(EXTEND32(1), (QIMP-1)); /* 0.5 in QIMP format */ |
462 | | |
463 | | /* first col and last non-zero values of each row are trivial */ |
464 | | |
465 | 1.18M | for(i=0;i<=m;i++) { |
466 | 1.00M | xp[i][1] = 0; |
467 | 1.00M | xp[i][2] = xin; |
468 | 1.00M | xp[i][2+2*i] = xin; |
469 | 1.00M | xq[i][1] = 0; |
470 | 1.00M | xq[i][2] = xin; |
471 | 1.00M | xq[i][2+2*i] = xin; |
472 | 1.00M | } |
473 | | |
474 | | /* 2nd row (first output row) is trivial */ |
475 | | |
476 | 174k | xp[1][3] = -MULT16_32_Q14(freqn[0],xp[0][2]); |
477 | 174k | xq[1][3] = -MULT16_32_Q14(freqn[1],xq[0][2]); |
478 | | |
479 | 174k | xout1 = xout2 = 0; |
480 | | |
481 | | /* now generate remaining rows */ |
482 | | |
483 | 833k | for(i=1;i<m;i++) { |
484 | | |
485 | 3.83M | for(j=1;j<2*(i+1)-1;j++) { |
486 | 3.17M | mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); |
487 | 3.17M | xp[i+1][j+2] = ADD32(SUB32(xp[i][j+2], mult), xp[i][j]); |
488 | 3.17M | mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); |
489 | 3.17M | xq[i+1][j+2] = ADD32(SUB32(xq[i][j+2], mult), xq[i][j]); |
490 | 3.17M | } |
491 | | |
492 | | /* for last col xp[i][j+2] = xq[i][j+2] = 0 */ |
493 | | |
494 | 658k | mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); |
495 | 658k | xp[i+1][j+2] = SUB32(xp[i][j], mult); |
496 | 658k | mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); |
497 | 658k | xq[i+1][j+2] = SUB32(xq[i][j], mult); |
498 | 658k | } |
499 | | |
500 | | /* process last row to extra a{k} */ |
501 | | |
502 | 1.84M | for(j=1;j<=lpcrdr;j++) { |
503 | 1.66M | int shift = QIMP-13; |
504 | | |
505 | | /* final filter sections */ |
506 | 1.66M | a = PSHR32(xp[m][j+2] + xout1 + xq[m][j+2] - xout2, shift); |
507 | 1.66M | xout1 = xp[m][j+2]; |
508 | 1.66M | xout2 = xq[m][j+2]; |
509 | | |
510 | | /* hard limit ak's to +/- 32767 */ |
511 | | |
512 | 1.66M | if (a < -32767) a = -32767; |
513 | 1.66M | if (a > 32767) a = 32767; |
514 | 1.66M | ak[j-1] = (short)a; |
515 | | |
516 | 1.66M | } |
517 | | |
518 | 174k | } |
519 | | |
520 | | #else |
521 | | |
522 | | void lsp_to_lpc(const spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) |
523 | | /* float *freq array of LSP frequencies in the x domain */ |
524 | | /* float *ak array of LPC coefficients */ |
525 | | /* int lpcrdr order of LPC coefficients */ |
526 | | |
527 | | |
528 | | { |
529 | | int i,j; |
530 | | float xout1,xout2,xin1,xin2; |
531 | | VARDECL(float *Wp); |
532 | | float *pw,*n1,*n2,*n3,*n4=NULL; |
533 | | VARDECL(float *x_freq); |
534 | | int m = lpcrdr>>1; |
535 | | |
536 | | ALLOC(Wp, 4*m+2, float); |
537 | | pw = Wp; |
538 | | |
539 | | /* initialise contents of array */ |
540 | | |
541 | | for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ |
542 | | *pw++ = 0.0; |
543 | | } |
544 | | |
545 | | /* Set pointers up */ |
546 | | |
547 | | pw = Wp; |
548 | | xin1 = 1.0; |
549 | | xin2 = 1.0; |
550 | | |
551 | | ALLOC(x_freq, lpcrdr, float); |
552 | | for (i=0;i<lpcrdr;i++) |
553 | | x_freq[i] = ANGLE2X(freq[i]); |
554 | | |
555 | | /* reconstruct P(z) and Q(z) by cascading second order |
556 | | polynomials in form 1 - 2xz(-1) +z(-2), where x is the |
557 | | LSP coefficient */ |
558 | | |
559 | | for(j=0;j<=lpcrdr;j++){ |
560 | | int i2=0; |
561 | | for(i=0;i<m;i++,i2+=2){ |
562 | | n1 = pw+(i*4); |
563 | | n2 = n1 + 1; |
564 | | n3 = n2 + 1; |
565 | | n4 = n3 + 1; |
566 | | xout1 = xin1 - 2.f*x_freq[i2] * *n1 + *n2; |
567 | | xout2 = xin2 - 2.f*x_freq[i2+1] * *n3 + *n4; |
568 | | *n2 = *n1; |
569 | | *n4 = *n3; |
570 | | *n1 = xin1; |
571 | | *n3 = xin2; |
572 | | xin1 = xout1; |
573 | | xin2 = xout2; |
574 | | } |
575 | | xout1 = xin1 + *(n4+1); |
576 | | xout2 = xin2 - *(n4+2); |
577 | | if (j>0) |
578 | | ak[j-1] = (xout1 + xout2)*0.5f; |
579 | | *(n4+1) = xin1; |
580 | | *(n4+2) = xin2; |
581 | | |
582 | | xin1 = 0.0; |
583 | | xin2 = 0.0; |
584 | | } |
585 | | |
586 | | } |
587 | | #endif |
588 | | |
589 | | |
590 | | #ifdef FIXED_POINT |
591 | | |
592 | | |
593 | | void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *lsp, int len, int subframe, int nb_subframes, spx_word16_t margin) |
594 | 171k | { |
595 | 171k | int i; |
596 | 171k | spx_word16_t m = margin; |
597 | 171k | spx_word16_t m2 = 25736-margin; |
598 | 171k | spx_word16_t tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes); |
599 | 171k | spx_word16_t tmp2 = 16384-tmp; |
600 | 1.81M | for (i=0;i<len;i++) |
601 | 1.63M | lsp[i] = MULT16_16_P14(tmp2,old_lsp[i]) + MULT16_16_P14(tmp,new_lsp[i]); |
602 | | /* Enforce margin to sure the LSPs are stable*/ |
603 | 171k | if (lsp[0]<m) |
604 | 40 | lsp[0]=m; |
605 | 171k | if (lsp[len-1]>m2) |
606 | 37 | lsp[len-1]=m2; |
607 | 1.46M | for (i=1;i<len-1;i++) |
608 | 1.29M | { |
609 | 1.29M | if (lsp[i]<lsp[i-1]+m) |
610 | 3.09k | lsp[i]=lsp[i-1]+m; |
611 | | |
612 | 1.29M | if (lsp[i]>lsp[i+1]-m) |
613 | 3.46k | lsp[i]= SHR16(lsp[i],1) + SHR16(lsp[i+1]-m,1); |
614 | 1.29M | } |
615 | 171k | } |
616 | | |
617 | | #else |
618 | | |
619 | | |
620 | | void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *lsp, int len, int subframe, int nb_subframes, spx_word16_t margin) |
621 | | { |
622 | | int i; |
623 | | float tmp = (1.0f + subframe)/nb_subframes; |
624 | | for (i=0;i<len;i++) |
625 | | lsp[i] = (1-tmp)*old_lsp[i] + tmp*new_lsp[i]; |
626 | | /* Enforce margin to sure the LSPs are stable*/ |
627 | | if (lsp[0]<LSP_SCALING*margin) |
628 | | lsp[0]=LSP_SCALING*margin; |
629 | | if (lsp[len-1]>LSP_SCALING*(M_PI-margin)) |
630 | | lsp[len-1]=LSP_SCALING*(M_PI-margin); |
631 | | for (i=1;i<len-1;i++) |
632 | | { |
633 | | if (lsp[i]<lsp[i-1]+LSP_SCALING*margin) |
634 | | lsp[i]=lsp[i-1]+LSP_SCALING*margin; |
635 | | |
636 | | if (lsp[i]>lsp[i+1]-LSP_SCALING*margin) |
637 | | lsp[i]= .5f* (lsp[i] + lsp[i+1]-LSP_SCALING*margin); |
638 | | } |
639 | | } |
640 | | |
641 | | #endif |