--- /dev/null
+/*---------------------------------------------------------------------------*\\r
+\r
+ FILE........: lsp.c\r
+ AUTHOR......: David Rowe\r
+ DATE CREATED: 24/2/93\r
+\r
+\r
+ This file contains functions for LPC to LSP conversion and LSP to\r
+ LPC conversion. Note that the LSP coefficients are not in radians\r
+ format but in the x domain of the unit circle.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+#include "lsp.h"\r
+#include <math.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+/*---------------------------------------------------------------------------*\\r
+\r
+ FUNCTION....: cheb_poly_eva()\r
+ AUTHOR......: David Rowe\r
+ DATE CREATED: 24/2/93\r
+\r
+ This function evalutes a series of chebyshev polynomials\r
+\r
+ FIXME: performing memory allocation at run time is very inefficient,\r
+ replace with stack variables of MAX_P size.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+\r
+float cheb_poly_eva(float *coef,float x,int m)\r
+/* float coef[] coefficients of the polynomial to be evaluated */\r
+/* float x the point where polynomial is to be evaluated */\r
+/* int m order of the polynomial */\r
+{\r
+ int i;\r
+ float *T,*t,*u,*v,sum;\r
+\r
+ /* Allocate memory for chebyshev series formulation */\r
+\r
+ if((T = (float *)malloc((m/2+1)*sizeof(float))) == NULL){\r
+ printf("not enough memory to allocate buffer\n");\r
+ exit(1);\r
+ }\r
+\r
+ /* Initialise pointers */\r
+\r
+ t = T; /* T[i-2] */\r
+ *t++ = 1.0;\r
+ u = t--; /* T[i-1] */\r
+ *u++ = x;\r
+ v = u--; /* T[i] */\r
+\r
+ /* Evaluate chebyshev series formulation using iterative approach */\r
+\r
+ for(i=2;i<=m/2;i++)\r
+ *v++ = (2*x)*(*u++) - *t++; /* T[i] = 2*x*T[i-1] - T[i-2] */\r
+\r
+ sum=0.0; /* initialise sum to zero */\r
+ t = T; /* reset pointer */\r
+\r
+ /* Evaluate polynomial and return value also free memory space */\r
+\r
+ for(i=0;i<=m/2;i++)\r
+ sum+=coef[(m/2)-i]**t++;\r
+\r
+ free(T);\r
+ return sum;\r
+}\r
+\r
+\r
+/*---------------------------------------------------------------------------*\\r
+\r
+ FUNCTION....: lpc_to_lsp()\r
+ AUTHOR......: David Rowe\r
+ DATE CREATED: 24/2/93\r
+\r
+ This function converts LPC coefficients to LSP coefficients.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+int lpc_to_lsp (float *a,int lpcrdr,float *freq,int nb,float delta)\r
+/* float *a lpc coefficients */\r
+/* int lpcrdr order of LPC coefficients (10) */\r
+/* float *freq LSP frequencies in the x domain */\r
+/* int nb number of sub-intervals (4) */\r
+/* float delta grid spacing interval (0.02) */\r
+{\r
+ float psuml,psumr,psumm,temp_xr,xl,xr,xm;\r
+ float temp_psumr;\r
+ int i,j,m,flag,k;\r
+ float *Q; /* ptrs for memory allocation */\r
+ float *P;\r
+ float *px; /* ptrs of respective P'(z) & Q'(z) */\r
+ float *qx;\r
+ float *p;\r
+ float *q;\r
+ float *pt; /* ptr used for cheb_poly_eval()\r
+ whether P' or Q' */\r
+ int roots=0; /* number of roots found */\r
+ flag = 1; \r
+ m = lpcrdr/2; /* order of P'(z) & Q'(z) polynimials */\r
+\r
+ /* Allocate memory space for polynomials */\r
+\r
+ if((Q = (float *) malloc((m+1)*sizeof(float))) == NULL){\r
+ printf("not enough memory to allocate buffer\n");\r
+ exit(1);\r
+ }\r
+\r
+ if((P = (float *) malloc((m+1)*sizeof(float))) == NULL){\r
+ printf("not enough memory to allocate buffer\n");\r
+ exit(1);\r
+ }\r
+\r
+ /* determine P'(z)'s and Q'(z)'s coefficients where\r
+ P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */\r
+\r
+ px = P; /* initilaise ptrs */\r
+ qx = Q;\r
+ p = px;\r
+ q = qx;\r
+ *px++ = 1.0;\r
+ *qx++ = 1.0;\r
+ for(i=1;i<=m;i++){\r
+ *px++ = a[i]+a[lpcrdr+1-i]-*p++;\r
+ *qx++ = a[i]-a[lpcrdr+1-i]+*q++;\r
+ }\r
+ px = P;\r
+ qx = Q;\r
+ for(i=0;i<m;i++){\r
+ *px = 2**px;\r
+ *qx = 2**qx;\r
+ px++;\r
+ qx++;\r
+ }\r
+ px = P; /* re-initialise ptrs */\r
+ qx = Q;\r
+\r
+ /* Search for a zero in P'(z) polynomial first and then alternate to Q'(z).\r
+ Keep alternating between the two polynomials as each zero is found */\r
+\r
+ xr = 0; /* initialise xr to zero */\r
+ xl = 1.0; /* start at point xl = 1 */\r
+\r
+\r
+ for(j=0;j<lpcrdr;j++){\r
+ if(j%2) /* determines whether P' or Q' is eval. */\r
+ pt = qx;\r
+ else\r
+ pt = px;\r
+\r
+ psuml = cheb_poly_eva(pt,xl,lpcrdr); /* evals poly. at xl */\r
+ flag = 1;\r
+ while(flag && (xr >= -1.0)){\r
+ xr = xl - delta ; /* interval spacing */\r
+ psumr = cheb_poly_eva(pt,xr,lpcrdr);/* poly(xl-delta_x) */\r
+ temp_psumr = psumr;\r
+ temp_xr = xr;\r
+\r
+ /* if no sign change increment xr and re-evaluate\r
+ poly(xr). Repeat til sign change. if a sign change has\r
+ occurred the interval is bisected and then checked again\r
+ for a sign change which determines in which interval the\r
+ zero lies in. If there is no sign change between poly(xm)\r
+ and poly(xl) set interval between xm and xr else set\r
+ interval between xl and xr and repeat till root is located\r
+ within the specified limits */\r
+\r
+ if((psumr*psuml)<0.0){\r
+ roots++;\r
+\r
+ psumm=psuml;\r
+ for(k=0;k<=nb;k++){\r
+ xm = (xl+xr)/2; /* bisect the interval */\r
+ psumm=cheb_poly_eva(pt,xm,lpcrdr);\r
+ if(psumm*psuml>0.){\r
+ psuml=psumm;\r
+ xl=xm;\r
+ }\r
+ else{\r
+ psumr=psumm;\r
+ xr=xm;\r
+ }\r
+ }\r
+\r
+ /* once zero is found, reset initial interval to xr */\r
+ freq[j] = (xm);\r
+ xl = xm;\r
+ flag = 0; /* reset flag for next search */\r
+ }\r
+ else{\r
+ psuml=temp_psumr;\r
+ xl=temp_xr;\r
+ }\r
+ }\r
+ }\r
+ free(P); /* free memory space */\r
+ free(Q);\r
+\r
+ return(roots);\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+\r
+ FUNCTION....: lsp_to_lpc()\r
+ AUTHOR......: David Rowe\r
+ DATE CREATED: 24/2/93\r
+\r
+ This function converts LSP coefficients to LPC coefficients. In the\r
+ Speex code we worked out a wayto simplify this significantly.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+void lsp_to_lpc(float *freq,float *ak,int lpcrdr)\r
+/* float *freq array of LSP frequencies in the x domain */\r
+/* float *ak array of LPC coefficients */\r
+/* int lpcrdr order of LPC coefficients */\r
+\r
+\r
+{\r
+ int i,j;\r
+ float xout1,xout2,xin1,xin2;\r
+ float *Wp;\r
+ float *pw,*n1,*n2,*n3,*n4;\r
+ int m = lpcrdr/2;\r
+\r
+ if((Wp = (float *) malloc((4*m+2)*sizeof(float))) == NULL){\r
+ printf("not enough memory to allocate buffer\n");\r
+ exit(1);\r
+ }\r
+ pw = Wp;\r
+\r
+ /* initialise contents of array */\r
+\r
+ for(i=0;i<=4*m+1;i++){ /* set contents of buffer to 0 */\r
+ *pw++ = 0.0;\r
+ }\r
+\r
+ /* Set pointers up */\r
+\r
+ pw = Wp;\r
+ xin1 = 1.0;\r
+ xin2 = 1.0;\r
+\r
+ /* reconstruct P(z) and Q(z) by cascading second order polynomials\r
+ in form 1 - 2xz(-1) +z(-2), where x is the LSP coefficient */\r
+\r
+ for(j=0;j<=lpcrdr;j++){\r
+ for(i=0;i<m;i++){\r
+ n1 = pw+(i*4);\r
+ n2 = n1 + 1;\r
+ n3 = n2 + 1;\r
+ n4 = n3 + 1;\r
+ xout1 = xin1 - 2*(freq[2*i]) * *n1 + *n2;\r
+ xout2 = xin2 - 2*(freq[2*i+1]) * *n3 + *n4;\r
+ *n2 = *n1;\r
+ *n4 = *n3;\r
+ *n1 = xin1;\r
+ *n3 = xin2;\r
+ xin1 = xout1;\r
+ xin2 = xout2;\r
+ }\r
+ xout1 = xin1 + *(n4+1);\r
+ xout2 = xin2 - *(n4+2);\r
+ ak[j] = (xout1 + xout2)*0.5;\r
+ *(n4+1) = xin1;\r
+ *(n4+2) = xin2;\r
+\r
+ xin1 = 0.0;\r
+ xin2 = 0.0;\r
+ }\r
+ free(Wp);\r
+}\r
+\r