void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) /* float *freq array of LSP frequencies in the x domain */ /* float *ak array of LPC coefficients */ /* int lpcrdr order of LPC coefficients */ { int i,j; float xout1,xout2,xin1,xin2; float *Wp; float *pw,*n1,*n2,*n3,*n4=NULL; float *x_freq; int m = lpcrdr>>1; Wp = PUSH(stack, 4*m+2, float); pw = Wp; /* initialise contents of array */ for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ *pw++ = 0.0; } /* Set pointers up */ pw = Wp; xin1 = 1.0; xin2 = 1.0; x_freq=PUSH(stack, lpcrdr, float); for (i=0;i<lpcrdr;i++) x_freq[i] = ANGLE2X(freq[i]); /* reconstruct P(z) and Q(z) by cascading second order polynomials in form 1 - 2xz(-1) +z(-2), where x is the LSP coefficient */ for(j=0;j<=lpcrdr;j++){ int i2=0; for(i=0;i<m;i++,i2+=2){ n1 = pw+(i*4); n2 = n1 + 1; n3 = n2 + 1; n4 = n3 + 1; xout1 = xin1 - 2.f*x_freq[i2] * *n1 + *n2; xout2 = xin2 - 2.f*x_freq[i2+1] * *n3 + *n4; *n2 = *n1; *n4 = *n3; *n1 = xin1; *n3 = xin2; xin1 = xout1; xin2 = xout2; } xout1 = xin1 + *(n4+1); xout2 = xin2 - *(n4+2); ak[j] = (xout1 + xout2)*0.5f; *(n4+1) = xin1; *(n4+2) = xin2; xin1 = 0.0; xin2 = 0.0; } }
void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) /* float *freq array of LSP frequencies in the x domain */ /* float *ak array of LPC coefficients */ /* int lpcrdr order of LPC coefficients */ { int i,j; spx_word32_t xout1,xout2,xin; spx_word32_t mult, a; VARDECL(spx_word32_t *xpmem); VARDECL(spx_word32_t *xqmem); #ifndef FIXED_LPC_SIZE VARDECL(spx_word16_t *freqn); VARDECL(spx_word32_t **xp); VARDECL(spx_word32_t **xq); #else spx_word16_t freqn[FIXED_LPC_SIZE]; spx_word32_t *xp[(FIXED_LPC_SIZE/2)+1]; spx_word32_t *xq[(FIXED_LPC_SIZE/2)+1]; #endif int m = lpcrdr>>1; /* Reconstruct P(z) and Q(z) by cascading second order polynomials in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency. In the time domain this is: y(n) = x(n) - 2cos(w)x(n-1) + x(n-2) This is what the ALLOCS below are trying to do: int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP These matrices store the output of each stage on each row. The final (m-th) row has the output of the final (m-th) cascaded 2nd order filter. The first row is the impulse input to the system (not written as it is known). The version below takes advantage of the fact that a lot of the outputs are zero or known, for example if we put an inpulse into the first section the "clock" it 10 times only the first 3 outputs samples are non-zero (it's an FIR filter). */ #ifndef FIXED_LPC_SIZE ALLOC(xp, (m+1), spx_word32_t*); #endif ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t); #ifndef FIXED_LPC_SIZE ALLOC(xq, (m+1), spx_word32_t*); #endif ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t); #ifndef FIXED_LPC_SIZE for(i=0; i<=m; i++) { xp[i] = xpmem + i*(lpcrdr+1+2); xq[i] = xqmem + i*(lpcrdr+1+2); } #else for(i=0; i<=m; i++) { xp[i] = xpmem + i*(FIXED_LPC_SIZE+1+2); xq[i] = xqmem + i*(FIXED_LPC_SIZE+1+2); } #endif /* work out 2cos terms in Q14 */ #ifndef FIXED_LPC_SIZE ALLOC(freqn, lpcrdr, spx_word16_t); for (i=0;i<lpcrdr;i++) freqn[i] = ANGLE2X(freq[i]); #else for (i=0;i<FIXED_LPC_SIZE;i++) freqn[i] = ANGLE2X(freq[i]); #endif #define QIMP 21 /* scaling for impulse */ xin = SHL32(EXTEND32(1), (QIMP-1)); /* 0.5 in QIMP format */ /* first col and last non-zero values of each row are trivial */ for(i=0;i<=m;i++) { xp[i][1] = 0; xp[i][2] = xin; xp[i][2+2*i] = xin; xq[i][1] = 0; xq[i][2] = xin; xq[i][2+2*i] = xin; } /* 2nd row (first output row) is trivial */ xp[1][3] = -MULT16_32_Q14(freqn[0],xp[0][2]); xq[1][3] = -MULT16_32_Q14(freqn[1],xq[0][2]); xout1 = xout2 = 0; /* now generate remaining rows */ for(i=1;i<m;i++) { for(j=1;j<2*(i+1)-1;j++) { mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); xp[i+1][j+2] = ADD32(SUB32(xp[i][j+2], mult), xp[i][j]); mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); xq[i+1][j+2] = ADD32(SUB32(xq[i][j+2], mult), xq[i][j]); } /* for last col xp[i][j+2] = xq[i][j+2] = 0 */ mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); xp[i+1][j+2] = SUB32(xp[i][j], mult); mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); xq[i+1][j+2] = SUB32(xq[i][j], mult); } /* process last row to extra a{k} */ #ifndef FIXED_LPC_SIZE for(j=1;j<=lpcrdr;j++) { #else for(j=1;j<=FIXED_LPC_SIZE;j++) { #endif int shift = QIMP-13; /* final filter sections */ a = PSHR32(xp[m][j+2] + xout1 + xq[m][j+2] - xout2, shift); xout1 = xp[m][j+2]; xout2 = xq[m][j+2]; /* hard limit ak's to +/- 32767 */ if (a < -32767) a = -32767; if (a > 32767) a = 32767; ak[j-1] = (short)a; } } #else void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) /* float *freq array of LSP frequencies in the x domain */ /* float *ak array of LPC coefficients */ /* int lpcrdr order of LPC coefficients */ { int i,j; float xout1,xout2,xin1,xin2; VARDECL(float *Wp); float *pw,*n1,*n2,*n3,*n4=NULL; VARDECL(float *x_freq); int m = lpcrdr>>1; ALLOC(Wp, 4*m+2, float); pw = Wp; /* initialise contents of array */ for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ *pw++ = 0.0; } /* Set pointers up */ pw = Wp; xin1 = 1.0; xin2 = 1.0; ALLOC(x_freq, lpcrdr, float); for (i=0;i<lpcrdr;i++) x_freq[i] = ANGLE2X(freq[i]); /* reconstruct P(z) and Q(z) by cascading second order polynomials in form 1 - 2xz(-1) +z(-2), where x is the LSP coefficient */ for(j=0;j<=lpcrdr;j++){ int i2=0; for(i=0;i<m;i++,i2+=2){ n1 = pw+(i*4); n2 = n1 + 1; n3 = n2 + 1; n4 = n3 + 1; xout1 = xin1 - 2.f*x_freq[i2] * *n1 + *n2; xout2 = xin2 - 2.f*x_freq[i2+1] * *n3 + *n4; *n2 = *n1; *n4 = *n3; *n1 = xin1; *n3 = xin2; xin1 = xout1; xin2 = xout2; } xout1 = xin1 + *(n4+1); xout2 = xin2 - *(n4+2); if (j>0) ak[j-1] = (xout1 + xout2)*0.5f; *(n4+1) = xin1; *(n4+2) = xin2; xin1 = 0.0; xin2 = 0.0; } }
void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) /* float *freq array of LSP frequencies in the x domain */ /* float *ak array of LPC coefficients */ /* int lpcrdr order of LPC coefficients */ { int i,j; spx_word32_t xout1,xout2,xin1,xin2; spx_word32_t *Wp; spx_word32_t *pw,*n1,*n2,*n3,*n4=NULL; spx_word16_t *freqn; int m = lpcrdr>>1; freqn = PUSH(stack, lpcrdr, spx_word16_t); for (i=0;i<lpcrdr;i++) freqn[i] = ANGLE2X(freq[i]); Wp = PUSH(stack, 4*m+2, spx_word32_t); pw = Wp; /* initialise contents of array */ for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */ *pw++ = 0; } /* Set pointers up */ pw = Wp; xin1 = 1048576; xin2 = 1048576; /* reconstruct P(z) and Q(z) by cascading second order polynomials in form 1 - 2xz(-1) +z(-2), where x is the LSP coefficient */ for(j=0;j<=lpcrdr;j++){ spx_word16_t *fr=freqn; for(i=0;i<m;i++){ n1 = pw+(i<<2); n2 = n1 + 1; n3 = n2 + 1; n4 = n3 + 1; xout1 = ADD32(SUB32(xin1, MULT16_32_Q14(*fr,*n1)), *n2); fr++; xout2 = ADD32(SUB32(xin2, MULT16_32_Q14(*fr,*n3)), *n4); fr++; *n2 = *n1; *n4 = *n3; *n1 = xin1; *n3 = xin2; xin1 = xout1; xin2 = xout2; } xout1 = xin1 + *(n4+1); xout2 = xin2 - *(n4+2); /* FIXME: perhaps apply bandwidth expansion in case of overflow? */ if (xout1 + xout2>256*32766) ak[j] = 32767; else if (xout1 + xout2 < -256*32767) ak[j] = -32768; else ak[j] = PSHR(ADD32(xout1,xout2),8); *(n4+1) = xin1; *(n4+2) = xin2; xin1 = 0; xin2 = 0; } }
void lsp_to_lpc(const spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack) /* float *freq array of LSP frequencies in the x domain */ /* float *ak array of LPC coefficients */ /* int lpcrdr order of LPC coefficients */ { int i,j; spx_word32_t xout1,xout2,xin; spx_word32_t mult, a; VARDECL(spx_word16_t *freqn); VARDECL(spx_word32_t **xp); VARDECL(spx_word32_t *xpmem); VARDECL(spx_word32_t **xq); VARDECL(spx_word32_t *xqmem); int m = lpcrdr>>1; /* Reconstruct P(z) and Q(z) by cascading second order polynomials in form 1 - 2cos(w)z(-1) + z(-2), where w is the LSP frequency. In the time domain this is: y(n) = x(n) - 2cos(w)x(n-1) + x(n-2) This is what the ALLOCS below are trying to do: int xp[m+1][lpcrdr+1+2]; // P matrix in QIMP int xq[m+1][lpcrdr+1+2]; // Q matrix in QIMP These matrices store the output of each stage on each row. The final (m-th) row has the output of the final (m-th) cascaded 2nd order filter. The first row is the impulse input to the system (not written as it is known). The version below takes advantage of the fact that a lot of the outputs are zero or known, for example if we put an inpulse into the first section the "clock" it 10 times only the first 3 outputs samples are non-zero (it's an FIR filter). */ ALLOC(xp, (m+1), spx_word32_t*); ALLOC(xpmem, (m+1)*(lpcrdr+1+2), spx_word32_t); ALLOC(xq, (m+1), spx_word32_t*); ALLOC(xqmem, (m+1)*(lpcrdr+1+2), spx_word32_t); for(i=0; i<=m; i++) { xp[i] = xpmem + i*(lpcrdr+1+2); xq[i] = xqmem + i*(lpcrdr+1+2); } /* work out 2cos terms in Q14 */ ALLOC(freqn, lpcrdr, spx_word16_t); for (i=0;i<lpcrdr;i++) freqn[i] = ANGLE2X(freq[i]); #define QIMP 21 /* scaling for impulse */ xin = SHL32(EXTEND32(1), (QIMP-1)); /* 0.5 in QIMP format */ /* first col and last non-zero values of each row are trivial */ for(i=0;i<=m;i++) { xp[i][1] = 0; xp[i][2] = xin; xp[i][2+2*i] = xin; xq[i][1] = 0; xq[i][2] = xin; xq[i][2+2*i] = xin; } /* 2nd row (first output row) is trivial */ xp[1][3] = -MULT16_32_Q14(freqn[0],xp[0][2]); xq[1][3] = -MULT16_32_Q14(freqn[1],xq[0][2]); xout1 = xout2 = 0; /* now generate remaining rows */ for(i=1;i<m;i++) { for(j=1;j<2*(i+1)-1;j++) { mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); xp[i+1][j+2] = ADD32(SUB32(xp[i][j+2], mult), xp[i][j]); mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); xq[i+1][j+2] = ADD32(SUB32(xq[i][j+2], mult), xq[i][j]); } /* for last col xp[i][j+2] = xq[i][j+2] = 0 */ mult = MULT16_32_Q14(freqn[2*i],xp[i][j+1]); xp[i+1][j+2] = SUB32(xp[i][j], mult); mult = MULT16_32_Q14(freqn[2*i+1],xq[i][j+1]); xq[i+1][j+2] = SUB32(xq[i][j], mult); } /* process last row to extra a{k} */ for(j=1;j<=lpcrdr;j++) { int shift = QIMP-13; /* final filter sections */ a = PSHR32(xp[m][j+2] + xout1 + xq[m][j+2] - xout2, shift); xout1 = xp[m][j+2]; xout2 = xq[m][j+2]; /* hard limit ak's to +/- 32767 */ if (a < -32767) a = -32767; if (a > 32767) a = 32767; ak[j-1] = (short)a; } }