📄 lsp.c
字号:
#ifdef FIXED_POINT
dd = MULT16_16_Q15(delta,SUB16(FREQ_SCALE, MULT16_16_Q14(MULT16_16_Q14(xl,xl),14000)));
if (psuml<512 && psuml>-512)
dd = PSHR16(dd,1);
#else
dd=delta*(1-.9*xl*xl);
if (fabs(psuml)<.2)
dd *= .5;
#endif
xr = SUB16(xl, dd); /* interval spacing */
psumr = cheb_poly_eva(pt,xr,m,stack);/* poly(xl-delta_x) */
temp_psumr = psumr;
temp_xr = xr;
/* if no sign change increment xr and re-evaluate poly(xr). Repeat til
sign change.
if a sign change has occurred the interval is bisected and then
checked again for a sign change which determines in which
interval the zero lies in.
If there is no sign change between poly(xm) and poly(xl) set interval
between xm and xr else set interval between xl and xr and repeat till
root is located within the specified limits */
if(SIGN_CHANGE(psumr,psuml))
{
roots++;
psumm=psuml;
for(k=0;k<=nb;k++){
#ifdef FIXED_POINT
xm = ADD16(PSHR16(xl,1),PSHR16(xr,1)); /* bisect the interval */
#else
xm = .5*(xl+xr); /* bisect the interval */
#endif
psumm=cheb_poly_eva(pt,xm,m,stack);
/*if(psumm*psuml>0.)*/
if(!SIGN_CHANGE(psumm,psuml))
{
psuml=psumm;
xl=xm;
} else {
psumr=psumm;
xr=xm;
}
}
/* once zero is found, reset initial interval to xr */
freq[j] = X2ANGLE(xm);
xl = xm;
flag = 0; /* reset flag for next search */
}
else{
psuml=temp_psumr;
xl=temp_xr;
}
}
}
return(roots);
}
/*---------------------------------------------------------------------------*\
FUNCTION....: lsp_to_lpc()
AUTHOR......: David Rowe
DATE CREATED: 24/2/93
Converts LSP coefficients to LPC coefficients.
\*---------------------------------------------------------------------------*/
#ifdef FIXED_POINT
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_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;
}
}
#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;
}
}
#endif
#ifdef FIXED_POINT
/*Makes sure the LSPs are stable*/
void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin)
{
int i;
spx_word16_t m = margin;
spx_word16_t m2 = 25736-margin;
if (lsp[0]<m)
lsp[0]=m;
if (lsp[len-1]>m2)
lsp[len-1]=m2;
for (i=1;i<len-1;i++)
{
if (lsp[i]<lsp[i-1]+m)
lsp[i]=lsp[i-1]+m;
if (lsp[i]>lsp[i+1]-m)
lsp[i]= SHR16(lsp[i],1) + SHR16(lsp[i+1]-m,1);
}
}
void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes)
{
int i;
spx_word16_t tmp = DIV32_16(SHL32(EXTEND32(1 + subframe),14),nb_subframes);
spx_word16_t tmp2 = 16384-tmp;
for (i=0;i<len;i++)
{
interp_lsp[i] = MULT16_16_P14(tmp2,old_lsp[i]) + MULT16_16_P14(tmp,new_lsp[i]);
}
}
#else
/*Makes sure the LSPs are stable*/
void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin)
{
int i;
if (lsp[0]<LSP_SCALING*margin)
lsp[0]=LSP_SCALING*margin;
if (lsp[len-1]>LSP_SCALING*(M_PI-margin))
lsp[len-1]=LSP_SCALING*(M_PI-margin);
for (i=1;i<len-1;i++)
{
if (lsp[i]<lsp[i-1]+LSP_SCALING*margin)
lsp[i]=lsp[i-1]+LSP_SCALING*margin;
if (lsp[i]>lsp[i+1]-LSP_SCALING*margin)
lsp[i]= .5f* (lsp[i] + lsp[i+1]-LSP_SCALING*margin);
}
}
void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes)
{
int i;
float tmp = (1.0f + subframe)/nb_subframes;
for (i=0;i<len;i++)
{
interp_lsp[i] = (1-tmp)*old_lsp[i] + tmp*new_lsp[i];
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -