Changeset 628 for pjproject/trunk/pjmedia/src/pjmedia-codec/speex/lsp.c
- Timestamp:
- Jul 26, 2006 5:04:54 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia-codec/speex/lsp.c
r278 r628 1 1 /*---------------------------------------------------------------------------*\ 2 2 Original copyright 3 FILE........: AKSLSPD.C 4 TYPE........: Turbo C 5 COMPANY.....: Voicetronix 3 FILE........: lsp.c 6 4 AUTHOR......: David Rowe 7 5 DATE CREATED: 24/2/93 … … 45 43 */ 46 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 47 82 #ifdef HAVE_CONFIG_H 48 83 #include "config.h" … … 64 99 #ifdef FIXED_POINT 65 100 66 67 68 101 #define FREQ_SCALE 16384 69 102 … … 73 106 /*#define X2ANGLE(x) (acos(.00006103515625*(x))*LSP_SCALING)*/ 74 107 #define X2ANGLE(x) (spx_acos(x)) 108 109 #ifdef BFIN_ASM 110 #include "lsp_bfin.h" 111 #endif 75 112 76 113 #else … … 89 126 /*---------------------------------------------------------------------------*\ 90 127 91 92 93 94 95 96 128 FUNCTION....: cheb_poly_eva() 129 130 AUTHOR......: David Rowe 131 DATE CREATED: 24/2/93 132 133 This function evaluates a series of Chebyshev polynomials 97 134 98 135 \*---------------------------------------------------------------------------*/ … … 100 137 #ifdef FIXED_POINT 101 138 102 static inline spx_word32_t cheb_poly_eva(spx_word32_t *coef,spx_word16_t x,int m,char *stack) 103 /* float coef[] coefficients of the polynomial to be evaluated */ 104 /* float x the point where polynomial is to be evaluated */ 105 /* int m order of the polynomial */ 139 #ifndef OVERRIDE_CHEB_POLY_EVA 140 static inline spx_word32_t cheb_poly_eva( 141 spx_word16_t *coef, /* P or Q coefs in Q13 format */ 142 spx_word16_t x, /* cos of freq (-1.0 to 1.0) in Q14 format */ 143 int m, /* LPC order/2 */ 144 char *stack 145 ) 106 146 { 107 147 int i; 108 VARDECL(spx_word16_t *T);148 spx_word16_t b0, b1; 109 149 spx_word32_t sum; 110 int m2=m>>1;111 VARDECL(spx_word16_t *coefn);112 150 113 151 /*Prevents overflows*/ … … 117 155 x = -16383; 118 156 119 /* Allocate memory for Chebyshev series formulation */ 120 ALLOC(T, m2+1, spx_word16_t); 121 ALLOC(coefn, m2+1, spx_word16_t); 122 123 for (i=0;i<m2+1;i++) 157 /* Initialise values */ 158 b1=16384; 159 b0=x; 160 161 /* Evaluate Chebyshev series formulation usin g iterative approach */ 162 sum = ADD32(EXTEND32(coef[m]), EXTEND32(MULT16_16_P14(coef[m-1],x))); 163 for(i=2;i<=m;i++) 124 164 { 125 coefn[i] = coef[i]; 126 /*printf ("%f ", coef[i]);*/ 127 } 128 /*printf ("\n");*/ 129 130 /* Initialise values */ 131 T[0]=16384; 132 T[1]=x; 133 134 /* Evaluate Chebyshev series formulation using iterative approach */ 135 /* Evaluate polynomial and return value also free memory space */ 136 sum = ADD32(EXTEND32(coefn[m2]), EXTEND32(MULT16_16_P14(coefn[m2-1],x))); 137 /*x *= 2;*/ 138 for(i=2;i<=m2;i++) 139 { 140 T[i] = SUB16(MULT16_16_Q13(x,T[i-1]), T[i-2]); 141 sum = ADD32(sum, EXTEND32(MULT16_16_P14(coefn[m2-i],T[i]))); 142 /*printf ("%f ", sum);*/ 143 } 144 145 /*printf ("\n");*/ 146 return sum; 147 } 148 #else 149 static float cheb_poly_eva(spx_word32_t *coef,float x,int m,char *stack) 150 /* float coef[] coefficients of the polynomial to be evaluated */ 151 /* float x the point where polynomial is to be evaluated */ 152 /* int m order of the polynomial */ 153 { 154 int i; 155 VARDECL(float *T); 156 float sum; 157 int m2=m>>1; 158 159 /* Allocate memory for Chebyshev series formulation */ 160 ALLOC(T, m2+1, float); 161 162 /* Initialise values */ 163 T[0]=1; 164 T[1]=x; 165 166 /* Evaluate Chebyshev series formulation using iterative approach */ 167 /* Evaluate polynomial and return value also free memory space */ 168 sum = coef[m2] + coef[m2-1]*x; 169 x *= 2; 170 for(i=2;i<=m2;i++) 171 { 172 T[i] = x*T[i-1] - T[i-2]; 173 sum += coef[m2-i] * T[i]; 165 spx_word16_t tmp=b0; 166 b0 = SUB16(MULT16_16_Q13(x,b0), b1); 167 b1 = tmp; 168 sum = ADD32(sum, EXTEND32(MULT16_16_P14(coef[m-i],b0))); 174 169 } 175 170 … … 178 173 #endif 179 174 175 #else 176 177 static float cheb_poly_eva(spx_word32_t *coef, spx_word16_t x, int m, char *stack) 178 { 179 int k; 180 float b0, b1, tmp; 181 182 /* Initial conditions */ 183 b0=0; /* b_(m+1) */ 184 b1=0; /* b_(m+2) */ 185 186 x*=2; 187 188 /* Calculate the b_(k) */ 189 for(k=m;k>0;k--) 190 { 191 tmp=b0; /* tmp holds the previous value of b0 */ 192 b0=x*b0-b1+coef[m-k]; /* b0 holds its new value based on b0 and b1 */ 193 b1=tmp; /* b1 holds the previous value of b0 */ 194 } 195 196 return(-b1+.5*x*b0+coef[m]); 197 } 198 #endif 199 180 200 /*---------------------------------------------------------------------------*\ 181 201 182 183 184 185 202 FUNCTION....: lpc_to_lsp() 203 204 AUTHOR......: David Rowe 205 DATE CREATED: 24/2/93 186 206 187 207 This function converts LPC coefficients to LSP … … 211 231 VARDECL(spx_word32_t *Q); /* ptrs for memory allocation */ 212 232 VARDECL(spx_word32_t *P); 233 VARDECL(spx_word16_t *Q16); /* ptrs for memory allocation */ 234 VARDECL(spx_word16_t *P16); 213 235 spx_word32_t *px; /* ptrs of respective P'(z) & Q'(z) */ 214 236 spx_word32_t *qx; 215 237 spx_word32_t *p; 216 238 spx_word32_t *q; 217 spx_word 32_t *pt; /* ptr used for cheb_poly_eval()239 spx_word16_t *pt; /* ptr used for cheb_poly_eval() 218 240 whether P' or Q' */ 219 241 int roots=0; /* DR 8/2/94: number of roots found */ … … 277 299 qx = Q; 278 300 301 /* now that we have computed P and Q convert to 16 bits to 302 speed up cheb_poly_eval */ 303 304 ALLOC(P16, m+1, spx_word16_t); 305 ALLOC(Q16, m+1, spx_word16_t); 306 307 for (i=0;i<m+1;i++) 308 { 309 P16[i] = P[i]; 310 Q16[i] = Q[i]; 311 } 312 279 313 /* Search for a zero in P'(z) polynomial first and then alternate to Q'(z). 280 314 Keep alternating between the two polynomials as each zero is found */ … … 283 317 xl = FREQ_SCALE; /* start at point xl = 1 */ 284 318 285 286 319 for(j=0;j<lpcrdr;j++){ 287 320 if(j&1) /* determines whether P' or Q' is eval. */ 288 pt = qx;321 pt = Q16; 289 322 else 290 pt = px;291 292 psuml = cheb_poly_eva(pt,xl, lpcrdr,stack); /* evals poly. at xl */323 pt = P16; 324 325 psuml = cheb_poly_eva(pt,xl,m,stack); /* evals poly. at xl */ 293 326 flag = 1; 294 327 while(flag && (xr >= -FREQ_SCALE)){ … … 305 338 #endif 306 339 xr = SUB16(xl, dd); /* interval spacing */ 307 psumr = cheb_poly_eva(pt,xr, lpcrdr,stack);/* poly(xl-delta_x) */340 psumr = cheb_poly_eva(pt,xr,m,stack);/* poly(xl-delta_x) */ 308 341 temp_psumr = psumr; 309 342 temp_xr = xr; … … 329 362 xm = .5*(xl+xr); /* bisect the interval */ 330 363 #endif 331 psumm=cheb_poly_eva(pt,xm, lpcrdr,stack);364 psumm=cheb_poly_eva(pt,xm,m,stack); 332 365 /*if(psumm*psuml>0.)*/ 333 366 if(!SIGN_CHANGE(psumm,psuml)) … … 355 388 } 356 389 357 358 390 /*---------------------------------------------------------------------------*\ 359 391 … … 363 395 DATE CREATED: 24/2/93 364 396 365 lsp_to_lpc: This function converts LSP coefficients to LPC 366 coefficients. 397 Converts LSP coefficients to LPC coefficients. 367 398 368 399 \*---------------------------------------------------------------------------*/ … … 374 405 /* float *ak array of LPC coefficients */ 375 406 /* int lpcrdr order of LPC coefficients */ 376 377 378 407 { 379 408 int i,j; 380 spx_word32_t xout1,xout2,xin1,xin2; 381 VARDECL(spx_word32_t *Wp); 382 spx_word32_t *pw,*n1,*n2,*n3,*n4=NULL; 409 spx_word32_t xout1,xout2,xin; 410 spx_word32_t mult, a; 383 411 VARDECL(spx_word16_t *freqn); 412 VARDECL(spx_word32_t **xp); 413 VARDECL(spx_word32_t *xpmem); 414 VARDECL(spx_word32_t **xq); 415 VARDECL(spx_word32_t *xqmem); 384 416 int m = lpcrdr>>1; 417 418 /* 385 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 ALLOC(xp, (m+1), spx_word32_t*); 443 ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t); 444 445 ALLOC(xq, (m+1), spx_word32_t*); 446 ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t); 447 448 for(i=0; i<=m; i++) { 449 xp[i] = xpmem + i*(lpcrdr+1+2); 450 xq[i] = xqmem + i*(lpcrdr+1+2); 451 } 452 453 /* work out 2cos terms in Q14 */ 454 386 455 ALLOC(freqn, lpcrdr, spx_word16_t); 387 for (i=0;i<lpcrdr;i++) 456 for (i=0;i<lpcrdr;i++) 388 457 freqn[i] = ANGLE2X(freq[i]); 389 458 390 ALLOC(Wp, 4*m+2, spx_word32_t); 391 pw = Wp; 392 393 394 /* initialise contents of array */ 395 396 for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ 397 *pw++ = 0; 398 } 399 400 /* Set pointers up */ 401 402 pw = Wp; 403 xin1 = 1048576; 404 xin2 = 1048576; 405 406 /* reconstruct P(z) and Q(z) by cascading second order 407 polynomials in form 1 - 2xz(-1) +z(-2), where x is the 408 LSP coefficient */ 409 410 for(j=0;j<=lpcrdr;j++){ 411 spx_word16_t *fr=freqn; 412 for(i=0;i<m;i++){ 413 n1 = pw+(i<<2); 414 n2 = n1 + 1; 415 n3 = n2 + 1; 416 n4 = n3 + 1; 417 xout1 = ADD32(SUB32(xin1, MULT16_32_Q14(*fr,*n1)), *n2); 418 fr++; 419 xout2 = ADD32(SUB32(xin2, MULT16_32_Q14(*fr,*n3)), *n4); 420 fr++; 421 *n2 = *n1; 422 *n4 = *n3; 423 *n1 = xin1; 424 *n3 = xin2; 425 xin1 = xout1; 426 xin2 = xout2; 427 } 428 xout1 = xin1 + *(n4+1); 429 xout2 = xin2 - *(n4+2); 430 /* FIXME: perhaps apply bandwidth expansion in case of overflow? */ 431 if (j>0) 432 { 433 if (xout1 + xout2>SHL32(EXTEND32(32766),8)) 434 ak[j-1] = 32767; 435 else if (xout1 + xout2 < -SHL32(EXTEND32(32766),8)) 436 ak[j-1] = -32767; 437 else 438 ak[j-1] = EXTRACT16(PSHR32(ADD32(xout1,xout2),8)); 439 } else {/*speex_warning_int("ak[0] = ", EXTRACT16(PSHR32(ADD32(xout1,xout2),8)));*/} 440 *(n4+1) = xin1; 441 *(n4+2) = xin2; 442 443 xin1 = 0; 444 xin2 = 0; 445 } 446 } 459 #define QIMP 21 /* scaling for impulse */ 460 461 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 for(i=0;i<=m;i++) { 466 xp[i][1] = 0; 467 xp[i][2] = xin; 468 xp[i][2+2*i] = xin; 469 xq[i][1] = 0; 470 xq[i][2] = xin; 471 xq[i][2+2*i] = xin; 472 } 473 474 /* 2nd row (first output row) is trivial */ 475 476 xp[1][3] = -MULT16_32_Q14(freqn[0],xp[0][2]); 477 xq[1][3] = -MULT16_32_Q14(freqn[1],xq[0][2]); 478 479 xout1 = xout2 = 0; 480 481 /* now generate remaining rows */ 482 483 for(i=1;i<m;i++) { 484 485 for(j=1;j<2*(i+1)-1;j++) { 486 mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); 487 xp[i+1][j+2] = ADD32(SUB32(xp[i][j+2], mult), xp[i][j]); 488 mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); 489 xq[i+1][j+2] = ADD32(SUB32(xq[i][j+2], mult), xq[i][j]); 490 } 491 492 /* for last col xp[i][j+2] = xq[i][j+2] = 0 */ 493 494 mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); 495 xp[i+1][j+2] = SUB32(xp[i][j], mult); 496 mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); 497 xq[i+1][j+2] = SUB32(xq[i][j], mult); 498 } 499 500 /* process last row to extra a{k} */ 501 502 for(j=1;j<=lpcrdr;j++) { 503 int shift = QIMP-13; 504 505 /* final filter sections */ 506 a = PSHR32(xp[m][j+2] + xout1 + xq[m][j+2] - xout2, shift); 507 xout1 = xp[m][j+2]; 508 xout2 = xq[m][j+2]; 509 510 /* hard limit ak's to +/- 32767 */ 511 512 if (a < -32767) a = 32767; 513 if (a > 32767) a = 32767; 514 ak[j-1] = (short)a; 515 516 } 517 518 } 519 447 520 #else 448 521
Note: See TracChangeset
for help on using the changeset viewer.