FreeCalypso > hg > gsm-codec-lib
diff libgsmefr/az_lsp.c @ 53:49dd1ac8e75b
libgsmefr: import most *.c files from ETSI source
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 25 Nov 2022 16:18:21 +0000 |
parents | |
children | 902bc4b64cc6 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/az_lsp.c Fri Nov 25 16:18:21 2022 +0000 @@ -0,0 +1,261 @@ +/*********************************************************************** + * + * FUNCTION: Az_lsp + * + * PURPOSE: Compute the LSPs from the LP coefficients (order=10) + * + * DESCRIPTION: + * - The sum and difference filters are computed and divided by + * 1+z^{-1} and 1-z^{-1}, respectively. + * + * f1[i] = a[i] + a[11-i] - f1[i-1] ; i=1,...,5 + * f2[i] = a[i] - a[11-i] + f2[i-1] ; i=1,...,5 + * + * - The roots of F1(z) and F2(z) are found using Chebyshev polynomial + * evaluation. The polynomials are evaluated at 60 points regularly + * spaced in the frequency domain. The sign change interval is + * subdivided 4 times to better track the root. + * The LSPs are found in the cosine domain [1,-1]. + * + * - If less than 10 roots are found, the LSPs from the past frame are + * used. + * + ***********************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "cnst.h" + +#include "grid.tab" + +/* M = LPC order, NC = M/2 */ + +#define NC M/2 + +/* local function */ + +static Word16 Chebps (Word16 x, Word16 f[], Word16 n); + +void Az_lsp ( + Word16 a[], /* (i) : predictor coefficients */ + Word16 lsp[], /* (o) : line spectral pairs */ + Word16 old_lsp[] /* (i) : old lsp[] (in case not found 10 roots) */ +) +{ + Word16 i, j, nf, ip; + Word16 xlow, ylow, xhigh, yhigh, xmid, ymid, xint; + Word16 x, y, sign, exp; + Word16 *coef; + Word16 f1[M / 2 + 1], f2[M / 2 + 1]; + Word32 t0; + + /*-------------------------------------------------------------* + * find the sum and diff. pol. F1(z) and F2(z) * + * F1(z) <--- F1(z)/(1+z**-1) & F2(z) <--- F2(z)/(1-z**-1) * + * * + * f1[0] = 1.0; * + * f2[0] = 1.0; * + * * + * for (i = 0; i< NC; i++) * + * { * + * f1[i+1] = a[i+1] + a[M-i] - f1[i] ; * + * f2[i+1] = a[i+1] - a[M-i] + f2[i] ; * + * } * + *-------------------------------------------------------------*/ + + f1[0] = 1024; move16 (); /* f1[0] = 1.0 */ + f2[0] = 1024; move16 (); /* f2[0] = 1.0 */ + + for (i = 0; i < NC; i++) + { + t0 = L_mult (a[i + 1], 8192); /* x = (a[i+1] + a[M-i]) >> 2 */ + t0 = L_mac (t0, a[M - i], 8192); + x = extract_h (t0); + /* f1[i+1] = a[i+1] + a[M-i] - f1[i] */ + f1[i + 1] = sub (x, f1[i]);move16 (); + + t0 = L_mult (a[i + 1], 8192); /* x = (a[i+1] - a[M-i]) >> 2 */ + t0 = L_msu (t0, a[M - i], 8192); + x = extract_h (t0); + /* f2[i+1] = a[i+1] - a[M-i] + f2[i] */ + f2[i + 1] = add (x, f2[i]);move16 (); + } + + /*-------------------------------------------------------------* + * find the LSPs using the Chebychev pol. evaluation * + *-------------------------------------------------------------*/ + + nf = 0; move16 (); /* number of found frequencies */ + ip = 0; move16 (); /* indicator for f1 or f2 */ + + coef = f1; move16 (); + + xlow = grid[0]; move16 (); + ylow = Chebps (xlow, coef, NC);move16 (); + + j = 0; + test (); test (); + /* while ( (nf < M) && (j < grid_points) ) */ + while ((sub (nf, M) < 0) && (sub (j, grid_points) < 0)) + { + j++; + xhigh = xlow; move16 (); + yhigh = ylow; move16 (); + xlow = grid[j]; move16 (); + ylow = Chebps (xlow, coef, NC); + move16 (); + + test (); + if (L_mult (ylow, yhigh) <= (Word32) 0L) + { + + /* divide 4 times the interval */ + + for (i = 0; i < 4; i++) + { + /* xmid = (xlow + xhigh)/2 */ + xmid = add (shr (xlow, 1), shr (xhigh, 1)); + ymid = Chebps (xmid, coef, NC); + move16 (); + + test (); + if (L_mult (ylow, ymid) <= (Word32) 0L) + { + yhigh = ymid; move16 (); + xhigh = xmid; move16 (); + } + else + { + ylow = ymid; move16 (); + xlow = xmid; move16 (); + } + } + + /*-------------------------------------------------------------* + * Linear interpolation * + * xint = xlow - ylow*(xhigh-xlow)/(yhigh-ylow); * + *-------------------------------------------------------------*/ + + x = sub (xhigh, xlow); + y = sub (yhigh, ylow); + + test (); + if (y == 0) + { + xint = xlow; move16 (); + } + else + { + sign = y; move16 (); + y = abs_s (y); + exp = norm_s (y); + y = shl (y, exp); + y = div_s ((Word16) 16383, y); + t0 = L_mult (x, y); + t0 = L_shr (t0, sub (20, exp)); + y = extract_l (t0); /* y= (xhigh-xlow)/(yhigh-ylow) */ + + test (); + if (sign < 0) + y = negate (y); + + t0 = L_mult (ylow, y); + t0 = L_shr (t0, 11); + xint = sub (xlow, extract_l (t0)); /* xint = xlow - ylow*y */ + } + + lsp[nf] = xint; move16 (); + xlow = xint; move16 (); + nf++; + + test (); + if (ip == 0) + { + ip = 1; move16 (); + coef = f2; move16 (); + } + else + { + ip = 0; move16 (); + coef = f1; move16 (); + } + ylow = Chebps (xlow, coef, NC); + move16 (); + + } + test (); test (); + } + + /* Check if M roots found */ + + test (); + if (sub (nf, M) < 0) + { + for (i = 0; i < M; i++) + { + lsp[i] = old_lsp[i]; move16 (); + } + + } + return; +} + +/************************************************************************ + * + * FUNCTION: Chebps + * + * PURPOSE: Evaluates the Chebyshev polynomial series + * + * DESCRIPTION: + * - The polynomial order is n = m/2 = 5 + * - The polynomial F(z) (F1(z) or F2(z)) is given by + * F(w) = 2 exp(-j5w) C(x) + * where + * C(x) = T_n(x) + f(1)T_n-1(x) + ... +f(n-1)T_1(x) + f(n)/2 + * and T_m(x) = cos(mw) is the mth order Chebyshev polynomial ( x=cos(w) ) + * - The function returns the value of C(x) for the input x. + * + ***********************************************************************/ + +static Word16 Chebps (Word16 x, Word16 f[], Word16 n) +{ + Word16 i, cheb; + Word16 b0_h, b0_l, b1_h, b1_l, b2_h, b2_l; + Word32 t0; + + b2_h = 256; move16 (); /* b2 = 1.0 */ + b2_l = 0; move16 (); + + t0 = L_mult (x, 512); /* 2*x */ + t0 = L_mac (t0, f[1], 8192); /* + f[1] */ + L_Extract (t0, &b1_h, &b1_l); /* b1 = 2*x + f[1] */ + + for (i = 2; i < n; i++) + { + t0 = Mpy_32_16 (b1_h, b1_l, x); /* t0 = 2.0*x*b1 */ + t0 = L_shl (t0, 1); + t0 = L_mac (t0, b2_h, (Word16) 0x8000); /* t0 = 2.0*x*b1 - b2 */ + t0 = L_msu (t0, b2_l, 1); + t0 = L_mac (t0, f[i], 8192); /* t0 = 2.0*x*b1 - b2 + f[i] */ + + L_Extract (t0, &b0_h, &b0_l); /* b0 = 2.0*x*b1 - b2 + f[i]*/ + + b2_l = b1_l; move16 (); /* b2 = b1; */ + b2_h = b1_h; move16 (); + b1_l = b0_l; move16 (); /* b1 = b0; */ + b1_h = b0_h; move16 (); + } + + t0 = Mpy_32_16 (b1_h, b1_l, x); /* t0 = x*b1; */ + t0 = L_mac (t0, b2_h, (Word16) 0x8000); /* t0 = x*b1 - b2 */ + t0 = L_msu (t0, b2_l, 1); + t0 = L_mac (t0, f[i], 4096); /* t0 = x*b1 - b2 + f[i]/2 */ + + t0 = L_shl (t0, 6); + + cheb = extract_h (t0); + + return (cheb); +}