# HG changeset patch # User Mychaela Falconia # Date 1712122297 0 # Node ID 56410792419a0e8790200dee1f9fcc7be31ed0fc src: original EFR source from ETSI diff -r 000000000000 -r 56410792419a src/agc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/agc.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,186 @@ +/************************************************************************* + * + * FUNCTION: agc + * + * PURPOSE: Scales the postfilter output on a subframe basis by automatic + * control of the subframe gain. + * + * DESCRIPTION: + * sig_out[n] = sig_out[n] * gain[n]; + * where gain[n] is the gain at the nth sample given by + * gain[n] = agc_fac * gain[n-1] + (1 - agc_fac) g_in/g_out + * g_in/g_out is the square root of the ratio of energy at the input + * and output of the postfilter. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" +#include "sig_proc.h" +#include "cnst.h" + +Word16 past_gain; /* initial value of past_gain = 1.0 */ + +void agc ( + Word16 *sig_in, /* (i) : postfilter input signal */ + Word16 *sig_out, /* (i/o) : postfilter output signal */ + Word16 agc_fac, /* (i) : AGC factor */ + Word16 l_trm /* (i) : subframe size */ +) +{ + Word16 i, exp; + Word16 gain_in, gain_out, g0, gain; + Word32 s; + + Word16 temp; + + /* calculate gain_out with exponent */ + + temp = shr (sig_out[0], 2); + s = L_mult (temp, temp); + + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_out[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + past_gain = 0; move16 (); + return; + } + exp = sub (norm_l (s), 1); + gain_out = round (L_shl (s, exp)); + + /* calculate gain_in with exponent */ + + temp = shr (sig_in[0], 2); + s = L_mult (temp, temp); + + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_in[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + g0 = 0; move16 (); + } + else + { + i = norm_l (s); + gain_in = round (L_shl (s, i)); + exp = sub (exp, i); + + /*---------------------------------------------------* + * g0 = (1-agc_fac) * sqrt(gain_in/gain_out); * + *---------------------------------------------------*/ + + s = L_deposit_l (div_s (gain_out, gain_in)); + s = L_shl (s, 7); /* s = gain_out / gain_in */ + s = L_shr (s, exp); /* add exponent */ + + s = Inv_sqrt (s); + i = round (L_shl (s, 9)); + + /* g0 = i * (1-agc_fac) */ + g0 = mult (i, sub (32767, agc_fac)); + } + + /* compute gain[n] = agc_fac * gain[n-1] + + (1-agc_fac) * sqrt(gain_in/gain_out) */ + /* sig_out[n] = gain[n] * sig_out[n] */ + + gain = past_gain; move16 (); + + for (i = 0; i < l_trm; i++) + { + gain = mult (gain, agc_fac); + gain = add (gain, g0); + sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], gain), 3)); + move16 (); + } + + past_gain = gain; move16 (); + + return; +} + +void agc2 ( + Word16 *sig_in, /* (i) : postfilter input signal */ + Word16 *sig_out, /* (i/o) : postfilter output signal */ + Word16 l_trm /* (i) : subframe size */ +) +{ + Word16 i, exp; + Word16 gain_in, gain_out, g0; + Word32 s; + + Word16 temp; + + /* calculate gain_out with exponent */ + + temp = shr (sig_out[0], 2); + s = L_mult (temp, temp); + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_out[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + return; + } + exp = sub (norm_l (s), 1); + gain_out = round (L_shl (s, exp)); + + /* calculate gain_in with exponent */ + + temp = shr (sig_in[0], 2); + s = L_mult (temp, temp); + for (i = 1; i < l_trm; i++) + { + temp = shr (sig_in[i], 2); + s = L_mac (s, temp, temp); + } + + test (); + if (s == 0) + { + g0 = 0; move16 (); + } + else + { + i = norm_l (s); + gain_in = round (L_shl (s, i)); + exp = sub (exp, i); + + /*---------------------------------------------------* + * g0 = sqrt(gain_in/gain_out); * + *---------------------------------------------------*/ + + s = L_deposit_l (div_s (gain_out, gain_in)); + s = L_shl (s, 7); /* s = gain_out / gain_in */ + s = L_shr (s, exp); /* add exponent */ + + s = Inv_sqrt (s); + g0 = round (L_shl (s, 9)); + } + + /* sig_out(n) = gain(n) sig_out(n) */ + + for (i = 0; i < l_trm; i++) + { + sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], g0), 3)); + move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/autocorr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/autocorr.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,99 @@ +/************************************************************************* + * + * FUNCTION: autocorr + * + * PURPOSE: Compute autocorrelations of signal with windowing + * + * DESCRIPTION: + * - Windowing of input speech: s'[n] = s[n] * w[n] + * - Autocorrelations of input speech: + * r[k] = sum_{i=k}^{239} s'[i]*s'[i-k] k=0,...,10 + * The autocorrelations are expressed in normalized double precision + * format. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "cnst.h" + +Word16 Autocorr ( + Word16 x[], /* (i) : Input signal */ + Word16 m, /* (i) : LPC order */ + Word16 r_h[], /* (o) : Autocorrelations (msb) */ + Word16 r_l[], /* (o) : Autocorrelations (lsb) */ + Word16 wind[] /* (i) : window for LPC analysis */ +) +{ + Word16 i, j, norm; + Word16 y[L_WINDOW]; + Word32 sum; + Word16 overfl, overfl_shft; + + /* Windowing of signal */ + + for (i = 0; i < L_WINDOW; i++) + { + y[i] = mult_r (x[i], wind[i]); move16 (); + } + + /* Compute r[0] and test for overflow */ + + overfl_shft = 0; move16 (); + + do + { + overfl = 0; move16 (); + sum = 0L; move32 (); + + for (i = 0; i < L_WINDOW; i++) + { + sum = L_mac (sum, y[i], y[i]); + } + + /* If overflow divide y[] by 4 */ + + test (); + if (L_sub (sum, MAX_32) == 0L) + { + overfl_shft = add (overfl_shft, 4); + overfl = 1; move16 (); /* Set the overflow flag */ + + for (i = 0; i < L_WINDOW; i++) + { + y[i] = shr (y[i], 2); move16 (); + } + } + test (); + } + while (overfl != 0); + + sum = L_add (sum, 1L); /* Avoid the case of all zeros */ + + /* Normalization of r[0] */ + + norm = norm_l (sum); + sum = L_shl (sum, norm); + L_Extract (sum, &r_h[0], &r_l[0]); /* Put in DPF format (see oper_32b) */ + + /* r[1] to r[m] */ + + for (i = 1; i <= m; i++) + { + sum = 0; move32 (); + + for (j = 0; j < L_WINDOW - i; j++) + { + sum = L_mac (sum, y[j], y[j + i]); + } + + sum = L_shl (sum, norm); + L_Extract (sum, &r_h[i], &r_l[i]); + } + + norm = sub (norm, overfl_shft); + + return norm; +} diff -r 000000000000 -r 56410792419a src/az_lsp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/az_lsp.c Wed Apr 03 05:31:37 2024 +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); +} diff -r 000000000000 -r 56410792419a src/basic_op.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/basic_op.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,62 @@ +/*___________________________________________________________________________ + | | + | Constants and Globals | + |___________________________________________________________________________| +*/ +extern Flag Overflow; +extern Flag Carry; + +#define MAX_32 (Word32)0x7fffffffL +#define MIN_32 (Word32)0x80000000L + +#define MAX_16 (Word16)0x7fff +#define MIN_16 (Word16)0x8000 + +/*___________________________________________________________________________ + | | + | Prototypes for basic arithmetic operators | + |___________________________________________________________________________| +*/ + +Word16 add (Word16 var1, Word16 var2); /* Short add, 1 */ +Word16 sub (Word16 var1, Word16 var2); /* Short sub, 1 */ +Word16 abs_s (Word16 var1); /* Short abs, 1 */ +Word16 shl (Word16 var1, Word16 var2); /* Short shift left, 1 */ +Word16 shr (Word16 var1, Word16 var2); /* Short shift right, 1 */ +Word16 mult (Word16 var1, Word16 var2); /* Short mult, 1 */ +Word32 L_mult (Word16 var1, Word16 var2); /* Long mult, 1 */ +Word16 negate (Word16 var1); /* Short negate, 1 */ +Word16 extract_h (Word32 L_var1); /* Extract high, 1 */ +Word16 extract_l (Word32 L_var1); /* Extract low, 1 */ +Word16 round (Word32 L_var1); /* Round, 1 */ +Word32 L_mac (Word32 L_var3, Word16 var1, Word16 var2); /* Mac, 1 */ +Word32 L_msu (Word32 L_var3, Word16 var1, Word16 var2); /* Msu, 1 */ +Word32 L_macNs (Word32 L_var3, Word16 var1, Word16 var2); /* Mac without + sat, 1 */ +Word32 L_msuNs (Word32 L_var3, Word16 var1, Word16 var2); /* Msu without + sat, 1 */ +Word32 L_add (Word32 L_var1, Word32 L_var2); /* Long add, 2 */ +Word32 L_sub (Word32 L_var1, Word32 L_var2); /* Long sub, 2 */ +Word32 L_add_c (Word32 L_var1, Word32 L_var2); /* Long add with c, 2 */ +Word32 L_sub_c (Word32 L_var1, Word32 L_var2); /* Long sub with c, 2 */ +Word32 L_negate (Word32 L_var1); /* Long negate, 2 */ +Word16 mult_r (Word16 var1, Word16 var2); /* Mult with round, 2 */ +Word32 L_shl (Word32 L_var1, Word16 var2); /* Long shift left, 2 */ +Word32 L_shr (Word32 L_var1, Word16 var2); /* Long shift right, 2*/ +Word16 shr_r (Word16 var1, Word16 var2); /* Shift right with + round, 2 */ +Word16 mac_r (Word32 L_var3, Word16 var1, Word16 var2); /* Mac with + rounding,2 */ +Word16 msu_r (Word32 L_var3, Word16 var1, Word16 var2); /* Msu with + rounding,2 */ +Word32 L_deposit_h (Word16 var1); /* 16 bit var1 -> MSB, 2 */ +Word32 L_deposit_l (Word16 var1); /* 16 bit var1 -> LSB, 2 */ + +Word32 L_shr_r (Word32 L_var1, Word16 var2); /* Long shift right with + round, 3 */ +Word32 L_abs (Word32 L_var1); /* Long abs, 3 */ +Word32 L_sat (Word32 L_var1); /* Long saturation, 4 */ +Word16 norm_s (Word16 var1); /* Short norm, 15 */ +Word16 div_s (Word16 var1, Word16 var2); /* Short division, 18 */ +Word16 norm_l (Word32 L_var1); /* Long norm, 30 */ + diff -r 000000000000 -r 56410792419a src/basicop2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/basicop2.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,2126 @@ +/*___________________________________________________________________________ + | | + | Basic arithmetic operators. | + |___________________________________________________________________________| +*/ + +/*___________________________________________________________________________ + | | + | Include-Files | + |___________________________________________________________________________| +*/ + +#include +#include +#include "typedef.h" +#include "basic_op.h" + +#if (WMOPS) +#include "count.h" +extern BASIC_OP counter; + +#endif + +/*___________________________________________________________________________ + | | + | Local Functions | + |___________________________________________________________________________| +*/ +Word16 saturate (Word32 L_var1); + +/*___________________________________________________________________________ + | | + | Constants and Globals | + |___________________________________________________________________________| +*/ +Flag Overflow = 0; +Flag Carry = 0; + +/*___________________________________________________________________________ + | | + | Functions | + |___________________________________________________________________________| +*/ + +/*___________________________________________________________________________ + | | + | Function Name : saturate | + | | + | Purpose : | + | | + | Limit the 32 bit input to the range of a 16 bit word. | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 +saturate (Word32 L_var1) +{ + Word16 var_out; + + if (L_var1 > 0X00007fffL) + { + Overflow = 1; + var_out = MAX_16; + } + else if (L_var1 < (Word32) 0xffff8000L) + { + Overflow = 1; + var_out = MIN_16; + } + else + { + Overflow = 0; + var_out = extract_l (L_var1); +#if (WMOPS) + counter.extract_l--; +#endif + } + + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : add | + | | + | Purpose : | + | | + | Performs the addition (var1+var2) with overflow control and saturation;| + | the 16 bit result is set at +32767 when overflow occurs or at -32768 | + | when underflow occurs. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 add (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_sum; + + L_sum = (Word32) var1 + var2; + var_out = saturate (L_sum); +#if (WMOPS) + counter.add++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : sub | + | | + | Purpose : | + | | + | Performs the subtraction (var1+var2) with overflow control and satu- | + | ration; the 16 bit result is set at +32767 when overflow occurs or at | + | -32768 when underflow occurs. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 sub (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_diff; + + L_diff = (Word32) var1 - var2; + var_out = saturate (L_diff); +#if (WMOPS) + counter.sub++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : abs_s | + | | + | Purpose : | + | | + | Absolute value of var1; abs_s(-32768) = 32767. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 abs_s (Word16 var1) +{ + Word16 var_out; + + if (var1 == (Word16) 0X8000) + { + var_out = MAX_16; + } + else + { + if (var1 < 0) + { + var_out = -var1; + } + else + { + var_out = var1; + } + } +#if (WMOPS) + counter.abs_s++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : shl | + | | + | Purpose : | + | | + | Arithmetically shift the 16 bit input var1 left var2 positions.Zero fill| + | the var2 LSB of the result. If var2 is negative, arithmetically shift | + | var1 right by -var2 with sign extension. Saturate the result in case of | + | underflows or overflows. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 shl (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 result; + + if (var2 < 0) + { + var_out = shr (var1, -var2); +#if (WMOPS) + counter.shr--; +#endif + } + else + { + result = (Word32) var1 *((Word32) 1 << var2); + + if ((var2 > 15 && var1 != 0) || (result != (Word32) ((Word16) result))) + { + Overflow = 1; + var_out = (var1 > 0) ? MAX_16 : MIN_16; + } + else + { + var_out = extract_l (result); +#if (WMOPS) + counter.extract_l--; +#endif + } + } +#if (WMOPS) + counter.shl++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : shr | + | | + | Purpose : | + | | + | Arithmetically shift the 16 bit input var1 right var2 positions with | + | sign extension. If var2 is negative, arithmetically shift var1 left by | + | -var2 with sign extension. Saturate the result in case of underflows or | + | overflows. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 shr (Word16 var1, Word16 var2) +{ + Word16 var_out; + + if (var2 < 0) + { + var_out = shl (var1, -var2); +#if (WMOPS) + counter.shl--; +#endif + } + else + { + if (var2 >= 15) + { + var_out = (var1 < 0) ? -1 : 0; + } + else + { + if (var1 < 0) + { + var_out = ~((~var1) >> var2); + } + else + { + var_out = var1 >> var2; + } + } + } + +#if (WMOPS) + counter.shr++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : mult | + | | + | Purpose : | + | | + | Performs the multiplication of var1 by var2 and gives a 16 bit result | + | which is scaled i.e.: | + | mult(var1,var2) = extract_l(L_shr((var1 times var2),15)) and | + | mult(-32768,-32768) = 32767. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 mult (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_product; + + L_product = (Word32) var1 *(Word32) var2; + + L_product = (L_product & (Word32) 0xffff8000L) >> 15; + + if (L_product & (Word32) 0x00010000L) + L_product = L_product | (Word32) 0xffff0000L; + + var_out = saturate (L_product); +#if (WMOPS) + counter.mult++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_mult | + | | + | Purpose : | + | | + | L_mult is the 32 bit result of the multiplication of var1 times var2 | + | with one shift left i.e.: | + | L_mult(var1,var2) = L_shl((var1 times var2),1) and | + | L_mult(-32768,-32768) = 2147483647. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_mult (Word16 var1, Word16 var2) +{ + Word32 L_var_out; + + L_var_out = (Word32) var1 *(Word32) var2; + + if (L_var_out != (Word32) 0x40000000L) + { + L_var_out *= 2; + } + else + { + Overflow = 1; + L_var_out = MAX_32; + } + +#if (WMOPS) + counter.L_mult++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : negate | + | | + | Purpose : | + | | + | Negate var1 with saturation, saturate in the case where input is -32768:| + | negate(var1) = sub(0,var1). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 negate (Word16 var1) +{ + Word16 var_out; + + var_out = (var1 == MIN_16) ? MAX_16 : -var1; +#if (WMOPS) + counter.negate++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : extract_h | + | | + | Purpose : | + | | + | Return the 16 MSB of L_var1. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 extract_h (Word32 L_var1) +{ + Word16 var_out; + + var_out = (Word16) (L_var1 >> 16); +#if (WMOPS) + counter.extract_h++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : extract_l | + | | + | Purpose : | + | | + | Return the 16 LSB of L_var1. | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 extract_l (Word32 L_var1) +{ + Word16 var_out; + + var_out = (Word16) L_var1; +#if (WMOPS) + counter.extract_l++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : round | + | | + | Purpose : | + | | + | Round the lower 16 bits of the 32 bit input number into the MS 16 bits | + | with saturation. Shift the resulting bits right by 16 and return the 16 | + | bit number: | + | round(L_var1) = extract_h(L_add(L_var1,32768)) | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32 ) whose value falls in the | + | range : 0x8000 0000 <= L_var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 round (Word32 L_var1) +{ + Word16 var_out; + Word32 L_rounded; + + L_rounded = L_add (L_var1, (Word32) 0x00008000L); +#if (WMOPS) + counter.L_add--; +#endif + var_out = extract_h (L_rounded); +#if (WMOPS) + counter.extract_h--; + counter.round++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_mac | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 with saturation, return a 32 bit result: | + | L_mac(L_var3,var1,var2) = L_add(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_mac (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult (var1, var2); +#if (WMOPS) + counter.L_mult--; +#endif + L_var_out = L_add (L_var3, L_product); +#if (WMOPS) + counter.L_add--; + counter.L_mac++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_msu | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result to L_var3 with saturation, return a 32 bit result: | + | L_msu(L_var3,var1,var2) = L_sub(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_msu (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + Word32 L_product; + + L_product = L_mult (var1, var2); +#if (WMOPS) + counter.L_mult--; +#endif + L_var_out = L_sub (L_var3, L_product); +#if (WMOPS) + counter.L_sub--; + counter.L_msu++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_macNs | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 without saturation, return a 32 bit result. Generate | + | carry and overflow values : | + | L_macNs(L_var3,var1,var2) = L_add_c(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ + +Word32 L_macNs (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + + L_var_out = L_mult (var1, var2); +#if (WMOPS) + counter.L_mult--; +#endif + L_var_out = L_add_c (L_var3, L_var_out); +#if (WMOPS) + counter.L_add_c--; + counter.L_macNs++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_msuNs | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result from L_var3 without saturation, return a 32 bit result. Ge- | + | nerate carry and overflow values : | + | L_msuNs(L_var3,var1,var2) = L_sub_c(L_var3,L_mult(var1,var2)). | + | | + | Complexity weight : 1 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ + +Word32 L_msuNs (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word32 L_var_out; + + L_var_out = L_mult (var1, var2); +#if (WMOPS) + counter.L_mult--; +#endif + L_var_out = L_sub_c (L_var3, L_var_out); +#if (WMOPS) + counter.L_sub_c--; + counter.L_msuNs++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_add | + | | + | Purpose : | + | | + | 32 bits addition of the two 32 bits variables (L_var1+L_var2) with | + | overflow control and saturation; the result is set at +2147483647 when | + | overflow occurs or at -2147483648 when underflow occurs. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_add (Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + + L_var_out = L_var1 + L_var2; + + if (((L_var1 ^ L_var2) & MIN_32) == 0) + { + if ((L_var_out ^ L_var1) & MIN_32) + { + L_var_out = (L_var1 < 0) ? MIN_32 : MAX_32; + Overflow = 1; + } + } +#if (WMOPS) + counter.L_add++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_sub | + | | + | Purpose : | + | | + | 32 bits subtraction of the two 32 bits variables (L_var1-L_var2) with | + | overflow control and saturation; the result is set at +2147483647 when | + | overflow occurs or at -2147483648 when underflow occurs. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_sub (Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + + L_var_out = L_var1 - L_var2; + + if (((L_var1 ^ L_var2) & MIN_32) != 0) + { + if ((L_var_out ^ L_var1) & MIN_32) + { + L_var_out = (L_var1 < 0L) ? MIN_32 : MAX_32; + Overflow = 1; + } + } +#if (WMOPS) + counter.L_sub++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_add_c | + | | + | Purpose : | + | | + | Performs 32 bits addition of the two 32 bits variables (L_var1+L_var2+C)| + | with carry. No saturation. Generate carry and Overflow values. The car- | + | ry and overflow values are binary variables which can be tested and as- | + | signed values. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ +Word32 L_add_c (Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + Word32 L_test; + Flag carry_int = 0; + + L_var_out = L_var1 + L_var2 + Carry; + + L_test = L_var1 + L_var2; + + if ((L_var1 > 0) && (L_var2 > 0) && (L_test < 0)) + { + Overflow = 1; + carry_int = 0; + } + else + { + if ((L_var1 < 0) && (L_var2 < 0)) + { + if (L_test >= 0) + { + Overflow = 1; + carry_int = 1; + } + else + { + Overflow = 0; + carry_int = 1; + } + } + else + { + if (((L_var1 ^ L_var2) < 0) && (L_test >= 0)) + { + Overflow = 0; + carry_int = 1; + } + else + { + Overflow = 0; + carry_int = 0; + } + } + } + + if (Carry) + { + if (L_test == MAX_32) + { + Overflow = 1; + Carry = carry_int; + } + else + { + if (L_test == (Word32) 0xFFFFFFFFL) + { + Carry = 1; + } + else + { + Carry = carry_int; + } + } + } + else + { + Carry = carry_int; + } + +#if (WMOPS) + counter.L_add_c++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_sub_c | + | | + | Purpose : | + | | + | Performs 32 bits subtraction of the two 32 bits variables with carry | + | (borrow) : L_var1-L_var2-C. No saturation. Generate carry and Overflow | + | values. The carry and overflow values are binary variables which can | + | be tested and assigned values. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | L_var2 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + | | + | Caution : | + | | + | In some cases the Carry flag has to be cleared or set before using | + | operators which take into account its value. | + |___________________________________________________________________________| +*/ + +Word32 L_sub_c (Word32 L_var1, Word32 L_var2) +{ + Word32 L_var_out; + Word32 L_test; + Flag carry_int = 0; + + if (Carry) + { + Carry = 0; + if (L_var2 != MIN_32) + { + L_var_out = L_add_c (L_var1, -L_var2); +#if (WMOPS) + counter.L_add_c--; +#endif + } + else + { + L_var_out = L_var1 - L_var2; + if (L_var1 > 0L) + { + Overflow = 1; + Carry = 0; + } + } + } + else + { + L_var_out = L_var1 - L_var2 - (Word32) 0X00000001L; + L_test = L_var1 - L_var2; + + if ((L_test < 0) && (L_var1 > 0) && (L_var2 < 0)) + { + Overflow = 1; + carry_int = 0; + } + else if ((L_test > 0) && (L_var1 < 0) && (L_var2 > 0)) + { + Overflow = 1; + carry_int = 1; + } + else if ((L_test > 0) && ((L_var1 ^ L_var2) > 0)) + { + Overflow = 0; + carry_int = 1; + } + if (L_test == MIN_32) + { + Overflow = 1; + Carry = carry_int; + } + else + { + Carry = carry_int; + } + } + +#if (WMOPS) + counter.L_sub_c++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_negate | + | | + | Purpose : | + | | + | Negate the 32 bit variable L_var1 with saturation; saturate in the case | + | where input is -2147483648 (0x8000 0000). | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_negate (Word32 L_var1) +{ + Word32 L_var_out; + + L_var_out = (L_var1 == MIN_32) ? MAX_32 : -L_var1; +#if (WMOPS) + counter.L_negate++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : mult_r | + | | + | Purpose : | + | | + | Same as mult with rounding, i.e.: | + | mult_r(var1,var2) = extract_l(L_shr(((var1 * var2) + 16384),15)) and | + | mult_r(-32768,-32768) = 32767. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 mult_r (Word16 var1, Word16 var2) +{ + Word16 var_out; + Word32 L_product_arr; + + L_product_arr = (Word32) var1 *(Word32) var2; /* product */ + L_product_arr += (Word32) 0x00004000L; /* round */ + L_product_arr &= (Word32) 0xffff8000L; + L_product_arr >>= 15; /* shift */ + + if (L_product_arr & (Word32) 0x00010000L) /* sign extend when necessary */ + { + L_product_arr |= (Word32) 0xffff0000L; + } + var_out = saturate (L_product_arr); +#if (WMOPS) + counter.mult_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_shl | + | | + | Purpose : | + | | + | Arithmetically shift the 32 bit input L_var1 left var2 positions. Zero | + | fill the var2 LSB of the result. If var2 is negative, arithmetically | + | shift L_var1 right by -var2 with sign extension. Saturate the result in | + | case of underflows or overflows. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_shl (Word32 L_var1, Word16 var2) +{ + Word32 L_var_out; + + if (var2 <= 0) + { + L_var_out = L_shr (L_var1, -var2); +#if (WMOPS) + counter.L_shr--; +#endif + } + else + { + for (; var2 > 0; var2--) + { + if (L_var1 > (Word32) 0X3fffffffL) + { + Overflow = 1; + L_var_out = MAX_32; + break; + } + else + { + if (L_var1 < (Word32) 0xc0000000L) + { + Overflow = 1; + L_var_out = MIN_32; + break; + } + } + L_var1 *= 2; + L_var_out = L_var1; + } + } +#if (WMOPS) + counter.L_shl++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_shr | + | | + | Purpose : | + | | + | Arithmetically shift the 32 bit input L_var1 right var2 positions with | + | sign extension. If var2 is negative, arithmetically shift L_var1 left | + | by -var2 and zero fill the -var2 LSB of the result. Saturate the result | + | in case of underflows or overflows. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var1 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_shr (Word32 L_var1, Word16 var2) +{ + Word32 L_var_out; + + if (var2 < 0) + { + L_var_out = L_shl (L_var1, -var2); +#if (WMOPS) + counter.L_shl--; +#endif + } + else + { + if (var2 >= 31) + { + L_var_out = (L_var1 < 0L) ? -1 : 0; + } + else + { + if (L_var1 < 0) + { + L_var_out = ~((~L_var1) >> var2); + } + else + { + L_var_out = L_var1 >> var2; + } + } + } +#if (WMOPS) + counter.L_shr++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : shr_r | + | | + | Purpose : | + | | + | Same as shr(var1,var2) but with rounding. Saturate the result in case of| + | underflows or overflows : | + | - If var2 is greater than zero : | + | if (sub(shl(shr(var1,var2),1),shr(var1,sub(var2,1)))) | + | is equal to zero | + | then | + | shr_r(var1,var2) = shr(var1,var2) | + | else | + | shr_r(var1,var2) = add(shr(var1,var2),1) | + | - If var2 is less than or equal to zero : | + | shr_r(var1,var2) = shr(var1,var2). | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 shr_r (Word16 var1, Word16 var2) +{ + Word16 var_out; + + if (var2 > 15) + { + var_out = 0; + } + else + { + var_out = shr (var1, var2); +#if (WMOPS) + counter.shr--; +#endif + + if (var2 > 0) + { + if ((var1 & ((Word16) 1 << (var2 - 1))) != 0) + { + var_out++; + } + } + } +#if (WMOPS) + counter.shr_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : mac_r | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Add the 32 bit | + | result to L_var3 with saturation. Round the LS 16 bits of the result | + | into the MS 16 bits with saturation and shift the result right by 16. | + | Return a 16 bit result. | + | mac_r(L_var3,var1,var2) = round(L_mac(L_var3,var1,var2)) | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 8000 <= L_var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 mac_r (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word16 var_out; + + L_var3 = L_mac (L_var3, var1, var2); +#if (WMOPS) + counter.L_mac--; +#endif + L_var3 = L_add (L_var3, (Word32) 0x00008000L); +#if (WMOPS) + counter.L_add--; +#endif + var_out = extract_h (L_var3); +#if (WMOPS) + counter.extract_h--; + counter.mac_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : msu_r | + | | + | Purpose : | + | | + | Multiply var1 by var2 and shift the result left by 1. Subtract the 32 | + | bit result to L_var3 with saturation. Round the LS 16 bits of the res- | + | ult into the MS 16 bits with saturation and shift the result right by | + | 16. Return a 16 bit result. | + | msu_r(L_var3,var1,var2) = round(L_msu(L_var3,var1,var2)) | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | L_var3 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= L_var3 <= 0x7fff ffff. | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 8000 <= L_var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word16 msu_r (Word32 L_var3, Word16 var1, Word16 var2) +{ + Word16 var_out; + + L_var3 = L_msu (L_var3, var1, var2); +#if (WMOPS) + counter.L_msu--; +#endif + L_var3 = L_add (L_var3, (Word32) 0x00008000L); +#if (WMOPS) + counter.L_add--; +#endif + var_out = extract_h (L_var3); +#if (WMOPS) + counter.extract_h--; + counter.msu_r++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_deposit_h | + | | + | Purpose : | + | | + | Deposit the 16 bit var1 into the 16 MS bits of the 32 bit output. The | + | 16 LS bits of the output are zeroed. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff 0000. | + |___________________________________________________________________________| +*/ + +Word32 L_deposit_h (Word16 var1) +{ + Word32 L_var_out; + + L_var_out = (Word32) var1 << 16; +#if (WMOPS) + counter.L_deposit_h++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_deposit_l | + | | + | Purpose : | + | | + | Deposit the 16 bit var1 into the 16 LS bits of the 32 bit output. The | + | 16 MS bits of the output are sign extended. | + | | + | Complexity weight : 2 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0xFFFF 8000 <= var_out <= 0x0000 7fff. | + |___________________________________________________________________________| +*/ + +Word32 L_deposit_l (Word16 var1) +{ + Word32 L_var_out; + + L_var_out = (Word32) var1; +#if (WMOPS) + counter.L_deposit_l++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_shr_r | + | | + | Purpose : | + | | + | Same as L_shr(L_var1,var2) but with rounding. Saturate the result in | + | case of underflows or overflows : | + | - If var2 is greater than zero : | + | if (L_sub(L_shl(L_shr(L_var1,var2),1),L_shr(L_var1,sub(var2,1))))| + | is equal to zero | + | then | + | L_shr_r(L_var1,var2) = L_shr(L_var1,var2) | + | else | + | L_shr_r(L_var1,var2) = L_add(L_shr(L_var1,var2),1) | + | - If var2 is less than or equal to zero : | + | L_shr_r(L_var1,var2) = L_shr(L_var1,var2). | + | | + | Complexity weight : 3 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_shr_r (Word32 L_var1, Word16 var2) +{ + Word32 L_var_out; + + if (var2 > 31) + { + L_var_out = 0; + } + else + { + L_var_out = L_shr (L_var1, var2); +#if (WMOPS) + counter.L_shr--; +#endif + if (var2 > 0) + { + if ((L_var1 & ((Word32) 1 << (var2 - 1))) != 0) + { + L_var_out++; + } + } + } +#if (WMOPS) + counter.L_shr_r++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_abs | + | | + | Purpose : | + | | + | Absolute value of L_var1; Saturate in case where the input is | + | -214783648 | + | | + | Complexity weight : 3 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_abs (Word32 L_var1) +{ + Word32 L_var_out; + + if (L_var1 == MIN_32) + { + L_var_out = MAX_32; + } + else + { + if (L_var1 < 0) + { + L_var_out = -L_var1; + } + else + { + L_var_out = L_var1; + } + } + +#if (WMOPS) + counter.L_abs++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : L_sat | + | | + | Purpose : | + | | + | 32 bit L_var1 is set to 2147483647 if an overflow occured or to | + | -2147483648 if an underflow occured on the most recent L_add_c, | + | L_sub_c, L_macNs or L_msuNs operations. The carry and overflow values | + | are binary values which can be tested and assigned values. | + | | + | Complexity weight : 4 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | L_var_out | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var_out <= 0x7fff ffff. | + |___________________________________________________________________________| +*/ + +Word32 L_sat (Word32 L_var1) +{ + Word32 L_var_out; + + L_var_out = L_var1; + + if (Overflow) + { + + if (Carry) + { + L_var_out = MIN_32; + } + else + { + L_var_out = MAX_32; + } + + Carry = 0; + Overflow = 0; + } +#if (WMOPS) + counter.L_sat++; +#endif + return (L_var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : norm_s | + | | + | Purpose : | + | | + | Produces the number of left shift needed to normalize the 16 bit varia- | + | ble var1 for positive values on the interval with minimum of 16384 and | + | maximum of 32767, and for negative values on the interval with minimum | + | of -32768 and maximum of -16384; in order to normalize the result, the | + | following operation must be done : | + | norm_var1 = shl(var1,norm_s(var1)). | + | | + | Complexity weight : 15 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0xffff 8000 <= var1 <= 0x0000 7fff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 000f. | + |___________________________________________________________________________| +*/ + +Word16 norm_s (Word16 var1) +{ + Word16 var_out; + + if (var1 == 0) + { + var_out = 0; + } + else + { + if (var1 == (Word16) 0xffff) + { + var_out = 15; + } + else + { + if (var1 < 0) + { + var1 = ~var1; + } + for (var_out = 0; var1 < 0x4000; var_out++) + { + var1 <<= 1; + } + } + } + +#if (WMOPS) + counter.norm_s++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : div_s | + | | + | Purpose : | + | | + | Produces a result which is the fractional integer division of var1 by | + | var2; var1 and var2 must be positive and var2 must be greater or equal | + | to var1; the result is positive (leading bit equal to 0) and truncated | + | to 16 bits. | + | If var1 = var2 then div(var1,var2) = 32767. | + | | + | Complexity weight : 18 | + | | + | Inputs : | + | | + | var1 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var1 <= var2 and var2 != 0. | + | | + | var2 | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : var1 <= var2 <= 0x0000 7fff and var2 != 0. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 7fff. | + | It's a Q15 value (point between b15 and b14). | + |___________________________________________________________________________| +*/ + +Word16 div_s (Word16 var1, Word16 var2) +{ + Word16 var_out = 0; + Word16 iteration; + Word32 L_num; + Word32 L_denom; + + if ((var1 > var2) || (var1 < 0) || (var2 < 0)) + { + printf ("Division Error var1=%d var2=%d\n", var1, var2); + exit (0); + } + if (var2 == 0) + { + printf ("Division by 0, Fatal error \n"); + exit (0); + } + if (var1 == 0) + { + var_out = 0; + } + else + { + if (var1 == var2) + { + var_out = MAX_16; + } + else + { + L_num = L_deposit_l (var1); +#if (WMOPS) + counter.L_deposit_l--; +#endif + L_denom = L_deposit_l (var2); +#if (WMOPS) + counter.L_deposit_l--; +#endif + + for (iteration = 0; iteration < 15; iteration++) + { + var_out <<= 1; + L_num <<= 1; + + if (L_num >= L_denom) + { + L_num = L_sub (L_num, L_denom); +#if (WMOPS) + counter.L_sub--; +#endif + var_out = add (var_out, 1); +#if (WMOPS) + counter.add--; +#endif + } + } + } + } + +#if (WMOPS) + counter.div_s++; +#endif + return (var_out); +} + +/*___________________________________________________________________________ + | | + | Function Name : norm_l | + | | + | Purpose : | + | | + | Produces the number of left shifts needed to normalize the 32 bit varia-| + | ble L_var1 for positive values on the interval with minimum of | + | 1073741824 and maximum of 2147483647, and for negative values on the in-| + | terval with minimum of -2147483648 and maximum of -1073741824; in order | + | to normalize the result, the following operation must be done : | + | norm_L_var1 = L_shl(L_var1,norm_l(L_var1)). | + | | + | Complexity weight : 30 | + | | + | Inputs : | + | | + | L_var1 | + | 32 bit long signed integer (Word32) whose value falls in the | + | range : 0x8000 0000 <= var1 <= 0x7fff ffff. | + | | + | Outputs : | + | | + | none | + | | + | Return Value : | + | | + | var_out | + | 16 bit short signed integer (Word16) whose value falls in the | + | range : 0x0000 0000 <= var_out <= 0x0000 001f. | + |___________________________________________________________________________| +*/ + +Word16 norm_l (Word32 L_var1) +{ + Word16 var_out; + + if (L_var1 == 0) + { + var_out = 0; + } + else + { + if (L_var1 == (Word32) 0xffffffffL) + { + var_out = 31; + } + else + { + if (L_var1 < 0) + { + L_var1 = ~L_var1; + } + for (var_out = 0; L_var1 < (Word32) 0x40000000L; var_out++) + { + L_var1 <<= 1; + } + } + } + +#if (WMOPS) + counter.norm_l++; +#endif + return (var_out); +} diff -r 000000000000 -r 56410792419a src/bits2prm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bits2prm.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,99 @@ +/************************************************************************* + * + * FUNCTION: Bits2prm_12k2 + * + * PURPOSE: Retrieves the vector of encoder parameters from the received + * serial bits in a frame. + * + * DESCRIPTION: The encoder parameters are: + * + * BFI bad frame indicator 1 bit + * + * LPC: + * 1st codebook 7 bit + * 2nd codebook 8 bit + * 3rd codebook 8+1 bit + * 4th codebook 8 bit + * 5th codebook 6 bit + * + * 1st and 3rd subframes: + * pitch period 9 bit + * pitch gain 4 bit + * codebook index 35 bit + * codebook gain 5 bit + * + * 2nd and 4th subframes: + * pitch period 6 bit + * pitch gain 4 bit + * codebook index 35 bit + * codebook gain 5 bit + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +/* Local function */ + +Word16 Bin2int ( /* Reconstructed parameter */ + Word16 no_of_bits, /* input : number of bits associated with value */ + Word16 *bitstream /* output: address where bits are written */ +); + +#define BIT_0 0 +#define BIT_1 1 +#define PRM_NO 57 + +void Bits2prm_12k2 ( + Word16 bits[], /* input : serial bits (244 + bfi) */ + Word16 prm[] /* output: analysis parameters (57+1 parameters) */ +) +{ + Word16 i; + + static const Word16 bitno[PRM_NO] = + { + 7, 8, 9, 8, 6, /* LSP VQ */ + 9, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, /* first subframe */ + 6, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, /* second subframe */ + 9, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, /* third subframe */ + 6, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5}; /* fourth subframe */ + + *prm++ = *bits++; move16 (); /* read BFI */ + + for (i = 0; i < PRM_NO; i++) + { + prm[i] = Bin2int (bitno[i], bits); move16 (); + bits += bitno[i]; + } + return; +} + +/************************************************************************* + * + * FUNCTION: Bin2int + * + * PURPOSE: Read "no_of_bits" bits from the array bitstream[] and convert + * to integer. + * + *************************************************************************/ + +Word16 Bin2int ( /* Reconstructed parameter */ + Word16 no_of_bits, /* input : number of bits associated with value */ + Word16 *bitstream /* output: address where bits are written */ +) +{ + Word16 value, i, bit; + + value = 0; move16 (); + for (i = 0; i < no_of_bits; i++) + { + value = shl (value, 1); + bit = *bitstream++; move16 (); + test (); + if (sub (bit, BIT_1) == 0) + value = add (value, 1); + } + return (value); +} diff -r 000000000000 -r 56410792419a src/c1035pf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/c1035pf.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,891 @@ +#include "typedef.h" +#include "basic_op.h" +#include "sig_proc.h" +#include "count.h" + +#define L_CODE 40 +#define NB_TRACK 5 +#define NB_PULSE 10 +#define STEP 5 + +/* local functions */ + +void cor_h_x ( + Word16 h[], /* (i) : impulse response of weighted synthesis filter */ + Word16 x[], /* (i) : target */ + Word16 dn[] /* (o) : correlation between target and h[] */ +); + +void set_sign ( + Word16 dn[], /* (i/o) : correlation between target and h[] */ + Word16 cn[], /* (i) : residual after long term prediction */ + Word16 sign[], /* (o) : sign of d[n] */ + Word16 pos_max[], /* (o) : position of maximum of dn[] */ + Word16 ipos[] /* (o) : starting position for each pulse */ +); + +void cor_h ( + Word16 h[], /* (i) : impulse response of weighted synthesis + filter */ + Word16 sign[], /* (i) : sign of d[n] */ + Word16 rr[][L_CODE] /* (o) : matrix of autocorrelation */ +); +void search_10i40 ( + Word16 dn[], /* (i) : correlation between target and h[] */ + Word16 rr[][L_CODE], /* (i) : matrix of autocorrelation */ + Word16 ipos[], /* (i) : starting position for each pulse */ + Word16 pos_max[], /* (i) : position of maximum of dn[] */ + Word16 codvec[] /* (o) : algebraic codebook vector */ +); +void build_code ( + Word16 codvec[], /* (i) : algebraic codebook vector */ + Word16 sign[], /* (i) : sign of dn[] */ + Word16 cod[], /* (o) : algebraic (fixed) codebook excitation */ + Word16 h[], /* (i) : impulse response of weighted synthesis filter*/ + Word16 y[], /* (o) : filtered fixed codebook excitation */ + Word16 indx[] /* (o) : index of 10 pulses (position+sign+ampl)*10 */ +); + +void q_p ( + Word16 *ind, /* Pulse position */ + Word16 n /* Pulse number */ +); + +/************************************************************************* + * + * FUNCTION: code_10i40_35bits() + * + * PURPOSE: Searches a 35 bit algebraic codebook containing 10 pulses + * in a frame of 40 samples. + * + * DESCRIPTION: + * The code contains 10 nonzero pulses: i0...i9. + * All pulses can have two possible amplitudes: +1 or -1. + * The 40 positions in a subframe are divided into 5 tracks of + * interleaved positions. Each track contains two pulses. + * The pulses can have the following possible positions: + * + * i0, i5 : 0, 5, 10, 15, 20, 25, 30, 35. + * i1, i6 : 1, 6, 11, 16, 21, 26, 31, 36. + * i2, i7 : 2, 7, 12, 17, 22, 27, 32, 37. + * i3, i8 : 3, 8, 13, 18, 23, 28, 33, 38. + * i4, i9 : 4, 9, 14, 19, 24, 29, 34, 39. + * + * Each pair of pulses require 1 bit for their signs and 6 bits for their + * positions (3 bits + 3 bits). This results in a 35 bit codebook. + * The function determines the optimal pulse signs and positions, builds + * the codevector, and computes the filtered codevector. + * + *************************************************************************/ + +void code_10i40_35bits ( + Word16 x[], /* (i) : target vector */ + Word16 cn[], /* (i) : residual after long term prediction */ + Word16 h[], /* (i) : impulse response of weighted synthesis filter + h[-L_subfr..-1] must be set to zero */ + Word16 cod[], /* (o) : algebraic (fixed) codebook excitation */ + Word16 y[], /* (o) : filtered fixed codebook excitation */ + Word16 indx[] /* (o) : index of 10 pulses (sign + position) */ +) +{ + Word16 ipos[NB_PULSE], pos_max[NB_TRACK], codvec[NB_PULSE]; + Word16 dn[L_CODE], sign[L_CODE]; + Word16 rr[L_CODE][L_CODE], i; + + cor_h_x (h, x, dn); + set_sign (dn, cn, sign, pos_max, ipos); + cor_h (h, sign, rr); + search_10i40 (dn, rr, ipos, pos_max, codvec); + build_code (codvec, sign, cod, h, y, indx); + for (i = 0; i < 10; i++) + { + q_p (&indx[i], i); + } + return; +} + +/************************************************************************* + * + * FUNCTION: cor_h_x() + * + * PURPOSE: Computes correlation between target signal "x[]" and + * impulse response"h[]". + * + * DESCRIPTION: + * The correlation is given by: + * d[n] = sum_{i=n}^{L-1} x[i] h[i-n] n=0,...,L-1 + * + * d[n] is normalized such that the sum of 5 maxima of d[n] corresponding + * to each position track does not saturate. + * + *************************************************************************/ +void cor_h_x ( + Word16 h[], /* (i) : impulse response of weighted synthesis filter */ + Word16 x[], /* (i) : target */ + Word16 dn[] /* (o) : correlation between target and h[] */ +) +{ + Word16 i, j, k; + Word32 s, y32[L_CODE], max, tot; + + /* first keep the result on 32 bits and find absolute maximum */ + + tot = 5; move32 (); + + for (k = 0; k < NB_TRACK; k++) + { + max = 0; move32 (); + for (i = k; i < L_CODE; i += STEP) + { + s = 0; move32 (); + for (j = i; j < L_CODE; j++) + s = L_mac (s, x[j], h[j - i]); + + y32[i] = s; move32 (); + + s = L_abs (s); + test (); + if (L_sub (s, max) > (Word32) 0L) + max = s; move32 (); + } + tot = L_add (tot, L_shr (max, 1)); + } + + j = sub (norm_l (tot), 2); /* multiply tot by 4 */ + + for (i = 0; i < L_CODE; i++) + { + dn[i] = round (L_shl (y32[i], j)); move16 (); + } +} + +/************************************************************************* + * + * FUNCTION set_sign() + * + * PURPOSE: Builds sign[] vector according to "dn[]" and "cn[]", and modifies + * dn[] to include the sign information (dn[i]=sign[i]*dn[i]). + * Also finds the position of maximum of correlation in each track + * and the starting position for each pulse. + * + *************************************************************************/ + +void set_sign ( + Word16 dn[], /* (i/o): correlation between target and h[] */ + Word16 cn[], /* (i) : residual after long term prediction */ + Word16 sign[], /* (o) : sign of d[n] */ + Word16 pos_max[], /* (o) : position of maximum correlation */ + Word16 ipos[] /* (o) : starting position for each pulse */ +) +{ + Word16 i, j; + Word16 val, cor, k_cn, k_dn, max, max_of_all, pos; + Word16 en[L_CODE]; /* correlation vector */ + Word32 s; + + /* calculate energy for normalization of cn[] and dn[] */ + + s = 256; move32 (); + for (i = 0; i < L_CODE; i++) + { + s = L_mac (s, cn[i], cn[i]); + } + s = Inv_sqrt (s); move32 (); + k_cn = extract_h (L_shl (s, 5)); + + s = 256; move32 (); + for (i = 0; i < L_CODE; i++) + { + s = L_mac (s, dn[i], dn[i]); + } + s = Inv_sqrt (s); move32 (); + k_dn = extract_h (L_shl (s, 5)); + + for (i = 0; i < L_CODE; i++) + { + val = dn[i]; move16 (); + cor = round (L_shl (L_mac (L_mult (k_cn, cn[i]), k_dn, val), 10)); + + test (); + if (cor >= 0) + { + sign[i] = 32767; move16 (); /* sign = +1 */ + } + else + { + sign[i] = -32767; move16 (); /* sign = -1 */ + cor = negate (cor); + val = negate (val); + } + /* modify dn[] according to the fixed sign */ + dn[i] = val; move16 (); + en[i] = cor; move16 (); + } + + max_of_all = -1; move16 (); + for (i = 0; i < NB_TRACK; i++) + { + max = -1; move16 (); + + for (j = i; j < L_CODE; j += STEP) + { + cor = en[j]; move16 (); + val = sub (cor, max); + test (); + if (val > 0) + { + max = cor; move16 (); + pos = j; move16 (); + } + } + /* store maximum correlation position */ + pos_max[i] = pos; move16 (); + val = sub (max, max_of_all); + test (); + if (val > 0) + { + max_of_all = max; move16 (); + /* starting position for i0 */ + ipos[0] = i; move16 (); + } + } + + /*----------------------------------------------------------------* + * Set starting position of each pulse. * + *----------------------------------------------------------------*/ + + pos = ipos[0]; move16 (); + ipos[5] = pos; move16 (); + + for (i = 1; i < NB_TRACK; i++) + { + pos = add (pos, 1); + if (sub (pos, NB_TRACK) >= 0) + { + pos = 0; move16 (); + } + ipos[i] = pos; move16 (); + ipos[i + 5] = pos; move16 (); + } +} + +void q_p ( + Word16 *ind, /* Pulse position */ + Word16 n /* Pulse number */ +) +{ + static const Word16 gray[8] = {0, 1, 3, 2, 6, 4, 5, 7}; + Word16 tmp; + + tmp = *ind; move16 (); + + test (); + if (sub (n, 5) < 0) + { + tmp = (tmp & 0x8) | gray[tmp & 0x7]; logic16 (); logic16 (); + logic16 (); + } + else + { + tmp = gray[tmp & 0x7]; logic16 (); move16 (); + } + + *ind = tmp; move16 (); +} + +/************************************************************************* + * + * FUNCTION: cor_h() + * + * PURPOSE: Computes correlations of h[] needed for the codebook search; + * and includes the sign information into the correlations. + * + * DESCRIPTION: The correlations are given by + * rr[i][j] = sum_{n=i}^{L-1} h[n-i] h[n-j]; i>=j; i,j=0,...,L-1 + * + * and the sign information is included by + * rr[i][j] = rr[i][j]*sign[i]*sign[j] + * + *************************************************************************/ + +void cor_h ( + Word16 h[], /* (i) : impulse response of weighted synthesis + filter */ + Word16 sign[], /* (i) : sign of d[n] */ + Word16 rr[][L_CODE] /* (o) : matrix of autocorrelation */ +) +{ + Word16 i, j, k, dec, h2[L_CODE]; + Word32 s; + + /* Scaling for maximum precision */ + + s = 2; move32 (); + for (i = 0; i < L_CODE; i++) + s = L_mac (s, h[i], h[i]); + + j = sub (extract_h (s), 32767); + test (); + if (j == 0) + { + for (i = 0; i < L_CODE; i++) + { + h2[i] = shr (h[i], 1); move16 (); + } + } + else + { + s = L_shr (s, 1); + k = extract_h (L_shl (Inv_sqrt (s), 7)); + k = mult (k, 32440); /* k = 0.99*k */ + + for (i = 0; i < L_CODE; i++) + { + h2[i] = round (L_shl (L_mult (h[i], k), 9)); + move16 (); + } + } + + /* build matrix rr[] */ + s = 0; move32 (); + i = L_CODE - 1; + for (k = 0; k < L_CODE; k++, i--) + { + s = L_mac (s, h2[k], h2[k]); + rr[i][i] = round (s); move16 (); + } + + for (dec = 1; dec < L_CODE; dec++) + { + s = 0; move32 (); + j = L_CODE - 1; + i = sub (j, dec); + for (k = 0; k < (L_CODE - dec); k++, i--, j--) + { + s = L_mac (s, h2[k], h2[k + dec]); + rr[j][i] = mult (round (s), mult (sign[i], sign[j])); + move16 (); + rr[i][j] = rr[j][i]; move16 (); + } + } +} + +/************************************************************************* + * + * FUNCTION search_10i40() + * + * PURPOSE: Search the best codevector; determine positions of the 10 pulses + * in the 40-sample frame. + * + *************************************************************************/ + +#define _1_2 (Word16)(32768L/2) +#define _1_4 (Word16)(32768L/4) +#define _1_8 (Word16)(32768L/8) +#define _1_16 (Word16)(32768L/16) +#define _1_32 (Word16)(32768L/32) +#define _1_64 (Word16)(32768L/64) +#define _1_128 (Word16)(32768L/128) + +void search_10i40 ( + Word16 dn[], /* (i) : correlation between target and h[] */ + Word16 rr[][L_CODE], /* (i) : matrix of autocorrelation */ + Word16 ipos[], /* (i) : starting position for each pulse */ + Word16 pos_max[], /* (i) : position of maximum of dn[] */ + Word16 codvec[] /* (o) : algebraic codebook vector */ +) +{ + Word16 i0, i1, i2, i3, i4, i5, i6, i7, i8, i9; + Word16 i, j, k, pos, ia, ib; + Word16 psk, ps, ps0, ps1, ps2, sq, sq2; + Word16 alpk, alp, alp_16; + Word16 rrv[L_CODE]; + Word32 s, alp0, alp1, alp2; + + /* fix i0 on maximum of correlation position */ + + i0 = pos_max[ipos[0]]; move16 (); + + /*------------------------------------------------------------------* + * i1 loop: * + *------------------------------------------------------------------*/ + + /* Default value */ + psk = -1; move16 (); + alpk = 1; move16 (); + for (i = 0; i < NB_PULSE; i++) + { + codvec[i] = i; move16 (); + } + + for (i = 1; i < NB_TRACK; i++) + { + i1 = pos_max[ipos[1]]; move16 (); + ps0 = add (dn[i0], dn[i1]); + alp0 = L_mult (rr[i0][i0], _1_16); + alp0 = L_mac (alp0, rr[i1][i1], _1_16); + alp0 = L_mac (alp0, rr[i0][i1], _1_8); + + /*----------------------------------------------------------------* + * i2 and i3 loop: * + *----------------------------------------------------------------*/ + + /* initialize 4 indices for next loop. */ + move16 (); /* initialize "rr[i3][i3]" pointer */ + move16 (); /* initialize "rr[i0][i3]" pointer */ + move16 (); /* initialize "rr[i1][i3]" pointer */ + move16 (); /* initialize "rrv[i3]" pointer */ + + for (i3 = ipos[3]; i3 < L_CODE; i3 += STEP) + { + s = L_mult (rr[i3][i3], _1_8); /* index incr= STEP+L_CODE */ + s = L_mac (s, rr[i0][i3], _1_4); /* index increment = STEP */ + s = L_mac (s, rr[i1][i3], _1_4); /* index increment = STEP */ + rrv[i3] = round (s); move16 (); + } + + /* Default value */ + sq = -1; move16 (); + alp = 1; move16 (); + ps = 0; move16 (); + ia = ipos[2]; move16 (); + ib = ipos[3]; move16 (); + + /* initialize 4 indices for i2 loop. */ + move16 (); /* initialize "dn[i2]" pointer */ + move16 (); /* initialize "rr[i2][i2]" pointer */ + move16 (); /* initialize "rr[i0][i2]" pointer */ + move16 (); /* initialize "rr[i1][i2]" pointer */ + + for (i2 = ipos[2]; i2 < L_CODE; i2 += STEP) + { + /* index increment = STEP */ + ps1 = add (ps0, dn[i2]); + + /* index incr= STEP+L_CODE */ + alp1 = L_mac (alp0, rr[i2][i2], _1_16); + /* index increment = STEP */ + alp1 = L_mac (alp1, rr[i0][i2], _1_8); + /* index increment = STEP */ + alp1 = L_mac (alp1, rr[i1][i2], _1_8); + + /* initialize 3 indices for i3 inner loop */ + move16 (); /* initialize "dn[i3]" pointer */ + move16 (); /* initialize "rrv[i3]" pointer */ + move16 (); /* initialize "rr[i2][i3]" pointer */ + + for (i3 = ipos[3]; i3 < L_CODE; i3 += STEP) + { + /* index increment = STEP */ + ps2 = add (ps1, dn[i3]); + + /* index increment = STEP */ + alp2 = L_mac (alp1, rrv[i3], _1_2); + /* index increment = STEP */ + alp2 = L_mac (alp2, rr[i2][i3], _1_8); + + sq2 = mult (ps2, ps2); + + alp_16 = round (alp2); + + s = L_msu (L_mult (alp, sq2), sq, alp_16); + + test (); + if (s > 0) + { + sq = sq2; move16 (); + ps = ps2; move16 (); + alp = alp_16; move16 (); + ia = i2; move16 (); + ib = i3; move16 (); + } + } + } + i2 = ia; move16 (); + i3 = ib; move16 (); + + /*----------------------------------------------------------------* + * i4 and i5 loop: * + *----------------------------------------------------------------*/ + + ps0 = ps; move16 (); + alp0 = L_mult (alp, _1_2); + + /* initialize 6 indices for next loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); move16 (); move16 (); move16 (); + + for (i5 = ipos[5]; i5 < L_CODE; i5 += STEP) + { + s = L_mult (rr[i5][i5], _1_8); + s = L_mac (s, rr[i0][i5], _1_4); + s = L_mac (s, rr[i1][i5], _1_4); + s = L_mac (s, rr[i2][i5], _1_4); + s = L_mac (s, rr[i3][i5], _1_4); + rrv[i5] = round (s); move16 (); + } + + /* Default value */ + sq = -1; move16 (); + alp = 1; move16 (); + ps = 0; move16 (); + ia = ipos[4]; move16 (); + ib = ipos[5]; move16 (); + + /* initialize 6 indices for i4 loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); move16 (); move16 (); move16 (); + + for (i4 = ipos[4]; i4 < L_CODE; i4 += STEP) + { + ps1 = add (ps0, dn[i4]); + + alp1 = L_mac (alp0, rr[i4][i4], _1_32); + alp1 = L_mac (alp1, rr[i0][i4], _1_16); + alp1 = L_mac (alp1, rr[i1][i4], _1_16); + alp1 = L_mac (alp1, rr[i2][i4], _1_16); + alp1 = L_mac (alp1, rr[i3][i4], _1_16); + + /* initialize 3 indices for i5 inner loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); + + for (i5 = ipos[5]; i5 < L_CODE; i5 += STEP) + { + ps2 = add (ps1, dn[i5]); + + alp2 = L_mac (alp1, rrv[i5], _1_4); + alp2 = L_mac (alp2, rr[i4][i5], _1_16); + + sq2 = mult (ps2, ps2); + + alp_16 = round (alp2); + + s = L_msu (L_mult (alp, sq2), sq, alp_16); + + test (); + if (s > 0) + { + sq = sq2; move16 (); + ps = ps2; move16 (); + alp = alp_16; move16 (); + ia = i4; move16 (); + ib = i5; move16 (); + } + } + } + i4 = ia; move16 (); + i5 = ib; move16 (); + + /*----------------------------------------------------------------* + * i6 and i7 loop: * + *----------------------------------------------------------------*/ + + ps0 = ps; move16 (); + alp0 = L_mult (alp, _1_2); + + /* initialize 8 indices for next loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); move16 (); + move16 (); move16 (); move16 (); move16 (); + + for (i7 = ipos[7]; i7 < L_CODE; i7 += STEP) + { + s = L_mult (rr[i7][i7], _1_16); + s = L_mac (s, rr[i0][i7], _1_8); + s = L_mac (s, rr[i1][i7], _1_8); + s = L_mac (s, rr[i2][i7], _1_8); + s = L_mac (s, rr[i3][i7], _1_8); + s = L_mac (s, rr[i4][i7], _1_8); + s = L_mac (s, rr[i5][i7], _1_8); + rrv[i7] = round (s); move16 (); + } + + /* Default value */ + sq = -1; move16 (); + alp = 1; move16 (); + ps = 0; move16 (); + ia = ipos[6]; move16 (); + ib = ipos[7]; move16 (); + + /* initialize 8 indices for i6 loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); move16 (); + move16 (); move16 (); move16 (); move16 (); + + for (i6 = ipos[6]; i6 < L_CODE; i6 += STEP) + { + ps1 = add (ps0, dn[i6]); + + alp1 = L_mac (alp0, rr[i6][i6], _1_64); + alp1 = L_mac (alp1, rr[i0][i6], _1_32); + alp1 = L_mac (alp1, rr[i1][i6], _1_32); + alp1 = L_mac (alp1, rr[i2][i6], _1_32); + alp1 = L_mac (alp1, rr[i3][i6], _1_32); + alp1 = L_mac (alp1, rr[i4][i6], _1_32); + alp1 = L_mac (alp1, rr[i5][i6], _1_32); + + /* initialize 3 indices for i7 inner loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); + + for (i7 = ipos[7]; i7 < L_CODE; i7 += STEP) + { + ps2 = add (ps1, dn[i7]); + + alp2 = L_mac (alp1, rrv[i7], _1_4); + alp2 = L_mac (alp2, rr[i6][i7], _1_32); + + sq2 = mult (ps2, ps2); + + alp_16 = round (alp2); + + s = L_msu (L_mult (alp, sq2), sq, alp_16); + + test (); + if (s > 0) + { + sq = sq2; move16 (); + ps = ps2; move16 (); + alp = alp_16; move16 (); + ia = i6; move16 (); + ib = i7; move16 (); + } + } + } + i6 = ia; move16 (); + i7 = ib; move16 (); + + /*----------------------------------------------------------------* + * i8 and i9 loop: * + *----------------------------------------------------------------*/ + + ps0 = ps; move16 (); + alp0 = L_mult (alp, _1_2); + + /* initialize 10 indices for next loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); move16 (); move16 (); + move16 (); move16 (); move16 (); move16 (); move16 (); + + for (i9 = ipos[9]; i9 < L_CODE; i9 += STEP) + { + s = L_mult (rr[i9][i9], _1_16); + s = L_mac (s, rr[i0][i9], _1_8); + s = L_mac (s, rr[i1][i9], _1_8); + s = L_mac (s, rr[i2][i9], _1_8); + s = L_mac (s, rr[i3][i9], _1_8); + s = L_mac (s, rr[i4][i9], _1_8); + s = L_mac (s, rr[i5][i9], _1_8); + s = L_mac (s, rr[i6][i9], _1_8); + s = L_mac (s, rr[i7][i9], _1_8); + rrv[i9] = round (s); move16 (); + } + + /* Default value */ + sq = -1; move16 (); + alp = 1; move16 (); + ps = 0; move16 (); + ia = ipos[8]; move16 (); + ib = ipos[9]; move16 (); + + /* initialize 10 indices for i8 loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); move16 (); move16 (); + move16 (); move16 (); move16 (); move16 (); move16 (); + + for (i8 = ipos[8]; i8 < L_CODE; i8 += STEP) + { + ps1 = add (ps0, dn[i8]); + + alp1 = L_mac (alp0, rr[i8][i8], _1_128); + alp1 = L_mac (alp1, rr[i0][i8], _1_64); + alp1 = L_mac (alp1, rr[i1][i8], _1_64); + alp1 = L_mac (alp1, rr[i2][i8], _1_64); + alp1 = L_mac (alp1, rr[i3][i8], _1_64); + alp1 = L_mac (alp1, rr[i4][i8], _1_64); + alp1 = L_mac (alp1, rr[i5][i8], _1_64); + alp1 = L_mac (alp1, rr[i6][i8], _1_64); + alp1 = L_mac (alp1, rr[i7][i8], _1_64); + + /* initialize 3 indices for i9 inner loop (see i2-i3 loop) */ + move16 (); move16 (); move16 (); + + for (i9 = ipos[9]; i9 < L_CODE; i9 += STEP) + { + ps2 = add (ps1, dn[i9]); + + alp2 = L_mac (alp1, rrv[i9], _1_8); + alp2 = L_mac (alp2, rr[i8][i9], _1_64); + + sq2 = mult (ps2, ps2); + + alp_16 = round (alp2); + + s = L_msu (L_mult (alp, sq2), sq, alp_16); + + test (); + if (s > 0) + { + sq = sq2; move16 (); + ps = ps2; move16 (); + alp = alp_16; move16 (); + ia = i8; move16 (); + ib = i9; move16 (); + } + } + } + + /*----------------------------------------------------------------* + * memorise codevector if this one is better than the last one. * + *----------------------------------------------------------------*/ + + s = L_msu (L_mult (alpk, sq), psk, alp); + + test (); + if (s > 0) + { + psk = sq; move16 (); + alpk = alp; move16 (); + codvec[0] = i0; move16 (); + codvec[1] = i1; move16 (); + codvec[2] = i2; move16 (); + codvec[3] = i3; move16 (); + codvec[4] = i4; move16 (); + codvec[5] = i5; move16 (); + codvec[6] = i6; move16 (); + codvec[7] = i7; move16 (); + codvec[8] = ia; move16 (); + codvec[9] = ib; move16 (); + } + /*----------------------------------------------------------------* + * Cyclic permutation of i1,i2,i3,i4,i5,i6,i7,i8 and i9. * + *----------------------------------------------------------------*/ + + pos = ipos[1]; move16 (); + for (j = 1, k = 2; k < NB_PULSE; j++, k++) + { + ipos[j] = ipos[k]; move16 (); + } + ipos[NB_PULSE - 1] = pos; move16 (); +} +} + +/************************************************************************* + * + * FUNCTION: build_code() + * + * PURPOSE: Builds the codeword, the filtered codeword and index of the + * codevector, based on the signs and positions of 10 pulses. + * + *************************************************************************/ + +void build_code ( + Word16 codvec[], /* (i) : position of pulses */ + Word16 sign[], /* (i) : sign of d[n] */ + Word16 cod[], /* (o) : innovative code vector */ + Word16 h[], /* (i) : impulse response of weighted synthesis filter*/ + Word16 y[], /* (o) : filtered innovative code */ + Word16 indx[] /* (o) : index of 10 pulses (sign+position) */ +) +{ + Word16 i, j, k, track, index, _sign[NB_PULSE]; + Word16 *p0, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9; + Word32 s; + + for (i = 0; i < L_CODE; i++) + { + cod[i] = 0; move16 (); + } + for (i = 0; i < NB_TRACK; i++) + { + indx[i] = -1; move16 (); + } + + for (k = 0; k < NB_PULSE; k++) + { + /* read pulse position */ + i = codvec[k]; move16 (); + /* read sign */ + j = sign[i]; move16 (); + + index = mult (i, 6554); /* index = pos/5 */ + /* track = pos%5 */ + track = sub (i, extract_l (L_shr (L_mult (index, 5), 1))); + test (); + if (j > 0) + { + cod[i] = add (cod[i], 4096); + _sign[k] = 8192; move16 (); + + } + else + { + cod[i] = sub (cod[i], 4096); + _sign[k] = -8192; move16 (); + index = add (index, 8); + } + + test (); + if (indx[track] < 0) + { + indx[track] = index; move16 (); + } + else + { + test (); logic16 (); logic16 (); + if (((index ^ indx[track]) & 8) == 0) + { + /* sign of 1st pulse == sign of 2nd pulse */ + + test (); + if (sub (indx[track], index) <= 0) + { + indx[track + 5] = index; move16 (); + } + else + { + indx[track + 5] = indx[track]; + move16 (); + indx[track] = index; move16 (); + } + } + else + { + /* sign of 1st pulse != sign of 2nd pulse */ + + test (); logic16 (); logic16 (); + if (sub ((indx[track] & 7), (index & 7)) <= 0) + { + indx[track + 5] = indx[track]; + move16 (); + indx[track] = index; move16 (); + } + else + { + indx[track + 5] = index; move16 (); + } + } + } + } + + p0 = h - codvec[0]; move16 (); + p1 = h - codvec[1]; move16 (); + p2 = h - codvec[2]; move16 (); + p3 = h - codvec[3]; move16 (); + p4 = h - codvec[4]; move16 (); + p5 = h - codvec[5]; move16 (); + p6 = h - codvec[6]; move16 (); + p7 = h - codvec[7]; move16 (); + p8 = h - codvec[8]; move16 (); + p9 = h - codvec[9]; move16 (); + + for (i = 0; i < L_CODE; i++) + { + s = 0; move32 (); + s = L_mac (s, *p0++, _sign[0]); + s = L_mac (s, *p1++, _sign[1]); + s = L_mac (s, *p2++, _sign[2]); + s = L_mac (s, *p3++, _sign[3]); + s = L_mac (s, *p4++, _sign[4]); + s = L_mac (s, *p5++, _sign[5]); + s = L_mac (s, *p6++, _sign[6]); + s = L_mac (s, *p7++, _sign[7]); + s = L_mac (s, *p8++, _sign[8]); + s = L_mac (s, *p9++, _sign[9]); + y[i] = round (s); move16 (); + } +} + diff -r 000000000000 -r 56410792419a src/cnst.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cnst.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------* +* Codec constant parameters (coder, decoder, and postfilter) * +*---------------------------------------------------------------------------*/ + +#define L_TOTAL 320 /* Total size of speech buffer. */ +#define L_WINDOW 240 /* Window size in LP analysis */ +#define L_FRAME 160 /* Frame size */ +#define L_FRAME_BY2 80 /* Frame size divided by 2 */ +#define L_SUBFR 40 /* Subframe size */ +#define M 10 /* Order of LP filter */ +#define MP1 (M+1) /* Order of LP filter + 1 */ +#define AZ_SIZE (4*M+4) /* Size of array of LP filters in 4 subfr.s */ +#define PIT_MIN 18 /* Minimum pitch lag */ +#define PIT_MAX 143 /* Maximum pitch lag */ +#define L_INTERPOL (10+1) /* Length of filter for interpolation */ + +#define PRM_SIZE 57 /* Size of vector of analysis parameters */ +#define SERIAL_SIZE (244+1) /* bits per frame + bfi */ + +#define MU 26214 /* Factor for tilt compensation filter 0.8 */ +#define AGC_FAC 29491 /* Factor for automatic gain control 0.9 */ diff -r 000000000000 -r 56410792419a src/cod_12k2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cod_12k2.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,834 @@ +/*************************************************************************** + * + * FILE NAME: cod_12k2.c + * + * FUNCTIONS DEFINED IN THIS FILE: + * Coder_12k2 and Init_Coder_12k2 + * + * + * Init_Coder_12k2(void): + * Initialization of variables for the coder section. + * + * Coder_12k2(Word16 ana[], Word16 synth[]): + * Speech encoder routine operating on a frame basis. + * + +***************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "sig_proc.h" +#include "count.h" +#include "codec.h" +#include "cnst.h" + +#include "window2.tab" + +#include "vad.h" +#include "dtx.h" + +/*-----------------------------------------------------------* + * Coder constant parameters (defined in "cnst.h") * + *-----------------------------------------------------------* + * L_WINDOW : LPC analysis window size * + * L_FRAME : Frame size * + * L_FRAME_BY2 : Half the frame size * + * L_SUBFR : Sub-frame size * + * M : LPC order * + * MP1 : LPC order+1 * + * L_TOTAL : Total size of speech buffer * + * PIT_MIN : Minimum pitch lag * + * PIT_MAX : Maximum pitch lag * + * L_INTERPOL : Length of filter for interpolation * + *-----------------------------------------------------------*/ + +/*--------------------------------------------------------* + * Static memory allocation. * + *--------------------------------------------------------*/ + + /* Speech vector */ + +static Word16 old_speech[L_TOTAL]; +static Word16 *speech, *p_window, *p_window_mid; +Word16 *new_speech; /* Global variable */ + + /* Weight speech vector */ + +static Word16 old_wsp[L_FRAME + PIT_MAX]; +static Word16 *wsp; + + /* Excitation vector */ + +static Word16 old_exc[L_FRAME + PIT_MAX + L_INTERPOL]; +static Word16 *exc; + + /* Zero vector */ + +static Word16 ai_zero[L_SUBFR + MP1]; +static Word16 *zero; + + /* Impulse response vector */ + +static Word16 *h1; +static Word16 hvec[L_SUBFR * 2]; + + /* Spectral expansion factors */ + +static const Word16 F_gamma1[M] = +{ + 29491, 26542, 23888, 21499, 19349, + 17414, 15672, 14105, 12694, 11425 +}; +static const Word16 F_gamma2[M] = +{ + 19661, 11797, 7078, 4247, 2548, + 1529, 917, 550, 330, 198 +}; + + /* Lsp (Line spectral pairs) */ + +static Word16 lsp_old[M]; +static Word16 lsp_old_q[M]; + + /* Filter's memory */ + +static Word16 mem_syn[M], mem_w0[M], mem_w[M]; +static Word16 mem_err[M + L_SUBFR], *error; + +/*************************************************************************** + * FUNCTION: Init_Coder_12k2 + * + * PURPOSE: Initialization of variables for the coder section. + * + * DESCRIPTION: + * - initilize pointers to speech buffer + * - initialize static pointers + * - set static vectors to zero + * + ***************************************************************************/ + +void Init_Coder_12k2 (void) +{ + +/*--------------------------------------------------------------------------* + * Initialize pointers to speech vector. * + *--------------------------------------------------------------------------*/ + + new_speech = old_speech + L_TOTAL - L_FRAME;/* New speech */ + speech = new_speech; /* Present frame */ + p_window = old_speech + L_TOTAL - L_WINDOW; /* For LPC window */ + p_window_mid = p_window; /* For LPC window */ + + /* Initialize static pointers */ + + wsp = old_wsp + PIT_MAX; + exc = old_exc + PIT_MAX + L_INTERPOL; + zero = ai_zero + MP1; + error = mem_err + M; + h1 = &hvec[L_SUBFR]; + + /* Static vectors to zero */ + + Set_zero (old_speech, L_TOTAL); + Set_zero (old_exc, PIT_MAX + L_INTERPOL); + Set_zero (old_wsp, PIT_MAX); + Set_zero (mem_syn, M); + Set_zero (mem_w, M); + Set_zero (mem_w0, M); + Set_zero (mem_err, M); + Set_zero (zero, L_SUBFR); + Set_zero (hvec, L_SUBFR); /* set to zero "h1[-L_SUBFR..-1]" */ + + /* Initialize lsp_old [] */ + + lsp_old[0] = 30000; + lsp_old[1] = 26000; + lsp_old[2] = 21000; + lsp_old[3] = 15000; + lsp_old[4] = 8000; + lsp_old[5] = 0; + lsp_old[6] = -8000; + lsp_old[7] = -15000; + lsp_old[8] = -21000; + lsp_old[9] = -26000; + + /* Initialize lsp_old_q[] */ + + Copy (lsp_old, lsp_old_q, M); + + return; +} + +/*************************************************************************** + * FUNCTION: Coder_12k2 + * + * PURPOSE: Principle encoder routine. + * + * DESCRIPTION: This function is called every 20 ms speech frame, + * operating on the newly read 160 speech samples. It performs the + * principle encoding functions to produce the set of encoded parameters + * which include the LSP, adaptive codebook, and fixed codebook + * quantization indices (addresses and gains). + * + * INPUTS: + * No input arguments are passed to this function. However, before + * calling this function, 160 new speech data samples should be copied to + * the vector new_speech[]. This is a global pointer which is declared in + * this file (it points to the end of speech buffer minus 160). + * + * OUTPUTS: + * + * ana[]: vector of analysis parameters. + * synth[]: Local synthesis speech (for debugging purposes) + * + ***************************************************************************/ + +void Coder_12k2 ( + Word16 ana[], /* output : Analysis parameters */ + Word16 synth[] /* output : Local synthesis */ +) +{ + /* LPC coefficients */ + + Word16 r_l[MP1], r_h[MP1]; /* Autocorrelations lo and hi */ + Word16 A_t[(MP1) * 4]; /* A(z) unquantized for the 4 subframes */ + Word16 Aq_t[(MP1) * 4]; /* A(z) quantized for the 4 subframes */ + Word16 Ap1[MP1]; /* A(z) with spectral expansion */ + Word16 Ap2[MP1]; /* A(z) with spectral expansion */ + Word16 *A, *Aq; /* Pointer on A_t and Aq_t */ + Word16 lsp_new[M], lsp_new_q[M];/* LSPs at 4th subframe */ + Word16 lsp_mid[M], lsp_mid_q[M];/* LSPs at 2nd subframe */ + + /* Other vectors */ + + Word16 xn[L_SUBFR]; /* Target vector for pitch search */ + Word16 xn2[L_SUBFR]; /* Target vector for codebook search */ + Word16 res2[L_SUBFR]; /* Long term prediction residual */ + Word16 code[L_SUBFR]; /* Fixed codebook excitation */ + Word16 y1[L_SUBFR]; /* Filtered adaptive excitation */ + Word16 y2[L_SUBFR]; /* Filtered fixed codebook excitation */ + + /* Scalars */ + + Word16 i, j, k, i_subfr; + Word16 T_op, T0, T0_min, T0_max, T0_frac; + Word16 gain_pit, gain_code, pit_flag, pit_sharp; + Word16 temp; + Word32 L_temp; + + Word16 scal_acf, VAD_flag, lags[2], rc[4]; + + extern Word16 ptch; + extern Word16 txdtx_ctrl, CN_excitation_gain; + extern Word32 L_pn_seed_tx; + extern Word16 dtx_mode; + + /*----------------------------------------------------------------------* + * - Perform LPC analysis: (twice per frame) * + * * autocorrelation + lag windowing * + * * Levinson-Durbin algorithm to find a[] * + * * convert a[] to lsp[] * + * * quantize and code the LSPs * + * * find the interpolated LSPs and convert to a[] for all * + * subframes (both quantized and unquantized) * + *----------------------------------------------------------------------*/ + + /* LP analysis centered at 2nd subframe */ + + + scal_acf = Autocorr (p_window_mid, M, r_h, r_l, window_160_80); + /* Autocorrelations */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Lag_window (M, r_h, r_l); /* Lag windowing */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Levinson (r_h, r_l, &A_t[MP1], rc); /* Levinson-Durbin */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Az_lsp (&A_t[MP1], lsp_mid, lsp_old); /* From A(z) to lsp */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /* LP analysis centered at 4th subframe */ + + /* Autocorrelations */ + scal_acf = Autocorr (p_window, M, r_h, r_l, window_232_8); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Lag_window (M, r_h, r_l); /* Lag windowing */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Levinson (r_h, r_l, &A_t[MP1 * 3], rc); /* Levinson-Durbin */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Az_lsp (&A_t[MP1 * 3], lsp_new, lsp_mid); /* From A(z) to lsp */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + if (dtx_mode == 1) + { + /* DTX enabled, make voice activity decision */ + VAD_flag = vad_computation (r_h, r_l, scal_acf, rc, ptch); + move16 (); + + tx_dtx (VAD_flag, &txdtx_ctrl); /* TX DTX handler */ + } + else + { + /* DTX disabled, active speech in every frame */ + VAD_flag = 1; + txdtx_ctrl = TX_VAD_FLAG | TX_SP_FLAG; + } + + /* LSP quantization (lsp_mid[] and lsp_new[] jointly quantized) */ + + Q_plsf_5 (lsp_mid, lsp_new, lsp_mid_q, lsp_new_q, ana, txdtx_ctrl); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + ana += 5; move16 (); + + /*--------------------------------------------------------------------* + * Find interpolated LPC parameters in all subframes (both quantized * + * and unquantized). * + * The interpolated parameters are in array A_t[] of size (M+1)*4 * + * and the quantized interpolated parameters are in array Aq_t[] * + *--------------------------------------------------------------------*/ + + Int_lpc2 (lsp_old, lsp_mid, lsp_new, A_t); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + Int_lpc (lsp_old_q, lsp_mid_q, lsp_new_q, Aq_t); + + /* update the LSPs for the next frame */ + for (i = 0; i < M; i++) + { + lsp_old[i] = lsp_new[i]; move16 (); + lsp_old_q[i] = lsp_new_q[i]; move16 (); + } + } + else + { + /* Use unquantized LPC parameters in case of no speech activity */ + for (i = 0; i < MP1; i++) + { + Aq_t[i] = A_t[i]; move16 (); + Aq_t[i + MP1] = A_t[i + MP1]; move16 (); + Aq_t[i + MP1 * 2] = A_t[i + MP1 * 2]; move16 (); + Aq_t[i + MP1 * 3] = A_t[i + MP1 * 3]; move16 (); + } + + /* update the LSPs for the next frame */ + for (i = 0; i < M; i++) + { + lsp_old[i] = lsp_new[i]; move16 (); + lsp_old_q[i] = lsp_new[i]; move16 (); + } + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*----------------------------------------------------------------------* + * - Find the weighted input speech wsp[] for the whole speech frame * + * - Find the open-loop pitch delay for first 2 subframes * + * - Set the range for searching closed-loop pitch in 1st subframe * + * - Find the open-loop pitch delay for last 2 subframes * + *----------------------------------------------------------------------*/ + + A = A_t; move16 (); + for (i = 0; i < L_FRAME; i += L_SUBFR) + { + Weight_Ai (A, F_gamma1, Ap1); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Weight_Ai (A, F_gamma2, Ap2); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Residu (Ap1, &speech[i], &wsp[i], L_SUBFR); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Syn_filt (Ap2, &wsp[i], &wsp[i], L_SUBFR, mem_w, 1); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + A += MP1; move16 (); + } + + /* Find open loop pitch lag for first two subframes */ + + T_op = Pitch_ol (wsp, PIT_MIN, PIT_MAX, L_FRAME_BY2); move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + lags[0] = T_op; move16 (); + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + /* Range for closed loop pitch search in 1st subframe */ + + T0_min = sub (T_op, 3); + test (); + if (sub (T0_min, PIT_MIN) < 0) + { + T0_min = PIT_MIN; move16 (); + } + T0_max = add (T0_min, 6); + test (); + if (sub (T0_max, PIT_MAX) > 0) + { + T0_max = PIT_MAX; move16 (); + T0_min = sub (T0_max, 6); + } +#if (WMOPS) + fwc (); /* function worst case */ +#endif + } + /* Find open loop pitch lag for last two subframes */ + + T_op = Pitch_ol (&wsp[L_FRAME_BY2], PIT_MIN, PIT_MAX, L_FRAME_BY2); + move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + if (dtx_mode == 1) + { + lags[1] = T_op; move16 (); + periodicity_update (lags, &ptch); + } + /*----------------------------------------------------------------------* + * Loop for every subframe in the analysis frame * + *----------------------------------------------------------------------* + * To find the pitch and innovation parameters. The subframe size is * + * L_SUBFR and the loop is repeated L_FRAME/L_SUBFR times. * + * - find the weighted LPC coefficients * + * - find the LPC residual signal res[] * + * - compute the target signal for pitch search * + * - compute impulse response of weighted synthesis filter (h1[]) * + * - find the closed-loop pitch parameters * + * - encode the pitch delay * + * - update the impulse response h1[] by including pitch * + * - find target vector for codebook search * + * - codebook search * + * - encode codebook address * + * - VQ of pitch and codebook gains * + * - find synthesis speech * + * - update states of weighting filter * + *----------------------------------------------------------------------*/ + + /* pointer to interpolated LPC parameters */ + A = A_t; move16 (); + /* pointer to interpolated quantized LPC parameters */ + Aq = Aq_t; move16 (); + + for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) + { + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + + /*---------------------------------------------------------------* + * Find the weighted LPC coefficients for the weighting filter. * + *---------------------------------------------------------------*/ + + Weight_Ai (A, F_gamma1, Ap1); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Weight_Ai (A, F_gamma2, Ap2); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*---------------------------------------------------------------* + * Compute impulse response, h1[], of weighted synthesis filter * + *---------------------------------------------------------------*/ + + for (i = 0; i <= M; i++) + { + ai_zero[i] = Ap1[i]; move16 (); + } + + Syn_filt (Aq, ai_zero, h1, L_SUBFR, zero, 0); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Syn_filt (Ap2, h1, h1, L_SUBFR, zero, 0); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + } + /*---------------------------------------------------------------* + * Find the target vector for pitch search: * + *---------------------------------------------------------------*/ + + Residu (Aq, &speech[i_subfr], res2, L_SUBFR); /* LPC residual */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) == 0) + { + /* Compute comfort noise excitation gain based on + LP residual energy */ + + CN_excitation_gain = compute_CN_excitation_gain (res2); + move16 (); + } + else + { + Copy (res2, &exc[i_subfr], L_SUBFR); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Syn_filt (Aq, &exc[i_subfr], error, L_SUBFR, mem_err, 0); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Residu (Ap1, error, xn, L_SUBFR); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Syn_filt (Ap2, xn, xn, L_SUBFR, mem_w0, 0); /* target signal xn[]*/ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*--------------------------------------------------------------* + * Closed-loop fractional pitch search * + *--------------------------------------------------------------*/ + + /* flag for first and 3th subframe */ + pit_flag = i_subfr; move16 (); + test (); + /* set t0_min and t0_max for 3th subf.*/ + if (sub (i_subfr, L_FRAME_BY2) == 0) + { + T0_min = sub (T_op, 3); + + test (); + if (sub (T0_min, PIT_MIN) < 0) + { + T0_min = PIT_MIN; move16 (); + } + T0_max = add (T0_min, 6); + test (); + if (sub (T0_max, PIT_MAX) > 0) + { + T0_max = PIT_MAX; move16 (); + T0_min = sub (T0_max, 6); + } + pit_flag = 0; move16 (); + } +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + T0 = Pitch_fr6 (&exc[i_subfr], xn, h1, L_SUBFR, T0_min, T0_max, + pit_flag, &T0_frac); move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + *ana = Enc_lag6 (T0, &T0_frac, &T0_min, &T0_max, PIT_MIN, + PIT_MAX, pit_flag); + move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + } + ana++; + /* Incrementation of ana is done here to work also + when no speech activity is present */ + + test (); logic16 (); + + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + + /*---------------------------------------------------------------* + * - find unity gain pitch excitation (adaptive codebook entry) * + * with fractional interpolation. * + * - find filtered pitch exc. y1[]=exc[] convolved with h1[] * + * - compute pitch gain and limit between 0 and 1.2 * + * - update target vector for codebook search * + * - find LTP residual. * + *---------------------------------------------------------------*/ + + Pred_lt_6 (&exc[i_subfr], T0, T0_frac, L_SUBFR); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Convolve (&exc[i_subfr], h1, y1, L_SUBFR); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + gain_pit = G_pitch (xn, y1, L_SUBFR); move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + *ana = q_gain_pitch (&gain_pit); move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + } + else + { + gain_pit = 0; move16 (); + } + + ana++; /* Incrementation of ana is done here to work + also when no speech activity is present */ + + test (); logic16 (); + + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + /* xn2[i] = xn[i] - y1[i] * gain_pit */ + /* res2[i] -= exc[i+i_subfr] * gain_pit */ + + for (i = 0; i < L_SUBFR; i++) + { + L_temp = L_mult (y1[i], gain_pit); + L_temp = L_shl (L_temp, 3); + xn2[i] = sub (xn[i], extract_h (L_temp)); move16 (); + + L_temp = L_mult (exc[i + i_subfr], gain_pit); + L_temp = L_shl (L_temp, 3); + res2[i] = sub (res2[i], extract_h (L_temp)); move16 (); + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*-------------------------------------------------------------* + * - include pitch contribution into impulse resp. h1[] * + *-------------------------------------------------------------*/ + + /* pit_sharp = gain_pit; */ + /* if (pit_sharp > 1.0) pit_sharp = 1.0; */ + + pit_sharp = shl (gain_pit, 3); + + for (i = T0; i < L_SUBFR; i++) + { + temp = mult (h1[i - T0], pit_sharp); + h1[i] = add (h1[i], temp); move16 (); + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*--------------------------------------------------------------* + * - Innovative codebook search (find index and gain) * + *--------------------------------------------------------------*/ + + code_10i40_35bits (xn2, res2, h1, code, y2, ana); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + } + else + { + build_CN_code (code, &L_pn_seed_tx); + } + ana += 10; move16 (); + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + + /*-------------------------------------------------------* + * - Add the pitch contribution to code[]. * + *-------------------------------------------------------*/ + + for (i = T0; i < L_SUBFR; i++) + { + temp = mult (code[i - T0], pit_sharp); + code[i] = add (code[i], temp); move16 (); + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*------------------------------------------------------* + * - Quantization of fixed codebook gain. * + *------------------------------------------------------*/ + + gain_code = G_code (xn2, y2); move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + } + *ana++ = q_gain_code (code, L_SUBFR, &gain_code, txdtx_ctrl, i_subfr); + move16 (); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*------------------------------------------------------* + * - Find the total excitation * + * - find synthesis speech corresponding to exc[] * + * - update filter memories for finding the target * + * vector in the next subframe * + * (update mem_err[] and mem_w0[]) * + *------------------------------------------------------*/ + + for (i = 0; i < L_SUBFR; i++) + { + /* exc[i] = gain_pit*exc[i] + gain_code*code[i]; */ + + L_temp = L_mult (exc[i + i_subfr], gain_pit); + L_temp = L_mac (L_temp, code[i], gain_code); + L_temp = L_shl (L_temp, 3); + exc[i + i_subfr] = round (L_temp); move16 (); + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Syn_filt (Aq, &exc[i_subfr], &synth[i_subfr], L_SUBFR, mem_syn, 1); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + + for (i = L_SUBFR - M, j = 0; i < L_SUBFR; i++, j++) + { + mem_err[j] = sub (speech[i_subfr + i], synth[i_subfr + i]); + move16 (); + temp = extract_h (L_shl (L_mult (y1[i], gain_pit), 3)); + k = extract_h (L_shl (L_mult (y2[i], gain_code), 5)); + mem_w0[j] = sub (xn[i], add (temp, k)); move16 (); + } + } + else + { + for (j = 0; j < M; j++) + { + mem_err[j] = 0; move16 (); + mem_w0[j] = 0; move16 (); + } + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + /* interpolated LPC parameters for next subframe */ + A += MP1; move16 (); + Aq += MP1; move16 (); + } + + /*--------------------------------------------------* + * Update signal for next frame. * + * -> shift to the left by L_FRAME: * + * speech[], wsp[] and exc[] * + *--------------------------------------------------*/ + + Copy (&old_speech[L_FRAME], &old_speech[0], L_TOTAL - L_FRAME); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Copy (&old_wsp[L_FRAME], &old_wsp[0], PIT_MAX); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Copy (&old_exc[L_FRAME], &old_exc[0], PIT_MAX + L_INTERPOL); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + return; +} diff -r 000000000000 -r 56410792419a src/codec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/codec.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,170 @@ +void Init_Coder_12k2 (void); + +void Coder_12k2 ( + Word16 ana[], /* output : Analysis parameters */ + Word16 synth[] /* output : Local synthesis */ +); + +void Init_Decoder_12k2 (void); + +void Decoder_12k2 ( + Word16 parm[], /* input : vector of synthesis parameters + parm[0] = bad frame indicator (bfi) */ + Word16 synth[], /* output: synthesis speech */ + Word16 A_t[], /* output: decoded LP filter in 4 subframes */ + Word16 TAF, + Word16 SID_flag +); + +void Init_Post_Filter (void); + +void Post_Filter ( + Word16 *syn, /* in/out: synthesis speech (postfiltered is output) */ + Word16 *Az_4 /* input : interpolated LPC parameters in all subfr. */ +); + +void code_10i40_35bits ( + Word16 x[], /* (i) : target vector */ + Word16 cn[], /* (i) : residual after long term prediction */ + Word16 h[], /* (i) : impulse response of weighted synthesis + filter */ + Word16 cod[], /* (o) : algebraic (fixed) codebook excitation */ + Word16 y[], /* (o) : filtered fixed codebook excitation */ + Word16 indx[] /* (o) : index of 10 pulses (sign + position) */ +); +void dec_10i40_35bits ( + Word16 index[], /* (i) : index of 10 pulses (sign+position) */ + Word16 cod[] /* (o) : algebraic (fixed) codebook excitation */ +); +Word16 Dec_lag6 ( /* output: return integer pitch lag */ + Word16 index, /* input : received pitch index */ + Word16 pit_min, /* input : minimum pitch lag */ + Word16 pit_max, /* input : maximum pitch lag */ + Word16 i_subfr, /* input : subframe flag */ + Word16 L_frame_by2,/* input : speech frame size divided by 2 */ + Word16 *T0_frac, /* output: fractional part of pitch lag */ + Word16 bfi /* input : bad frame indicator */ +); +Word16 d_gain_pitch ( /* out : quantized pitch gain */ + Word16 index, /* in : index of quantization */ + Word16 bfi, /* in : bad frame indicator (good = 0) */ + Word16 state, /* in : state of the state machine */ + Word16 prev_bf, /* Previous bf */ + Word16 rxdtx_ctrl + +); +void d_gain_code ( + Word16 index, /* input : received quantization index */ + Word16 code[], /* input : innovation codevector */ + Word16 lcode, /* input : codevector length */ + Word16 *gain_code, /* output: decoded innovation gain */ + Word16 bfi, /* input : bad frame indicator */ + Word16 state, /* in : state of the state machine */ + Word16 prev_bf, /* Previous bf */ + Word16 rxdtx_ctrl, + Word16 i_subfr, + Word16 rx_dtx_state + +); +void D_plsf_5 ( + Word16 *indice, /* input : quantization indices of 5 submatrices */ + Word16 *lsp1_q, /* output: quantized 1st LSP vector */ + Word16 *lsp2_q, /* output: quantized 2nd LSP vector */ + Word16 bfi, /* input : bad frame indicator (set to 1 if a bad + frame is received) */ + Word16 rxdtx_ctrl, + Word16 rx_dtx_state +); +Word16 Enc_lag6 ( /* output: Return index of encoding */ + Word16 T0, /* input : Pitch delay */ + Word16 *T0_frac, /* in/out: Fractional pitch delay */ + Word16 *T0_min, /* in/out: Minimum search delay */ + Word16 *T0_max, /* in/out: Maximum search delay */ + Word16 pit_min, /* input : Minimum pitch delay */ + Word16 pit_max, /* input : Maximum pitch delay */ + Word16 pit_flag /* input : Flag for 1st or 3rd subframe */ +); + +Word16 q_gain_pitch ( /* Return index of quantization */ + Word16 *gain /* (i) : Pitch gain to quantize */ +); + +Word16 q_gain_code ( /* Return quantization index */ + Word16 code[], /* (i) : fixed codebook excitation */ + Word16 lcode, /* (i) : codevector size */ + Word16 *gain, /* (i/o) : quantized fixed codebook gain */ + Word16 txdtx_ctrl, + Word16 i_subfr +); + +Word16 G_pitch ( /* (o) : Gain of pitch lag saturated to 1.2 */ + Word16 xn[], /* (i) : Pitch target. */ + Word16 y1[], /* (i) : Filtered adaptive codebook. */ + Word16 L_subfr /* : Length of subframe. */ +); +Word16 G_code ( /* out : Gain of innovation code. */ + Word16 xn[], /* in : target vector */ + Word16 y2[] /* in : filtered inovation vector */ +); + +Word16 Interpol_6 ( /* (o) : interpolated value */ + Word16 *x, /* (i) : input vector */ + Word16 frac /* (i) : fraction */ +); +void Int_lpc ( + Word16 lsp_old[], /* input: LSP vector at the 4th subfr. of past frame */ + Word16 lsp_mid[], /* input: LSP vector at the 2nd subfr. of + present frame */ + Word16 lsp_new[], /* input: LSP vector at the 4th subfr. of + present frame */ + Word16 Az[] /* output: interpolated LP parameters in all subfr. */ +); +void Int_lpc2 ( + Word16 lsp_old[], /* input: LSP vector at the 4th subfr. of past frame */ + Word16 lsp_mid[], /* input: LSP vector at the 2nd subframe of + present frame */ + Word16 lsp_new[], /* input: LSP vector at the 4th subframe of + present frame */ + Word16 Az[] /* output:interpolated LP parameters + in subframes 1 and 3 */ +); +Word16 Pitch_fr6 ( /* (o) : pitch period. */ + Word16 exc[], /* (i) : excitation buffer */ + Word16 xn[], /* (i) : target vector */ + Word16 h[], /* (i) : impulse response of synthesis and + weighting filters */ + Word16 L_subfr, /* (i) : Length of subframe */ + Word16 t0_min, /* (i) : minimum value in the searched range. */ + Word16 t0_max, /* (i) : maximum value in the searched range. */ + Word16 i_subfr, /* (i) : indicator for first subframe. */ + Word16 *pit_frac /* (o) : chosen fraction. */ +); +Word16 Pitch_ol ( /* output: open loop pitch lag */ + Word16 signal[], /* input: signal used to compute the open loop pitch */ + /* signal[-pit_max] to signal[-1] should be known */ + Word16 pit_min, /* input : minimum pitch lag */ + Word16 pit_max, /* input : maximum pitch lag */ + Word16 L_frame /* input : length of frame to compute pitch */ +); +void Pred_lt_6 ( + Word16 exc[], /* in/out: excitation buffer */ + Word16 T0, /* input : integer pitch lag */ + Word16 frac, /* input : fraction of lag */ + Word16 L_subfr /* input : subframe size */ +); +void Q_plsf_5 ( + Word16 *lsp1, /* input : 1st LSP vector */ + Word16 *lsp2, /* input : 2nd LSP vector */ + Word16 *lsp1_q, /* output: quantized 1st LSP vector */ + Word16 *lsp2_q, /* output: quantized 2nd LSP vector */ + Word16 *indice, /* output: quantization indices of 5 matrices */ + Word16 txdtx_ctrl /* input : tx dtx control word */ +); +void Bits2prm_12k2 ( + Word16 bits[], /* input : serial bits */ + Word16 prm[] /* output: analysis parameters */ +); +void Prm2bits_12k2 ( + Word16 prm[], /* input : analysis parameters */ + Word16 bits[] /* output: serial bits */ +); diff -r 000000000000 -r 56410792419a src/coder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/coder.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,209 @@ +/*************************************************************************** + * + * FILE NAME: CODER.C + * + * Main program of the EFR coder at 12.2 kbit/s. + * + * Usage : coder speech_file bitstream_file + * + * Format for speech_file: + * Speech is read from a binary file of 16 bits data. + * + * Format for bitstream_file: + * 244 words (2-byte) containing 244 bits. + * Bit 0 = 0x0000 and Bit 1 = 0x0001 + * One word (2-byte) for voice activity decision (VAD) flag bit + * 0x0000 -> inactive (no detected speech activity); + * 0x0001 -> active + * One word (2-byte) for speech (SP) flag bit + * 0x0000 -> inactive (no transmission of speech frames); + * 0x0001 -> active + * + ***************************************************************************/ + +#include +#include +#include +#include "typedef.h" +#include "basic_op.h" +#include "sig_proc.h" +#include "count.h" +#include "codec.h" +#include "cnst.h" +#include "n_stack.h" +#include "e_homing.h" + +#include "dtx.h" + +Word16 dtx_mode; +extern Word16 txdtx_ctrl; + +/* L_FRAME, M, PRM_SIZE, AZ_SIZE, SERIAL_SIZE: defined in "cnst.h" */ + +int main (int argc, char *argv[]) +{ + FILE *f_speech; /* File of speech data */ + FILE *f_serial; /* File of serial bits for transmission */ + + extern Word16 *new_speech; /* Pointer to new speech data */ + + Word16 prm[PRM_SIZE]; /* Analysis parameters. */ + Word16 serial[SERIAL_SIZE-1];/* Output bitstream buffer */ + Word16 syn[L_FRAME]; /* Buffer for synthesis speech */ + + Word16 frame; + + Word16 vad, sp; + + Word16 reset_flag; + Word16 i; + + proc_head ("Encoder"); + + /*----------------------------------------------------------------------* + * Open speech file and result file (output serial bit stream) * + *----------------------------------------------------------------------*/ + + if ((argc < 3) || (argc > 4)) + { + fprintf (stderr, + " Usage:\n\n coder speech_file bitstream_file \n"); + fprintf (stderr, "\n"); + exit (1); + } + if ((f_speech = fopen (argv[1], "rb")) == NULL) + { + fprintf (stderr, "Error opening input file %s !!\n", argv[1]); + exit (0); + } + fprintf (stderr, " Input speech file: %s\n", argv[1]); + + if ((f_serial = fopen (argv[2], "wb")) == NULL) + { + fprintf (stderr,"Error opening output bitstream file %s !!\n",argv[2]); + exit (0); + } + fprintf (stderr, " Output bitstream file: %s\n", argv[2]); + + dtx_mode = 0; /* DTX disabled by default */ + + if (argc == 4) + { + if (strcmp (argv[3], "nodtx") == 0) + { + dtx_mode = 0; + } + else if (strcmp (argv[3], "dtx") == 0) + { + dtx_mode = 1; + } + else + { + fprintf (stderr, "\nWrong DTX switch: %s !!\n", argv[3]); + exit (1); + } + } + if (dtx_mode == 1) + { + fprintf (stderr, " DTX: enabled\n"); + } + else + { + fprintf (stderr, " DTX: disabled\n"); + } + + /*-----------------------------------------------------------------------* + * Initialisation of the coder. * + *-----------------------------------------------------------------------*/ + + reset_enc (); /* Bring the encoder, VAD and DTX to the initial state */ + + Init_WMOPS_counter (); + + /* Loop for each "L_FRAME" speech data. */ + + frame = 0; + while (fread (new_speech, sizeof (Word16), L_FRAME, f_speech) == L_FRAME) + { +#if(WMOPS) + fprintf (stderr, "frame=%d ", ++frame); +#else + fprintf (stderr, "\nframe=%d ", ++frame); +#endif + + /* Check whether this frame is an encoder homing frame */ + reset_flag = encoder_homing_frame_test (new_speech); + +#if (WMOPS) + Reset_WMOPS_counter (); /* reset WMOPS counter for the new frame */ +#endif + + for (i = 0; i < L_FRAME; i++) /* Delete the 3 LSBs (13-bit input) */ + { + new_speech[i] = new_speech[i] & 0xfff8; logic16 (); move16 (); + } + + Pre_Process (new_speech, L_FRAME); /* filter + downscaling */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + Coder_12k2 (prm, syn); /* Find speech parameters */ + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) == 0) + { + /* Write comfort noise parameters into the parameter frame. + Use old parameters in case SID frame is not to be updated */ + CN_encoding (prm, txdtx_ctrl); + } + Prm2bits_12k2 (prm, &serial[0]); /* Parameters to serial bits */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + test (); logic16 (); + if ((txdtx_ctrl & TX_SP_FLAG) == 0) + { + /* Insert SID codeword into the serial parameter frame */ + sid_codeword_encoding (&serial[0]); + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + +#if (WMOPS) + WMOPS_output (dtx_mode);/* output speech encoder WMOPS values + for current frame */ +#endif + + /* Write the bit stream to file */ + fwrite (serial, sizeof (Word16), (SERIAL_SIZE-1), f_serial); + + /* Write the VAD- and SP-flags to file after the speech + parameter bit stream */ + vad = 0; + sp = 0; + + if ((txdtx_ctrl & TX_VAD_FLAG) != 0) + { + vad = 1; + } + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + sp = 1; + } + fwrite (&vad, sizeof (Word16), 1, f_serial); + fwrite (&sp, sizeof (Word16), 1, f_serial); + + if (reset_flag != 0) + { + reset_enc (); /*Bring the encoder, VAD and DTX to the home state */ + } + } + + return (0); +} diff -r 000000000000 -r 56410792419a src/convolve.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/convolve.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,43 @@ +/************************************************************************* + * + * FUNCTION: Convolve + * + * PURPOSE: + * Perform the convolution between two vectors x[] and h[] and + * write the result in the vector y[]. All vectors are of length L + * and only the first L samples of the convolution are computed. + * + * DESCRIPTION: + * The convolution is given by + * + * y[n] = sum_{i=0}^{n} x[i] h[n-i], n=0,...,L-1 + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +void Convolve ( + Word16 x[], /* (i) : input vector */ + Word16 h[], /* (i) : impulse response */ + Word16 y[], /* (o) : output vector */ + Word16 L /* (i) : vector size */ +) +{ + Word16 i, n; + Word32 s; + + for (n = 0; n < L; n++) + { + s = 0; move32 (); + for (i = 0; i <= n; i++) + { + s = L_mac (s, x[i], h[n - i]); + } + s = L_shl (s, 3); + y[n] = extract_h (s); move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/copy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/copy.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,28 @@ +/************************************************************************* + * + * FUNCTION: Copy + * + * PURPOSE: Copy vector x[] to y[] + * + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +void Copy ( + Word16 x[], /* (i) : input vector */ + Word16 y[], /* (o) : output vector */ + Word16 L /* (i) : vector length */ +) +{ + Word16 i; + + for (i = 0; i < L; i++) + { + y[i] = x[i]; move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/count.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/count.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,153 @@ +/*********************************************************************** + * + * This file contains functions for the automatic complexity calculation + * +*************************************************************************/ + +#include +#include "typedef.h" +#include "count.h" + +/* Global counter variable for calculation of complexity weight */ + +BASIC_OP counter; + +const BASIC_OP op_weight = +{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 4, 15, 18, 30, 1, 2, 1, 2, 2 +}; + +/* local variable */ + +#define NbFuncMax 1024 + +static Word16 funcid, nbframe; +static Word32 glob_wc, wc[NbFuncMax]; +static float total_wmops; + +static Word32 LastWOper; + +Word32 TotalWeightedOperation () +{ + Word16 i; + Word32 tot, *ptr, *ptr2; + + tot = 0; + ptr = (Word32 *) &counter; + ptr2 = (Word32 *) &op_weight; + for (i = 0; i < (sizeof (counter) / sizeof (Word32)); i++) + + { + tot += ((*ptr++) * (*ptr2++)); + } + + return ((Word32) tot); +} + +Word32 DeltaWeightedOperation () +{ + Word32 NewWOper, delta; + + NewWOper = TotalWeightedOperation (); + delta = NewWOper - LastWOper; + LastWOper = NewWOper; + return (delta); +} + +void move16 (void) +{ + counter.DataMove16++; +} + +void move32 (void) +{ + counter.DataMove32++; +} + +void test (void) +{ + counter.Test++; +} + +void logic16 (void) +{ + counter.Logic16++; +} + +void logic32 (void) +{ + counter.Logic32++; +} + +void Init_WMOPS_counter (void) +{ + Word16 i; + + /* reset function weight operation counter variable */ + + for (i = 0; i < NbFuncMax; i++) + wc[i] = (Word32) 0; + glob_wc = 0; + nbframe = 0; + total_wmops = 0.0; + +} + +void Reset_WMOPS_counter (void) +{ + Word16 i; + Word32 *ptr; + + ptr = (Word32 *) &counter; + for (i = 0; i < (sizeof (counter) / sizeof (Word32)); i++) + + { + *ptr++ = 0; + } + LastWOper = 0; + + funcid = 0; /* new frame, set function id to zero */ +} + +Word32 fwc (void) /* function worst case */ +{ + Word32 tot; + + tot = DeltaWeightedOperation (); + if (tot > wc[funcid]) + wc[funcid] = tot; + + funcid++; + + return (tot); +} + +void WMOPS_output (Word16 dtx_mode) +{ + Word16 i; + Word32 tot, tot_wc; + + tot = TotalWeightedOperation (); + if (tot > glob_wc) + glob_wc = tot; + + fprintf (stderr, "WMOPS=%.2f", ((float) tot) * 0.00005); + + nbframe++; + total_wmops += ((float) tot) * 0.00005; + fprintf (stderr, " Average=%.2f", total_wmops / (float) nbframe); + + fprintf (stderr, " WorstCase=%.2f", ((float) glob_wc) * 0.00005); + + /* Worst worst case printed only when not in DTX mode */ + if (dtx_mode == 0) + { + tot_wc = 0L; + for (i = 0; i < funcid; i++) + tot_wc += wc[i]; + fprintf (stderr, " WorstWC=%.2f", ((float) tot_wc) * 0.00005); + } + fprintf (stderr, "\n"); +} diff -r 000000000000 -r 56410792419a src/count.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/count.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,61 @@ +/* Global counter variable for calculation of complexity weight */ + +typedef struct +{ + Word32 add; /* Complexity Weight of 1 */ + Word32 sub; + Word32 abs_s; + Word32 shl; + Word32 shr; + Word32 extract_h; + Word32 extract_l; + Word32 mult; + Word32 L_mult; + Word32 negate; + Word32 round; + Word32 L_mac; + Word32 L_msu; + Word32 L_macNs; + Word32 L_msuNs; + Word32 L_add; /* Complexity Weight of 2 */ + Word32 L_sub; + Word32 L_add_c; + Word32 L_sub_c; + Word32 L_negate; + Word32 L_shl; + Word32 L_shr; + Word32 mult_r; + Word32 shr_r; + Word32 shift_r; + Word32 mac_r; + Word32 msu_r; + Word32 L_deposit_h; + Word32 L_deposit_l; + Word32 L_shr_r; /* Complexity Weight of 3 */ + Word32 L_shift_r; + Word32 L_abs; + Word32 L_sat; /* Complexity Weight of 4 */ + Word32 norm_s; /* Complexity Weight of 15 */ + Word32 div_s; /* Complexity Weight of 18 */ + Word32 norm_l; /* Complexity Weight of 30 */ + Word32 DataMove16; /* Complexity Weight of 1 */ + Word32 DataMove32; /* Complexity Weight of 2 */ + Word32 Logic16; /* Complexity Weight of 1 */ + Word32 Logic32; /* Complexity Weight of 2 */ + Word32 Test; /* Complexity Weight of 2 */ +} +BASIC_OP; + +Word32 TotalWeightedOperation (void); +Word32 DeltaWeightedOperation (void); + +void Init_WMOPS_counter (void); +void Reset_WMOPS_counter (void); +void WMOPS_output (Word16 dtx_mode); +Word32 fwc (void); + +void move16 (void); +void move32 (void); +void logic16 (void); +void logic32 (void); +void test (void); diff -r 000000000000 -r 56410792419a src/d1035pf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/d1035pf.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,76 @@ +/************************************************************************* + * + * FUNCTION: dec_10i40_35bits() + * + * PURPOSE: Builds the innovative codevector from the received + * index of algebraic codebook. + * + * See c1035pf.c for more details about the algebraic codebook structure. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +#define L_CODE 40 /* codevector length */ +#define NB_PULSE 10 /* number of pulses */ +#define NB_TRACK 5 /* number of track */ + +void dec_10i40_35bits ( + Word16 index[], /* (i) : index of 10 pulses (sign+position) */ + Word16 cod[] /* (o) : algebraic (fixed) codebook excitation */ +) +{ + static const Word16 dgray[8] = {0, 1, 3, 2, 5, 6, 4, 7}; + Word16 i, j, pos1, pos2, sign, tmp; + + for (i = 0; i < L_CODE; i++) + { + cod[i] = 0; move16 (); + } + + /* decode the positions and signs of pulses and build the codeword */ + + for (j = 0; j < NB_TRACK; j++) + { + /* compute index i */ + + tmp = index[j]; move16 (); + i = tmp & 7; logic16 (); + i = dgray[i]; move16 (); + + i = extract_l (L_shr (L_mult (i, 5), 1)); + pos1 = add (i, j); /* position of pulse "j" */ + + i = shr (tmp, 3) & 1; logic16 (); + test (); + if (i == 0) + { + sign = 4096; move16 (); /* +1.0 */ + } + else + { + sign = -4096; move16 (); /* -1.0 */ + } + + cod[pos1] = sign; move16 (); + + /* compute index i */ + + i = index[add (j, 5)] & 7; logic16 (); + i = dgray[i]; move16 (); + i = extract_l (L_shr (L_mult (i, 5), 1)); + + pos2 = add (i, j); /* position of pulse "j+5" */ + + test (); + if (sub (pos2, pos1) < 0) + { + sign = negate (sign); + } + cod[pos2] = add (cod[pos2], sign); move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/d_gains.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/d_gains.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,490 @@ +/************************************************************************* + * + * FILE NAME: D_GAINS.C + * + * FUNCTIONS DEFINED IN THIS FILE: + * + * d_gain_pitch(), d_gain_code() and gmed5() + * + * MA prediction is performed on the innovation energy + * ( in dB/(20*log10(2)) ) with mean removed. + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "sig_proc.h" + +#include "gains_tb.h" + +#include "cnst.h" +#include "dtx.h" + +extern Word16 gain_code_old_rx[4 * DTX_HANGOVER]; + +/* Static variables for bad frame handling */ + +/* Variables used by d_gain_pitch: */ +Word16 pbuf[5], past_gain_pit, prev_gp; + +/* Variables used by d_gain_code: */ +Word16 gbuf[5], past_gain_code, prev_gc; + +/* Static variables for CNI (used by d_gain_code) */ + +Word16 gcode0_CN, gain_code_old_CN, gain_code_new_CN, gain_code_muting_CN; + +/* Memories of gain dequantization: */ + +/* past quantized energies. */ +/* initialized to -14.0/constant, constant = 20*Log10(2) */ + +Word16 past_qua_en[4]; + +/* MA prediction coeff */ +Word16 pred[4]; + +/************************************************************************* + * + * FUNCTION: gmed5 + * + * PURPOSE: calculates 5-point median. + * + * DESCRIPTION: + * + *************************************************************************/ + +Word16 gmed5 ( /* out : index of the median value (0...4) */ + Word16 ind[] /* in : Past gain values */ +) +{ + Word16 i, j, ix = 0, tmp[5]; + Word16 max, tmp2[5]; + + for (i = 0; i < 5; i++) + { + tmp2[i] = ind[i]; move16 (); + } + + for (i = 0; i < 5; i++) + { + max = -8192; move16 (); + for (j = 0; j < 5; j++) + { + test (); + if (sub (tmp2[j], max) >= 0) + { + max = tmp2[j]; move16 (); + ix = j; move16 (); + } + } + tmp2[ix] = -16384; move16 (); + tmp[i] = ix; move16 (); + } + + return (ind[tmp[2]]); +} + +/************************************************************************* + * + * FUNCTION: d_gain_pitch + * + * PURPOSE: decodes the pitch gain using the received index. + * + * DESCRIPTION: + * In case of no frame erasure, the gain is obtained from the + * quantization table at the given index; otherwise, a downscaled + * past gain is used. + * + *************************************************************************/ + +Word16 d_gain_pitch ( /* out : quantized pitch gain */ + Word16 index, /* in : index of quantization */ + Word16 bfi, /* in : bad frame indicator (good = 0) */ + Word16 state, + Word16 prev_bf, + Word16 rxdtx_ctrl +) +{ + static const Word16 pdown[7] = + { + 32767, 32112, 32112, 26214, + 9830, 6553, 6553 + }; + + Word16 gain, tmp, i; + + test (); + if (bfi == 0) + { + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + gain = shr (qua_gain_pitch[index], 2); move16 (); + + test (); + if (prev_bf != 0) + { + test (); + if (sub (gain, prev_gp) > 0) + { + gain = prev_gp; + } + } + } + else + { + gain = 0; move16 (); + } + prev_gp = gain; move16 (); + } + else + { + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + tmp = gmed5 (pbuf); move16 (); + + test (); + if (sub (tmp, past_gain_pit) < 0) + { + past_gain_pit = tmp; move16 (); + } + gain = mult (pdown[state], past_gain_pit); + } + else + { + gain = 0; move16 (); + } + } + + past_gain_pit = gain; move16 (); + + test (); + if (sub (past_gain_pit, 4096) > 0) /* if (past_gain_pit > 1.0) */ + { + past_gain_pit = 4096; move16 (); + } + for (i = 1; i < 5; i++) + { + pbuf[i - 1] = pbuf[i]; move16 (); + } + + pbuf[4] = past_gain_pit; move16 (); + + return gain; +} + +/************************************************************************* + * + * FUNCTION: d_gain_code + * + * PURPOSE: decode the fixed codebook gain using the received index. + * + * DESCRIPTION: + * The received index gives the gain correction factor gamma. + * The quantized gain is given by g_q = g0 * gamma + * where g0 is the predicted gain. + * To find g0, 4th order MA prediction is applied to the mean-removed + * innovation energy in dB. + * In case of frame erasure, downscaled past gain is used. + * + *************************************************************************/ + +/* average innovation energy. */ +/* MEAN_ENER = 36.0/constant, constant = 20*Log10(2) */ +#define MEAN_ENER 783741L /* 36/(20*log10(2)) */ + +void d_gain_code ( + Word16 index, /* input : received quantization index */ + Word16 code[], /* input : innovation codevector */ + Word16 lcode, /* input : codevector length */ + Word16 *gain_code, /* output: decoded innovation gain */ + Word16 bfi, /* input : bad frame indicator */ + Word16 state, + Word16 prev_bf, + Word16 rxdtx_ctrl, + Word16 i_subfr, + Word16 rx_dtx_state +) +{ + static const Word16 cdown[7] = + { + 32767, 32112, 32112, 32112, + 32112, 32112, 22937 + }; + + Word16 i, tmp; + Word16 gcode0, exp, frac, av_pred_en; + Word32 ener, ener_code; + + test (); test (); logic16 (); + if (((rxdtx_ctrl & RX_UPD_SID_QUANT_MEM) != 0) && (i_subfr == 0)) + { + gcode0_CN = update_gcode0_CN (gain_code_old_rx); move16 (); + gcode0_CN = shl (gcode0_CN, 4); + } + + /* Handle cases of comfort noise fixed codebook gain decoding in + which past valid SID frames are repeated */ + + test (); test (); test (); logic16 (); logic16 (); logic16 (); + if (((rxdtx_ctrl & RX_NO_TRANSMISSION) != 0) + || ((rxdtx_ctrl & RX_INVALID_SID_FRAME) != 0) + || ((rxdtx_ctrl & RX_LOST_SID_FRAME) != 0)) + { + + test (); logic16 (); + if ((rxdtx_ctrl & RX_NO_TRANSMISSION) != 0) + { + /* DTX active: no transmission. Interpolate gain values + in memory */ + test (); + if (i_subfr == 0) + { + *gain_code = interpolate_CN_param (gain_code_old_CN, + gain_code_new_CN, rx_dtx_state); + move16 (); + } + else + { + *gain_code = prev_gc; move16 (); + } + } + else + { /* Invalid or lost SID frame: + use gain values from last good SID frame */ + gain_code_old_CN = gain_code_new_CN; move16 (); + *gain_code = gain_code_new_CN; move16 (); + + /* reset table of past quantized energies */ + for (i = 0; i < 4; i++) + { + past_qua_en[i] = -2381; move16 (); + } + } + + test (); logic16 (); + if ((rxdtx_ctrl & RX_DTX_MUTING) != 0) + { + /* attenuate the gain value by 0.75 dB in each subframe */ + /* (total of 3 dB per frame) */ + gain_code_muting_CN = mult (gain_code_muting_CN, 30057); + *gain_code = gain_code_muting_CN; move16 (); + } + else + { + /* Prepare for DTX muting by storing last good gain value */ + gain_code_muting_CN = gain_code_new_CN; move16 (); + } + + past_gain_code = *gain_code; move16 (); + + for (i = 1; i < 5; i++) + { + gbuf[i - 1] = gbuf[i]; move16 (); + } + + gbuf[4] = past_gain_code; move16 (); + prev_gc = past_gain_code; move16 (); + + return; + } + + /*----------------- Test erasure ---------------*/ + + test (); + if (bfi != 0) + { + tmp = gmed5 (gbuf); move16 (); + test (); + if (sub (tmp, past_gain_code) < 0) + { + past_gain_code = tmp; move16 (); + } + past_gain_code = mult (past_gain_code, cdown[state]); + *gain_code = past_gain_code; move16 (); + + av_pred_en = 0; move16 (); + for (i = 0; i < 4; i++) + { + av_pred_en = add (av_pred_en, past_qua_en[i]); + } + + /* av_pred_en = 0.25*av_pred_en - 4/(20Log10(2)) */ + av_pred_en = mult (av_pred_en, 8192); /* *= 0.25 */ + + /* if (av_pred_en < -14/(20Log10(2))) av_pred_en = .. */ + test (); + if (sub (av_pred_en, -2381) < 0) + { + av_pred_en = -2381; move16 (); + } + for (i = 3; i > 0; i--) + { + past_qua_en[i] = past_qua_en[i - 1]; move16 (); + } + past_qua_en[0] = av_pred_en; move16 (); + for (i = 1; i < 5; i++) + { + gbuf[i - 1] = gbuf[i]; move16 (); + } + gbuf[4] = past_gain_code; move16 (); + + /* Use the most recent comfort noise fixed codebook gain value + for updating the fixed codebook gain history */ + test (); + if (gain_code_new_CN == 0) + { + tmp = prev_gc; move16 (); + } + else + { + tmp = gain_code_new_CN; + } + + update_gain_code_history_rx (tmp, gain_code_old_rx); + + test (); + if (sub (i_subfr, (3 * L_SUBFR)) == 0) + { + gain_code_old_CN = *gain_code; move16 (); + } + return; + } + + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + + /*-------------- Decode codebook gain ---------------*/ + + /*-------------------------------------------------------------------* + * energy of code: * + * ~~~~~~~~~~~~~~~ * + * ener_code = 10 * Log10(energy/lcode) / constant * + * = 1/2 * Log2(energy/lcode) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------------*/ + + /* ener_code = log10(ener_code/lcode) / (20*log10(2)) */ + ener_code = 0; move32 (); + for (i = 0; i < lcode; i++) + { + ener_code = L_mac (ener_code, code[i], code[i]); + } + /* ener_code = ener_code / lcode */ + ener_code = L_mult (round (ener_code), 26214); + + /* ener_code = 1/2 * Log2(ener_code) */ + Log2 (ener_code, &exp, &frac); + ener_code = L_Comp (sub (exp, 30), frac); + + /* predicted energy */ + + ener = MEAN_ENER; move32 (); + for (i = 0; i < 4; i++) + { + ener = L_mac (ener, past_qua_en[i], pred[i]); + } + + /*-------------------------------------------------------------------* + * predicted codebook gain * + * ~~~~~~~~~~~~~~~~~~~~~~~ * + * gcode0 = Pow10( (ener*constant - ener_code*constant) / 20 ) * + * = Pow2(ener-ener_code) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------------*/ + + ener = L_shr (L_sub (ener, ener_code), 1); + L_Extract (ener, &exp, &frac); + + gcode0 = extract_l (Pow2 (exp, frac)); /* predicted gain */ + + gcode0 = shl (gcode0, 4); + + *gain_code = mult (qua_gain_code[index], gcode0); move16 (); + + test (); + if (prev_bf != 0) + { + test (); + if (sub (*gain_code, prev_gc) > 0) + { + *gain_code = prev_gc; move16 (); + } + } + /*-------------------------------------------------------------------* + * update table of past quantized energies * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + * past_qua_en = 20 * Log10(qua_gain_code) / constant * + * = Log2(qua_gain_code) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------------*/ + + for (i = 3; i > 0; i--) + { + past_qua_en[i] = past_qua_en[i - 1]; move16 (); + } + Log2 (L_deposit_l (qua_gain_code[index]), &exp, &frac); + + past_qua_en[0] = shr (frac, 5); move16 (); + past_qua_en[0] = add (past_qua_en[0], shl (sub (exp, 11), 10)); + move16 (); + + update_gain_code_history_rx (*gain_code, gain_code_old_rx); + + if (sub (i_subfr, (3 * L_SUBFR)) == 0) + { + gain_code_old_CN = *gain_code; move16 (); + } + } + else + { + test (); test (); logic16 (); + if (((rxdtx_ctrl & RX_FIRST_SID_UPDATE) != 0) && (i_subfr == 0)) + { + gain_code_new_CN = mult (gcode0_CN, qua_gain_code[index]); + + /*---------------------------------------------------------------* + * reset table of past quantized energies * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *---------------------------------------------------------------*/ + + for (i = 0; i < 4; i++) + { + past_qua_en[i] = -2381; move16 (); + } + } + test (); test (); logic16 (); + if (((rxdtx_ctrl & RX_CONT_SID_UPDATE) != 0) && (i_subfr == 0)) + { + gain_code_old_CN = gain_code_new_CN; move16 (); + gain_code_new_CN = mult (gcode0_CN, qua_gain_code[index]); + move16 (); + } + test (); + if (i_subfr == 0) + { + *gain_code = interpolate_CN_param (gain_code_old_CN, + gain_code_new_CN, + rx_dtx_state); move16 (); + } + else + { + *gain_code = prev_gc; move16 (); + } + } + + past_gain_code = *gain_code; move16 (); + + for (i = 1; i < 5; i++) + { + gbuf[i - 1] = gbuf[i]; move16 (); + } + gbuf[4] = past_gain_code; move16 (); + prev_gc = past_gain_code; move16 (); + + return; +} diff -r 000000000000 -r 56410792419a src/d_homing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/d_homing.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,344 @@ +/************************************************************************** + * + * File Name: d_homing.c + * + * Purpose: + * This file contains the following functions: + * + * decoder_homing_frame_test() checks if a frame of input speech + * parameters matches the Decoder Homing + * Frame pattern. + * + * decoder_reset() called by reset_dec() to reset all of + * the state variables for the decoder + * + * reset_dec() calls functions to reset the state + * variables for the decoder, and for + * the receive DTX and Comfort Noise. + * + **************************************************************************/ + +#include "typedef.h" +#include "cnst.h" +#include "dtx.h" +#include "codec.h" +#include "d_homing.h" +#include "q_plsf_5.tab" + +#define PRM_NO 57 + +/*************************************************************************** + * + * FUNCTION NAME: decoder_homing_frame_test + * + * PURPOSE: + * Checks if a frame of input speech parameters matches the Decoder + * Homing Frame pattern, which is: + * + * parameter decimal value hexidecimal value + * --------- ------------- ----------------- + * LPC 1 4 0x0004 + * LPC 2 47 0x002F + * LPC 3 180 0x00B4 + * LPC 4 144 0x0090 + * LPC 5 62 0x003E + * LTP-LAG 1 342 0x0156 + * LTP-GAIN 1 11 0x000B + * PULSE1_1 0 0x0000 + * PULSE1_2 1 0x0001 + * PULSE1_3 15 0x000F + * PULSE1_4 1 0x0001 + * PULSE1_5 13 0x000D + * PULSE1_6 0 0x0000 + * PULSE1_7 3 0x0003 + * PULSE1_8 0 0x0000 + * PULSE1_9 3 0x0003 + * PULSE1_10 0 0x0000 + * FCB-GAIN 1 3 0x0003 + * LTP-LAG 2 54 0x0036 + * LTP-GAIN 2 1 0x0001 + * PULSE2_1 8 0x0008 + * PULSE2_2 8 0x0008 + * PULSE2_3 5 0x0005 + * PULSE2_4 8 0x0008 + * PULSE2_5 1 0x0001 + * PULSE2_6 0 0x0000 + * PULSE2_7 0 0x0000 + * PULSE2_8 1 0x0001 + * PULSE2_9 1 0x0001 + * PULSE2_10 0 0x0000 + * FCB-GAIN 2 0 0x0000 + * LTP-LAG 3 342 0x0156 + * LTP-GAIN 3 0 0x0000 + * PULSE3_1 0 0x0000 + * PULSE3_2 0 0x0000 + * PULSE3_3 0 0x0000 + * PULSE3_4 0 0x0000 + * PULSE3_5 0 0x0000 + * PULSE3_6 0 0x0000 + * PULSE3_7 0 0x0000 + * PULSE3_8 0 0x0000 + * PULSE3_9 0 0x0000 + * PULSE3_10 0 0x0000 + * FCB-GAIN 3 0 0x0000 + * LTP-LAG 4 54 0x0036 + * LTP-GAIN 4 11 0x000B + * PULSE4_1 0 0x0000 + * PULSE4_2 0 0x0000 + * PULSE4_3 0 0x0000 + * PULSE4_4 0 0x0000 + * PULSE4_5 0 0x0000 + * PULSE4_6 0 0x0000 + * PULSE4_7 0 0x0000 + * PULSE4_8 0 0x0000 + * PULSE4_9 0 0x0000 + * PULSE4_10 0 0x0000 + * FCB-GAIN 4 0 0x0000 + * + * INPUT: + * parm[] one frame of speech parameters in parallel format + * + * nbr_of_params + * the number of consecutive parameters in parm[] to match + * + * OUTPUT: + * None + * + * RETURN: + * 0 input frame does not match the Decoder Homing Frame pattern. + * 1 input frame matches the Decoder Homing Frame pattern. + * + **************************************************************************/ + +Word16 decoder_homing_frame_test (Word16 parm[], Word16 nbr_of_params) +{ + static const Word16 dhf_mask[PRM_NO] = + { + 0x0004, /* LPC 1 */ + 0x002f, /* LPC 2 */ + 0x00b4, /* LPC 3 */ + 0x0090, /* LPC 4 */ + 0x003e, /* LPC 5 */ + + 0x0156, /* LTP-LAG 1 */ + 0x000b, /* LTP-GAIN 1 */ + 0x0000, /* PULSE 1_1 */ + 0x0001, /* PULSE 1_2 */ + 0x000f, /* PULSE 1_3 */ + 0x0001, /* PULSE 1_4 */ + 0x000d, /* PULSE 1_5 */ + 0x0000, /* PULSE 1_6 */ + 0x0003, /* PULSE 1_7 */ + 0x0000, /* PULSE 1_8 */ + 0x0003, /* PULSE 1_9 */ + 0x0000, /* PULSE 1_10 */ + 0x0003, /* FCB-GAIN 1 */ + + 0x0036, /* LTP-LAG 2 */ + 0x0001, /* LTP-GAIN 2 */ + 0x0008, /* PULSE 2_1 */ + 0x0008, /* PULSE 2_2 */ + 0x0005, /* PULSE 2_3 */ + 0x0008, /* PULSE 2_4 */ + 0x0001, /* PULSE 2_5 */ + 0x0000, /* PULSE 2_6 */ + 0x0000, /* PULSE 2_7 */ + 0x0001, /* PULSE 2_8 */ + 0x0001, /* PULSE 2_9 */ + 0x0000, /* PULSE 2_10 */ + 0x0000, /* FCB-GAIN 2 */ + + 0x0156, /* LTP-LAG 3 */ + 0x0000, /* LTP-GAIN 3 */ + 0x0000, /* PULSE 3_1 */ + 0x0000, /* PULSE 3_2 */ + 0x0000, /* PULSE 3_3 */ + 0x0000, /* PULSE 3_4 */ + 0x0000, /* PULSE 3_5 */ + 0x0000, /* PULSE 3_6 */ + 0x0000, /* PULSE 3_7 */ + 0x0000, /* PULSE 3_8 */ + 0x0000, /* PULSE 3_9 */ + 0x0000, /* PULSE 3_10 */ + 0x0000, /* FCB-GAIN 3 */ + + 0x0036, /* LTP-LAG 4 */ + 0x000b, /* LTP-GAIN 4 */ + 0x0000, /* PULSE 4_1 */ + 0x0000, /* PULSE 4_2 */ + 0x0000, /* PULSE 4_3 */ + 0x0000, /* PULSE 4_4 */ + 0x0000, /* PULSE 4_5 */ + 0x0000, /* PULSE 4_6 */ + 0x0000, /* PULSE 4_7 */ + 0x0000, /* PULSE 4_8 */ + 0x0000, /* PULSE 4_9 */ + 0x0000, /* PULSE 4_10 */ + 0x0000 /* FCB-GAIN 4 */ }; + + Word16 i, j; + + for (i = 0; i < nbr_of_params; i++) + { + j = parm[i] ^ dhf_mask[i]; + + if (j) + break; + } + + return !j; +} + +/*************************************************************************** + * + * FUNCTION NAME: decoder_reset + * + * PURPOSE: + * resets all of the state variables for the decoder + * + * INPUT: + * None + * + * OUTPUT: + * None + * + * RETURN: + * None + * + **************************************************************************/ + +void decoder_reset (void) +{ + /* External declarations for decoder variables which need to be reset */ + + /* variable defined in decoder.c */ + /* ----------------------------- */ + extern Word16 synth_buf[L_FRAME + M]; + + /* variable defined in agc.c */ + /* -------------------------- */ + extern Word16 past_gain; + + /* variables defined in d_gains.c */ + /* ------------------------------ */ + /* Error concealment */ + extern Word16 pbuf[5], past_gain_pit, prev_gp, gbuf[5], past_gain_code, + prev_gc; + + /* CNI */ + extern Word16 gcode0_CN, gain_code_old_CN, gain_code_new_CN; + extern Word16 gain_code_muting_CN; + + /* Memories of gain dequantization: */ + extern Word16 past_qua_en[4], pred[4]; + + /* variables defined in d_plsf_5.c */ + /* ------------------------------ */ + /* Past quantized prediction error */ + extern Word16 past_r2_q[M]; + + /* Past dequantized lsfs */ + extern Word16 past_lsf_q[M]; + + /* CNI */ + extern Word16 lsf_p_CN[M], lsf_new_CN[M], lsf_old_CN[M]; + + /* variables defined in dec_lag6.c */ + /* ------------------------------ */ + extern Word16 old_T0; + + /* variable defined in preemph.c */ + /* ------------------------------ */ + extern Word16 mem_pre; + + Word16 i; + + /* reset all the decoder state variables */ + /* ------------------------------------- */ + + /* Variable in decoder.c: */ + for (i = 0; i < M; i++) + { + synth_buf[i] = 0; + } + + /* Variables in dec_12k2.c: */ + Init_Decoder_12k2 (); + + /* Variable in agc.c: */ + past_gain = 4096; + + /* Variables in d_gains.c: */ + for (i = 0; i < 5; i++) + { + pbuf[i] = 410; /* Error concealment */ + gbuf[i] = 1; /* Error concealment */ + } + + past_gain_pit = 0; /* Error concealment */ + prev_gp = 4096; /* Error concealment */ + past_gain_code = 0; /* Error concealment */ + prev_gc = 1; /* Error concealment */ + gcode0_CN = 0; /* CNI */ + gain_code_old_CN = 0; /* CNI */ + gain_code_new_CN = 0; /* CNI */ + gain_code_muting_CN = 0; /* CNI */ + + for (i = 0; i < 4; i++) + { + past_qua_en[i] = -2381; /* past quantized energies */ + } + + pred[0] = 44; /* MA prediction coeff */ + pred[1] = 37; /* MA prediction coeff */ + pred[2] = 22; /* MA prediction coeff */ + pred[3] = 12; /* MA prediction coeff */ + + /* Variables in d_plsf_5.c: */ + for (i = 0; i < M; i++) + { + past_r2_q[i] = 0; /* Past quantized prediction error */ + past_lsf_q[i] = mean_lsf[i]; /* Past dequantized lsfs */ + lsf_p_CN[i] = mean_lsf[i]; /* CNI */ + lsf_new_CN[i] = mean_lsf[i]; /* CNI */ + lsf_old_CN[i] = mean_lsf[i]; /* CNI */ + } + + /* Variable in dec_lag6.c: */ + old_T0 = 40; /* Old integer lag */ + + /* Variable in preemph.c: */ + mem_pre = 0; /* Filter memory */ + + /* Variables in pstfilt2.c: */ + Init_Post_Filter (); + + return; +} + +/*************************************************************************** + * + * FUNCTION NAME: reset_dec + * + * PURPOSE: + * resets all of the state variables for the decoder, and for the + * receive DTX and Comfort Noise. + * + * INPUT: + * None + * + * OUTPUT: + * None + * + * RETURN: + * None + * + **************************************************************************/ + +void reset_dec (void) +{ + decoder_reset (); /* reset all the state variables in the speech decoder*/ + reset_rx_dtx (); /* reset all the receive DTX and CN state variables */ + + return; +} diff -r 000000000000 -r 56410792419a src/d_homing.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/d_homing.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,20 @@ +/************************************************************************** + * + * File Name: d_homing.h + * + * Purpose: Contains the prototypes for all the functions of + * decoder homing. + * + **************************************************************************/ + +#define EHF_MASK 0x0008 /* Encoder Homing Frame pattern */ + +#define D_HOMING + +/* Function Prototypes */ + +Word16 decoder_homing_frame_test (Word16 parm[], Word16 nbr_of_params); + +void decoder_reset (void); + +void reset_dec (void); diff -r 000000000000 -r 56410792419a src/d_plsf_5.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/d_plsf_5.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,289 @@ +/************************************************************************* + * + * FUNCTION: D_plsf_5() + * + * PURPOSE: Decodes the 2 sets of LSP parameters in a frame using the + * received quantization indices. + * + * DESCRIPTION: + * The two sets of LSFs are quantized using split by 5 matrix + * quantization (split-MQ) with 1st order MA prediction. + * + * See "q_plsf_5.c" for more details about the quantization procedure + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" +#include "sig_proc.h" + +#include "q_plsf_5.tab" /* Codebooks of LSF prediction residual */ + +#include "cnst.h" +#include "dtx.h" + +/* M ->order of linear prediction filter */ +/* LSF_GAP -> Minimum distance between LSF after quantization */ +/* 50 Hz = 205 */ +/* PRED_FAC -> Prediction factor = 0.65 */ +/* ALPHA -> 0.9 */ +/* ONE_ALPHA-> (1.0-ALPHA) */ + +#define M 10 +#define LSF_GAP 205 +#define PRED_FAC 21299 +#define ALPHA 31128 +#define ONE_ALPHA 1639 + +/* Past quantized prediction error */ + +Word16 past_r2_q[M]; + +/* Past dequantized lsfs */ + +Word16 past_lsf_q[M]; + +/* Reference LSF parameter vector (comfort noise) */ + +Word16 lsf_p_CN[M]; + +/* LSF memories for comfort noise interpolation */ + +Word16 lsf_old_CN[M], lsf_new_CN[M]; + + /* LSF parameter buffer */ + +extern Word16 lsf_old_rx[DTX_HANGOVER][M]; + +void D_plsf_5 ( + Word16 *indice, /* input : quantization indices of 5 submatrices */ + Word16 *lsp1_q, /* output: quantized 1st LSP vector */ + Word16 *lsp2_q, /* output: quantized 2nd LSP vector */ + Word16 bfi, /* input : bad frame indicator (set to 1 if a bad + frame is received) */ + Word16 rxdtx_ctrl, /* input : RX DTX control word */ + Word16 rx_dtx_state /* input : state of the comfort noise insertion + period */ +) +{ + Word16 i; + const Word16 *p_dico; + Word16 temp, sign; + Word16 lsf1_r[M], lsf2_r[M]; + Word16 lsf1_q[M], lsf2_q[M]; + + /* Update comfort noise LSF quantizer memory */ + test (); logic16 (); + if ((rxdtx_ctrl & RX_UPD_SID_QUANT_MEM) != 0) + { + update_lsf_p_CN (lsf_old_rx, lsf_p_CN); + } + /* Handle cases of comfort noise LSF decoding in which past + valid SID frames are repeated */ + + test (); logic16 (); + test (); logic16 (); + test (); logic16 (); + if (((rxdtx_ctrl & RX_NO_TRANSMISSION) != 0) + || ((rxdtx_ctrl & RX_INVALID_SID_FRAME) != 0) + || ((rxdtx_ctrl & RX_LOST_SID_FRAME) != 0)) + { + + test (); logic16 (); + if ((rxdtx_ctrl & RX_NO_TRANSMISSION) != 0) + { + /* DTX active: no transmission. Interpolate LSF values in memory */ + interpolate_CN_lsf (lsf_old_CN, lsf_new_CN, lsf2_q, rx_dtx_state); + } + else + { /* Invalid or lost SID frame: use LSFs + from last good SID frame */ + for (i = 0; i < M; i++) + { + lsf_old_CN[i] = lsf_new_CN[i]; move16 (); + lsf2_q[i] = lsf_new_CN[i]; move16 (); + past_r2_q[i] = 0; move16 (); + } + } + + for (i = 0; i < M; i++) + { + past_lsf_q[i] = lsf2_q[i]; move16 (); + } + + /* convert LSFs to the cosine domain */ + Lsf_lsp (lsf2_q, lsp2_q, M); + + return; + } + + test (); + if (bfi != 0) /* if bad frame */ + { + /* use the past LSFs slightly shifted towards their mean */ + + for (i = 0; i < M; i++) + { + /* lsfi_q[i] = ALPHA*past_lsf_q[i] + ONE_ALPHA*mean_lsf[i]; */ + + lsf1_q[i] = add (mult (past_lsf_q[i], ALPHA), + mult (mean_lsf[i], ONE_ALPHA)); + move16 (); + + lsf2_q[i] = lsf1_q[i]; move16 (); + } + + /* estimate past quantized residual to be used in next frame */ + + for (i = 0; i < M; i++) + { + /* temp = mean_lsf[i] + past_r2_q[i] * PRED_FAC; */ + + temp = add (mean_lsf[i], mult (past_r2_q[i], PRED_FAC)); + + past_r2_q[i] = sub (lsf2_q[i], temp); + move16 (); + } + } + else + /* if good LSFs received */ + { + /* decode prediction residuals from 5 received indices */ + + p_dico = &dico1_lsf[shl (indice[0], 2)]; + lsf1_r[0] = *p_dico++; move16 (); + lsf1_r[1] = *p_dico++; move16 (); + lsf2_r[0] = *p_dico++; move16 (); + lsf2_r[1] = *p_dico++; move16 (); + + p_dico = &dico2_lsf[shl (indice[1], 2)]; + lsf1_r[2] = *p_dico++; move16 (); + lsf1_r[3] = *p_dico++; move16 (); + lsf2_r[2] = *p_dico++; move16 (); + lsf2_r[3] = *p_dico++; move16 (); + + sign = indice[2] & 1; logic16 (); + i = shr (indice[2], 1); + p_dico = &dico3_lsf[shl (i, 2)]; move16 (); + + test (); + if (sign == 0) + { + lsf1_r[4] = *p_dico++; move16 (); + lsf1_r[5] = *p_dico++; move16 (); + lsf2_r[4] = *p_dico++; move16 (); + lsf2_r[5] = *p_dico++; move16 (); + } + else + { + lsf1_r[4] = negate (*p_dico++); move16 (); + lsf1_r[5] = negate (*p_dico++); move16 (); + lsf2_r[4] = negate (*p_dico++); move16 (); + lsf2_r[5] = negate (*p_dico++); move16 (); + } + + p_dico = &dico4_lsf[shl (indice[3], 2)];move16 (); + lsf1_r[6] = *p_dico++; move16 (); + lsf1_r[7] = *p_dico++; move16 (); + lsf2_r[6] = *p_dico++; move16 (); + lsf2_r[7] = *p_dico++; move16 (); + + p_dico = &dico5_lsf[shl (indice[4], 2)];move16 (); + lsf1_r[8] = *p_dico++; move16 (); + lsf1_r[9] = *p_dico++; move16 (); + lsf2_r[8] = *p_dico++; move16 (); + lsf2_r[9] = *p_dico++; move16 (); + + /* Compute quantized LSFs and update the past quantized residual */ + /* Use lsf_p_CN as predicted LSF vector in case of no speech + activity */ + + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + for (i = 0; i < M; i++) + { + temp = add (mean_lsf[i], mult (past_r2_q[i], PRED_FAC)); + lsf1_q[i] = add (lsf1_r[i], temp); + move16 (); + lsf2_q[i] = add (lsf2_r[i], temp); + move16 (); + past_r2_q[i] = lsf2_r[i]; move16 (); + } + } + else + { /* Valid SID frame */ + for (i = 0; i < M; i++) + { + lsf2_q[i] = add (lsf2_r[i], lsf_p_CN[i]); + move16 (); + + /* Use the dequantized values of lsf2 also for lsf1 */ + lsf1_q[i] = lsf2_q[i]; move16 (); + + past_r2_q[i] = 0; move16 (); + } + } + } + + /* verification that LSFs have minimum distance of LSF_GAP Hz */ + + Reorder_lsf (lsf1_q, LSF_GAP, M); + Reorder_lsf (lsf2_q, LSF_GAP, M); + + test (); logic16 (); + if ((rxdtx_ctrl & RX_FIRST_SID_UPDATE) != 0) + { + for (i = 0; i < M; i++) + { + lsf_new_CN[i] = lsf2_q[i]; move16 (); + } + } + test (); logic16 (); + if ((rxdtx_ctrl & RX_CONT_SID_UPDATE) != 0) + { + for (i = 0; i < M; i++) + { + lsf_old_CN[i] = lsf_new_CN[i]; move16 (); + lsf_new_CN[i] = lsf2_q[i]; move16 (); + } + } + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + /* Update lsf history with quantized LSFs + when speech activity is present. If the current frame is + a bad one, update with most recent good comfort noise LSFs */ + + if (bfi==0) + { + update_lsf_history (lsf1_q, lsf2_q, lsf_old_rx); + } + else + { + update_lsf_history (lsf_new_CN, lsf_new_CN, lsf_old_rx); + } + + for (i = 0; i < M; i++) + { + lsf_old_CN[i] = lsf2_q[i]; move16 (); + } + } + else + { + interpolate_CN_lsf (lsf_old_CN, lsf_new_CN, lsf2_q, rx_dtx_state); + } + + for (i = 0; i < M; i++) + { + past_lsf_q[i] = lsf2_q[i]; move16 (); + } + + /* convert LSFs to the cosine domain */ + + Lsf_lsp (lsf1_q, lsp1_q, M); + Lsf_lsp (lsf2_q, lsp2_q, M); + + return; +} diff -r 000000000000 -r 56410792419a src/dec_12k2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dec_12k2.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,424 @@ +/*************************************************************************** + * + * FILE NAME: dec_12k2.c + * + * FUNCTIONS DEFINED IN THIS FILE: + * Init_Decoder_12k2 and Decoder_12k2 + * + * + * Init_Decoder_12k2(): + * Initialization of variables for the decoder section. + * + * Decoder_12k2(): + * Speech decoder routine operating on a frame basis. + * + ***************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "sig_proc.h" +#include "count.h" +#include "codec.h" +#include "cnst.h" + +#include "dtx.h" + +extern Word16 dtx_mode; + +/*---------------------------------------------------------------* + * Decoder constant parameters (defined in "cnst.h") * + *---------------------------------------------------------------* + * L_FRAME : Frame size. * + * L_FRAME_BY2 : Half the frame size. * + * L_SUBFR : Sub-frame size. * + * M : LPC order. * + * MP1 : LPC order+1 * + * PIT_MIN : Minimum pitch lag. * + * PIT_MAX : Maximum pitch lag. * + * L_INTERPOL : Length of filter for interpolation * + * PRM_SIZE : size of vector containing analysis parameters * + *---------------------------------------------------------------*/ + +/*--------------------------------------------------------* + * Static memory allocation. * + *--------------------------------------------------------*/ + + /* Excitation vector */ + +static Word16 old_exc[L_FRAME + PIT_MAX + L_INTERPOL]; +static Word16 *exc; + + /* Lsp (Line spectral pairs) */ + +static Word16 lsp_old[M]; + + /* Filter's memory */ + +static Word16 mem_syn[M]; + + /* Memories for bad frame handling */ + +static Word16 prev_bf; +static Word16 state; + +/*************************************************************************** + * + * FUNCTION: Init_Decoder_12k2 + * + * PURPOSE: Initialization of variables for the decoder section. + * + ***************************************************************************/ + +void Init_Decoder_12k2 (void) +{ + /* Initialize static pointer */ + + exc = old_exc + PIT_MAX + L_INTERPOL; + + /* Static vectors to zero */ + + Set_zero (old_exc, PIT_MAX + L_INTERPOL); + Set_zero (mem_syn, M); + + /* Initialize lsp_old [] */ + + lsp_old[0] = 30000; + lsp_old[1] = 26000; + lsp_old[2] = 21000; + lsp_old[3] = 15000; + lsp_old[4] = 8000; + lsp_old[5] = 0; + lsp_old[6] = -8000; + lsp_old[7] = -15000; + lsp_old[8] = -21000; + lsp_old[9] = -26000; + + /* Initialize memories of bad frame handling */ + + prev_bf = 0; + state = 0; + + return; +} + +/*************************************************************************** + * + * FUNCTION: Decoder_12k2 + * + * PURPOSE: Speech decoder routine. + * + ***************************************************************************/ + +void Decoder_12k2 ( + Word16 parm[], /* input : vector of synthesis parameters + parm[0] = bad frame indicator (bfi) */ + Word16 synth[],/* output: synthesis speech */ + Word16 A_t[], /* output: decoded LP filter in 4 subframes */ + Word16 TAF, + Word16 SID_flag +) +{ + + /* LPC coefficients */ + + Word16 *Az; /* Pointer on A_t */ + + /* LSPs */ + + Word16 lsp_new[M]; + Word16 lsp_mid[M]; + + /* Algebraic codevector */ + + Word16 code[L_SUBFR]; + + /* excitation */ + + Word16 excp[L_SUBFR]; + + /* Scalars */ + + Word16 i, i_subfr; + Word16 T0, T0_frac, index; + Word16 gain_pit, gain_code, bfi, pit_sharp; + Word16 temp; + Word32 L_temp; + + extern Word16 rxdtx_ctrl, rx_dtx_state; + extern Word32 L_pn_seed_rx; + + /* Test bad frame indicator (bfi) */ + + bfi = *parm++; move16 (); + + /* Set state machine */ + + test (); test (); + if (bfi != 0) + { + state = add (state, 1); + } + else if (sub (state, 6) == 0) + { + state = 5; + } + else + { + state = 0; + } + + test (); + if (sub (state, 6) > 0) + { + state = 6; + } + rx_dtx (&rxdtx_ctrl, TAF, bfi, SID_flag); + + /* If this frame is the first speech frame after CNI period, */ + /* set the BFH state machine to an appropriate state depending */ + /* on whether there was DTX muting before start of speech or not */ + /* If there was DTX muting, the first speech frame is muted. */ + /* If there was no DTX muting, the first speech frame is not */ + /* muted. The BFH state machine starts from state 5, however, to */ + /* keep the audible noise resulting from a SID frame which is */ + /* erroneously interpreted as a good speech frame as small as */ + /* possible (the decoder output in this case is quickly muted) */ + test (); logic16 (); + if ((rxdtx_ctrl & RX_FIRST_SP_FLAG) != 0) + { + test (); logic16 (); + if ((rxdtx_ctrl & RX_PREV_DTX_MUTING) != 0) + { + state = 5; move16 (); + prev_bf = 1; move16 (); + } + else + { + state = 5; move16 (); + prev_bf = 0; move16 (); + } + } + +#if (WMOPS) + fwc (); /* function worst case */ + + /* Note! The following test is performed only for determining + whether or not DTX mode is active, in order to switch off + worst worst case complexity printout when DTX mode is active + */ + if ((rxdtx_ctrl & RX_SP_FLAG) == 0) + { + dtx_mode = 1; + } +#endif + + D_plsf_5 (parm, lsp_mid, lsp_new, bfi, rxdtx_ctrl, rx_dtx_state); + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + /* Advance synthesis parameters pointer */ + parm += 5; move16 (); + + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + /* Interpolation of LPC for the 4 subframes */ + + Int_lpc (lsp_old, lsp_mid, lsp_new, A_t); + } + else + { + /* Comfort noise: use the same parameters in each subframe */ + Lsp_Az (lsp_new, A_t); + + for (i = 0; i < MP1; i++) + { + A_t[i + MP1] = A_t[i]; move16 (); + A_t[i + 2 * MP1] = A_t[i]; move16 (); + A_t[i + 3 * MP1] = A_t[i]; move16 (); + } + } + + /* update the LSPs for the next frame */ + for (i = 0; i < M; i++) + { + lsp_old[i] = lsp_new[i]; move16 (); + } +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*---------------------------------------------------------------------* + * Loop for every subframe in the analysis frame * + *---------------------------------------------------------------------* + * The subframe size is L_SUBFR and the loop is repeated * + * L_FRAME/L_SUBFR times * + * - decode the pitch delay * + * - decode algebraic code * + * - decode pitch and codebook gains * + * - find the excitation and compute synthesis speech * + *---------------------------------------------------------------------*/ + + /* pointer to interpolated LPC parameters */ + Az = A_t; move16 (); + + for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) + { + + index = *parm++; move16 (); /* pitch index */ + + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + T0 = Dec_lag6 (index, PIT_MIN, PIT_MAX, i_subfr, L_FRAME_BY2, + &T0_frac, bfi); +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*-------------------------------------------------* + * - Find the adaptive codebook vector. * + *-------------------------------------------------*/ + + Pred_lt_6 (&exc[i_subfr], T0, T0_frac, L_SUBFR); +#if (WMOPS) + fwc (); /* function worst case */ +#endif + } + else + { + T0 = L_SUBFR; move16 (); + } + + /*-------------------------------------------------------* + * - Decode pitch gain. * + *-------------------------------------------------------*/ + + index = *parm++; move16 (); + + gain_pit = d_gain_pitch (index, bfi, state, prev_bf, rxdtx_ctrl); + move16 (); +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*-------------------------------------------------------* + * - Decode innovative codebook. * + *-------------------------------------------------------*/ + + test (); logic16 (); + if ((rxdtx_ctrl & RX_SP_FLAG) != 0) + { + dec_10i40_35bits (parm, code); + } + else + { /* Use pseudo noise for excitation when SP_flag == 0 */ + build_CN_code (code, &L_pn_seed_rx); + } + + parm += 10; move16 (); +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*-------------------------------------------------------* + * - Add the pitch contribution to code[]. * + *-------------------------------------------------------*/ + + /* pit_sharp = gain_pit; */ + /* if (pit_sharp > 1.0) pit_sharp = 1.0; */ + + pit_sharp = shl (gain_pit, 3); + + /* This loop is not entered when SP_FLAG is 0 */ + for (i = T0; i < L_SUBFR; i++) + { + temp = mult (code[i - T0], pit_sharp); + code[i] = add (code[i], temp); + move16 (); + } +#if (WMOPS) + fwc (); /* function worst case */ +#endif + /* post processing of excitation elements */ + + test (); /* This test is not passed when SP_FLAG is 0 */ + if (sub (pit_sharp, 16384) > 0) + { + for (i = 0; i < L_SUBFR; i++) + { + temp = mult (exc[i + i_subfr], pit_sharp); + L_temp = L_mult (temp, gain_pit); + L_temp = L_shl (L_temp, 1); + excp[i] = round (L_temp); + move16 (); + } + } + /*-------------------------------------------------* + * - Decode codebook gain. * + *-------------------------------------------------*/ + + index = *parm++; move16 (); /* index of energy VQ */ + + d_gain_code (index, code, L_SUBFR, &gain_code, bfi, state, prev_bf, + rxdtx_ctrl, i_subfr, rx_dtx_state); +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + /*-------------------------------------------------------* + * - Find the total excitation. * + * - Find synthesis speech corresponding to exc[]. * + *-------------------------------------------------------*/ + for (i = 0; i < L_SUBFR; i++) + { + /* exc[i] = gain_pit*exc[i] + gain_code*code[i]; */ + + L_temp = L_mult (exc[i + i_subfr], gain_pit); + L_temp = L_mac (L_temp, code[i], gain_code); + L_temp = L_shl (L_temp, 3); + + exc[i + i_subfr] = round (L_temp); + move16 (); + } +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + test (); + if (sub (pit_sharp, 16384) > 0) + { + for (i = 0; i < L_SUBFR; i++) + { + excp[i] = add (excp[i], exc[i + i_subfr]); + move16 (); + } + agc2 (&exc[i_subfr], excp, L_SUBFR); + Syn_filt (Az, excp, &synth[i_subfr], L_SUBFR, mem_syn, 1); + } + else + { + Syn_filt (Az, &exc[i_subfr], &synth[i_subfr], L_SUBFR, mem_syn, 1); + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + /* interpolated LPC parameters for next subframe */ + Az += MP1; move16 (); + } + + /*--------------------------------------------------* + * Update signal for next frame. * + * -> shift to the left by L_FRAME exc[] * + *--------------------------------------------------*/ + + Copy (&old_exc[L_FRAME], &old_exc[0], PIT_MAX + L_INTERPOL); +#if (WMOPS) + fwc (); /* function worst case */ +#endif + prev_bf = bfi; move16 (); + + return; +} diff -r 000000000000 -r 56410792419a src/dec_lag6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dec_lag6.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,118 @@ +/************************************************************************* + * FUNCTION: Dec_lag6 + * + * PURPOSE: Decoding of fractional pitch lag with 1/6 resolution. + * Extract the integer and fraction parts of the pitch lag from + * the received adaptive codebook index. + * + * See "Enc_lag6.c" for more details about the encoding procedure. + * + * The fractional lag in 1st and 3rd subframes is encoded with 9 bits + * while that in 2nd and 4th subframes is relatively encoded with 6 bits. + * Note that in relative encoding only 61 values are used. If the + * decoder receives 61, 62, or 63 as the relative pitch index, it means + * that a transmission error occurred. In this case, the pitch lag from + * previous subframe is used. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +/* Old integer lag */ + +Word16 old_T0; + +Word16 +Dec_lag6 ( /* output: return integer pitch lag */ + Word16 index, /* input : received pitch index */ + Word16 pit_min, /* input : minimum pitch lag */ + Word16 pit_max, /* input : maximum pitch lag */ + Word16 i_subfr, /* input : subframe flag */ + Word16 L_frame_by2,/* input : speech frame size divided by 2 */ + Word16 *T0_frac, /* output: fractional part of pitch lag */ + Word16 bfi /* input : bad frame indicator */ +) +{ + Word16 pit_flag; + Word16 T0, i; + static Word16 T0_min, T0_max; + + pit_flag = i_subfr; move16 (); /* flag for 1st or 3rd subframe */ + test (); + if (sub (i_subfr, L_frame_by2) == 0) + { + pit_flag = 0; move16 (); + } + test (); + if (pit_flag == 0) /* if 1st or 3rd subframe */ + { + test (); + if (bfi == 0) + { /* if bfi == 0 decode pitch */ + test (); + if (sub (index, 463) < 0) + { + /* T0 = (index+5)/6 + 17 */ + T0 = add (mult (add (index, 5), 5462), 17); + i = add (add (T0, T0), T0); + /* *T0_frac = index - T0*6 + 105 */ + *T0_frac = add (sub (index, add (i, i)), 105); + move16 (); + } + else + { + T0 = sub (index, 368); + *T0_frac = 0; move16 (); + } + } + else + /* bfi == 1 */ + { + T0 = old_T0; move16 (); + *T0_frac = 0; move16 (); + } + + /* find T0_min and T0_max for 2nd (or 4th) subframe */ + + T0_min = sub (T0, 5); + test (); + if (sub (T0_min, pit_min) < 0) + { + T0_min = pit_min; move16 (); + } + T0_max = add (T0_min, 9); + test (); + if (sub (T0_max, pit_max) > 0) + { + T0_max = pit_max; move16 (); + T0_min = sub (T0_max, 9); + } + } + else + /* second or fourth subframe */ + { + test (); test (); + /* if bfi == 0 decode pitch */ + if ((bfi == 0) && (sub (index, 61) < 0)) + { + /* i = (index+5)/6 - 1 */ + i = sub (mult (add (index, 5), 5462), 1); + T0 = add (i, T0_min); + i = add (add (i, i), i); + *T0_frac = sub (sub (index, 3), add (i, i)); + move16 (); + } + else + /* bfi == 1 OR index >= 61 */ + { + T0 = old_T0; move16 (); + *T0_frac = 0; move16 (); + } + } + + old_T0 = T0; move16 (); + + return T0; +} diff -r 000000000000 -r 56410792419a src/decoder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/decoder.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,218 @@ +/*************************************************************************** + * + * FILE NAME: decoder.c + * + * Usage : decoder bitstream_file synth_file + * + * Format for bitstream_file: + * One word (2-byte) for bad frame indication (BFI) flag bit + * 0x0000 -> good frame; 0x0001 -> bad frame + * 244 words (2-byte) containing 244 bits. + * Bit 0 = 0x0000 and Bit 1 = 0x0001 + * One word (2-byte) for ternary Silence Descriptor (SID) flag + * 0x0000 -> inactive (no detected speech activity); + * 0x0001 -> active + * One word (2-byte) for Time Alignment Flag (TAF) bit + * 0x0000 -> inactive (no transmission of speech frames); + * 0x0001 -> active + * + * Format for synth_file: + * Synthesis is written to a binary file of 16 bits data. + * + ***************************************************************************/ + +#include +#include +#include "typedef.h" +#include "n_stack.h" +#include "basic_op.h" +#include "sig_proc.h" +#include "count.h" +#include "codec.h" +#include "cnst.h" +#include "d_homing.h" + + +/* These constants define the number of consecutive parameters + that function decoder_homing_frame_test() checks */ + +#define WHOLE_FRAME 57 +#define TO_FIRST_SUBFRAME 18 + + +Word16 synth_buf[L_FRAME + M]; + +/* L_FRAME, M, PRM_SIZE, AZ_SIZE, SERIAL_SIZE: defined in "cnst.h" */ + +/*-----------------------------------------------------------------* + * Global variables * + *-----------------------------------------------------------------*/ + +#if (WMOPS) +Word16 dtx_mode = 0; + +#endif + +/*-----------------------------------------------------------------* + * Main decoder routine * + *-----------------------------------------------------------------*/ + +int +main (int argc, char *argv[]) +{ + Word16 *synth; /* Synthesis */ + Word16 parm[PRM_SIZE + 1]; /* Synthesis parameters */ + Word16 serial[SERIAL_SIZE+2];/* Serial stream */ + Word16 Az_dec[AZ_SIZE]; /* Decoded Az for post-filter */ + /* in 4 subframes, length= 44 */ + Word16 i, frame, temp; + FILE *f_syn, *f_serial; + + Word16 TAF, SID_flag; + + Word16 reset_flag; + static Word16 reset_flag_old = 1; + + proc_head ("Decoder"); + + /*-----------------------------------------------------------------* + * Read passed arguments and open in/out files * + *-----------------------------------------------------------------*/ + + if (argc != 3) + { + fprintf (stderr, + " Usage:\n\n decoder bitstream_file synth_file\n"); + fprintf (stderr, "\n"); + exit (1); + } + /* Open file for synthesis and packed serial stream */ + + if ((f_serial = fopen (argv[1], "rb")) == NULL) + { + fprintf (stderr, "Input file '%s' does not exist !!\n", argv[1]); + exit (0); + } + else + fprintf (stderr, "Input bitstream file: %s\n", argv[1]); + + if ((f_syn = fopen (argv[2], "wb")) == NULL) + { + fprintf (stderr, "Cannot open file '%s' !!\n", argv[2]); + exit (0); + } + else + fprintf (stderr, "Synthesis speech file: %s\n", argv[2]); + + /*-----------------------------------------------------------------* + * Initialization of decoder * + *-----------------------------------------------------------------*/ + + synth = synth_buf + M; + + reset_dec (); /* Bring the decoder and receive DTX to the initial state */ + +#if (WMOPS) + Init_WMOPS_counter (); +#endif + + /*-----------------------------------------------------------------* + * Loop for each "L_FRAME" speech data * + *-----------------------------------------------------------------*/ + + frame = 0; + + while (fread (serial, sizeof (Word16), 247, f_serial) == 247) + { +#if (WMOPS) + fprintf (stderr, "frame=%d ", ++frame); +#else + fprintf (stderr, "\nframe=%d ", ++frame); +#endif + +#if (WMOPS) + Reset_WMOPS_counter (); /* reset WMOPS counter for the new frame */ +#endif + + SID_flag = serial[245]; /* Receive SID flag */ + TAF = serial[246]; /* Receive TAF flag */ + + Bits2prm_12k2 (serial, parm); /* serial to parameters */ + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + if (parm[0] == 0) /* BFI == 0, perform DHF check */ + { + if (reset_flag_old == 1) /* Check for second and further + successive DHF (to first subfr.) */ + { + reset_flag = decoder_homing_frame_test (&parm[1], + TO_FIRST_SUBFRAME); + } + else + { + reset_flag = 0; + } + } + else /* BFI==1, bypass DHF check (frame + is taken as not being a DHF) */ + { + reset_flag = 0; + } + + if ((reset_flag != 0) && (reset_flag_old != 0)) + { + /* Force the output to be the encoder homing frame pattern */ + + for (i = 0; i < L_FRAME; i++) + { + synth[i] = EHF_MASK; + } + } + else + { + Decoder_12k2 (parm, synth, Az_dec, TAF, SID_flag);/* Synthesis */ + + Post_Filter (synth, Az_dec); /* Post-filter */ +#if (WMOPS) + fwc (); /* function worst case */ +#endif + + for (i = 0; i < L_FRAME; i++) + /* Upscale the 15 bit linear PCM to 16 bits, + then truncate to 13 bits */ + { + temp = shl (synth[i], 1); + synth[i] = temp & 0xfff8; logic16 (); move16 (); + } + +#if (WMOPS) + fwc (); /* function worst case */ +#endif + +#if (WMOPS) + WMOPS_output (dtx_mode);/* output WMOPS values for current frame */ +#endif + } /* else */ + + fwrite (synth, sizeof (Word16), L_FRAME, f_syn); + + /* BFI == 0, perform check for first DHF (whole frame) */ + if ((parm[0] == 0) && (reset_flag_old == 0)) + { + reset_flag = decoder_homing_frame_test (&parm[1], WHOLE_FRAME); + } + + if (reset_flag != 0) + { + /* Bring the decoder and receive DTX to the home state */ + reset_dec (); + } + reset_flag_old = reset_flag; + + } /* while */ + + return 0; +} diff -r 000000000000 -r 56410792419a src/dtx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dtx.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,1293 @@ +/*************************************************************************** + * + * File Name: dtx.c + * + * Purpose: Contains functions for performing DTX operation and comfort + * noise generation. + * + * Below is a listing of all the functions appearing in the file. + * The functions are arranged according to their purpose. Under + * each heading, the ordering is hierarchical. + * + * Resetting of static variables of TX DTX: + * reset_tx_dtx() + * Resetting of static variables of RX DTX: + * reset_rx_dtx() + * + * TX DTX handler (called by the speech encoder): + * tx_dtx() + * RX DTX handler (called by the speech decoder): + * rx_dtx() + * Encoding of comfort noise parameters into SID frame: + * CN_encoding() + * Encoding of SID codeword into SID frame: + * sid_codeword_encoding() + * Detecting of SID codeword from a frame: + * sid_frame_detection() + * Update the LSF parameter history: + * update_lsf_history() + * Update the reference LSF parameter vector: + * update_lsf_p_CN() + * Compute the averaged LSF parameter vector: + * aver_lsf_history() + * Update the fixed codebook gain parameter history of the encoder: + * update_gain_code_history_tx() + * Update the fixed codebook gain parameter history of the decoder: + * update_gain_code_history_rx() + * Compute the unquantized fixed codebook gain: + * compute_CN_excitation_gain() + * Update the reference fixed codebook gain: + * update_gcode0_CN() + * Compute the averaged fixed codebook gain: + * aver_gain_code_history() + * Compute the comfort noise fixed codebook excitation: + * build_CN_code() + * Generate a random integer value: + * pseudonoise() + * Interpolate a comfort noise parameter value over the comfort noise + * update period: + * interpolate_CN_param() + * Interpolate comfort noise LSF pparameter values over the comfort + * noise update period: + * interpolate_CN_lsf() + * interpolate_CN_param() + * + **************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "cnst.h" +#include "sig_proc.h" +#include "count.h" +#include "dtx.h" + +/* Inverse values of DTX hangover period and DTX hangover period + 1 */ + +#define INV_DTX_HANGOVER (0x7fff / DTX_HANGOVER) +#define INV_DTX_HANGOVER_P1 (0x7fff / (DTX_HANGOVER+1)) + +#define NB_PULSE 10 /* Number of pulses in fixed codebook excitation */ + +/* SID frame classification thresholds */ + +#define VALID_SID_THRESH 2 +#define INVALID_SID_THRESH 16 + +/* Constant DTX_ELAPSED_THRESHOLD is used as threshold for allowing + SID frame updating without hangover period in case when elapsed + time measured from previous SID update is below 24 */ + +#define DTX_ELAPSED_THRESHOLD (24 + DTX_HANGOVER - 1) + +/* Index map for encoding and detecting SID codeword */ + +static const Word16 SID_codeword_bit_idx[95] = +{ + 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 94, 95, 96, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221 +}; + +Word16 txdtx_ctrl; /* Encoder DTX control word */ +Word16 rxdtx_ctrl; /* Decoder DTX control word */ +Word16 CN_excitation_gain; /* Unquantized fixed codebook gain */ +Word32 L_pn_seed_tx; /* PN generator seed (encoder) */ +Word32 L_pn_seed_rx; /* PN generator seed (decoder) */ +Word16 rx_dtx_state; /* State of comfort noise insertion period */ + +static Word16 txdtx_hangover; /* Length of hangover period (VAD=0, SP=1) */ +static Word16 rxdtx_aver_period;/* Length of hangover period (VAD=0, SP=1) */ +static Word16 txdtx_N_elapsed; /* Measured time from previous SID frame */ +static Word16 rxdtx_N_elapsed; /* Measured time from previous SID frame */ +static Word16 old_CN_mem_tx[6]; /* The most recent CN parameters are stored*/ +static Word16 prev_SID_frames_lost; /* Counter for lost SID frames */ +static Word16 buf_p_tx; /* Circular buffer pointer for gain code + history update in tx */ +static Word16 buf_p_rx; /* Circular buffer pointer for gain code + history update in rx */ + +Word16 lsf_old_tx[DTX_HANGOVER][M]; /* Comfort noise LSF averaging buffer */ +Word16 lsf_old_rx[DTX_HANGOVER][M]; /* Comfort noise LSF averaging buffer */ + +Word16 gain_code_old_tx[4 * DTX_HANGOVER]; /* Comfort noise gain averaging + buffer */ +Word16 gain_code_old_rx[4 * DTX_HANGOVER]; /* Comfort noise gain averaging + buffer */ + +/************************************************************************* + * + * FUNCTION NAME: reset_tx_dtx + * + * PURPOSE: Resets the static variables of the TX DTX handler to their + * initial values + * + *************************************************************************/ + +void reset_tx_dtx () +{ + Word16 i; + + /* suppose infinitely long speech period before start */ + + txdtx_hangover = DTX_HANGOVER; + txdtx_N_elapsed = 0x7fff; + txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG; + + for (i = 0; i < 6; i++) + { + old_CN_mem_tx[i] = 0; + } + + for (i = 0; i < DTX_HANGOVER; i++) + { + lsf_old_tx[i][0] = 1384; + lsf_old_tx[i][1] = 2077; + lsf_old_tx[i][2] = 3420; + lsf_old_tx[i][3] = 5108; + lsf_old_tx[i][4] = 6742; + lsf_old_tx[i][5] = 8122; + lsf_old_tx[i][6] = 9863; + lsf_old_tx[i][7] = 11092; + lsf_old_tx[i][8] = 12714; + lsf_old_tx[i][9] = 13701; + } + + for (i = 0; i < 4 * DTX_HANGOVER; i++) + { + gain_code_old_tx[i] = 0; + } + + L_pn_seed_tx = PN_INITIAL_SEED; + + buf_p_tx = 0; + return; +} + +/************************************************************************* + * + * FUNCTION NAME: reset_rx_dtx + * + * PURPOSE: Resets the static variables of the RX DTX handler to their + * initial values + * + *************************************************************************/ + +void reset_rx_dtx () +{ + Word16 i; + + /* suppose infinitely long speech period before start */ + + rxdtx_aver_period = DTX_HANGOVER; + rxdtx_N_elapsed = 0x7fff; + rxdtx_ctrl = RX_SP_FLAG; + + for (i = 0; i < DTX_HANGOVER; i++) + { + lsf_old_rx[i][0] = 1384; + lsf_old_rx[i][1] = 2077; + lsf_old_rx[i][2] = 3420; + lsf_old_rx[i][3] = 5108; + lsf_old_rx[i][4] = 6742; + lsf_old_rx[i][5] = 8122; + lsf_old_rx[i][6] = 9863; + lsf_old_rx[i][7] = 11092; + lsf_old_rx[i][8] = 12714; + lsf_old_rx[i][9] = 13701; + } + + for (i = 0; i < 4 * DTX_HANGOVER; i++) + { + gain_code_old_rx[i] = 0; + } + + L_pn_seed_rx = PN_INITIAL_SEED; + rx_dtx_state = CN_INT_PERIOD - 1; + + prev_SID_frames_lost = 0; + buf_p_rx = 0; + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: tx_dtx + * + * PURPOSE: DTX handler of the speech encoder. Determines when to add + * the hangover period to the end of the speech burst, and + * also determines when to use old SID parameters, and when + * to update the SID parameters. This function also initializes + * the pseudo noise generator shift register. + * + * Operation of the TX DTX handler is based on the VAD flag + * given as input from the speech encoder. + * + * INPUTS: VAD_flag Voice activity decision + * *txdtx_ctrl Old encoder DTX control word + * + * OUTPUTS: *txdtx_ctrl Updated encoder DTX control word + * L_pn_seed_tx Initialized pseudo noise generator shift + * register (global variable) + * + * RETURN VALUE: none + * + *************************************************************************/ + +void tx_dtx ( + Word16 VAD_flag, + Word16 *txdtx_ctrl +) +{ + + /* N_elapsed (frames since last SID update) is incremented. If SID + is updated N_elapsed is cleared later in this function */ + + txdtx_N_elapsed = add (txdtx_N_elapsed, 1); + + /* If voice activity was detected, reset hangover counter */ + + test (); + if (sub (VAD_flag, 1) == 0) + { + txdtx_hangover = DTX_HANGOVER; move16 (); + *txdtx_ctrl = TX_SP_FLAG | TX_VAD_FLAG; move16 (); logic16 (); + } + else + { + test (); + if (txdtx_hangover == 0) + { + /* Hangover period is over, SID should be updated */ + + txdtx_N_elapsed = 0; move16 (); + + /* Check if this is the first frame after hangover period */ + test (); logic16 (); + if ((*txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0) + { + *txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE + | TX_SID_UPDATE; move16 (); logic16 (); + L_pn_seed_tx = PN_INITIAL_SEED; move32 (); + } + else + { + *txdtx_ctrl = TX_SID_UPDATE; move16 (); + } + } + else + { + /* Hangover period is not over, update hangover counter */ + txdtx_hangover = sub (txdtx_hangover, 1); + + /* Check if elapsed time from last SID update is greater than + threshold. If not, set SP=0 (although hangover period is not + over) and use old SID parameters for new SID frame. + N_elapsed counter must be summed with hangover counter in order + to avoid erroneus SP=1 decision in case when N_elapsed is grown + bigger than threshold and hangover period is still active */ + + test (); + if (sub (add (txdtx_N_elapsed, txdtx_hangover), + DTX_ELAPSED_THRESHOLD) < 0) + { + /* old SID frame should be used */ + *txdtx_ctrl = TX_USE_OLD_SID; move16 (); + } + else + { + test (); logic16 (); + if ((*txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0) + { + *txdtx_ctrl = TX_PREV_HANGOVER_ACTIVE + | TX_HANGOVER_ACTIVE + | TX_SP_FLAG; move16 (); logic16 (); logic16 (); + } + else + { + *txdtx_ctrl = TX_HANGOVER_ACTIVE + | TX_SP_FLAG; move16 (); logic16 (); + } + } + } + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: rx_dtx + * + * PURPOSE: DTX handler of the speech decoder. Determines when to update + * the reference comfort noise parameters (LSF and gain) at the + * end of the speech burst. Also classifies the incoming frames + * according to SID flag and BFI flag + * and determines when the transmission is active during comfort + * noise insertion. This function also initializes the pseudo + * noise generator shift register. + * + * Operation of the RX DTX handler is based on measuring the + * lengths of speech bursts and the lengths of the pauses between + * speech bursts to determine when there exists a hangover period + * at the end of a speech burst. The idea is to keep in sync with + * the TX DTX handler to be able to update the reference comfort + * noise parameters at the same time instances. + * + * INPUTS: *rxdtx_ctrl Old decoder DTX control word + * TAF Time alignment flag + * bfi Bad frame indicator flag + * SID_flag Silence descriptor flag + * + * OUTPUTS: *rxdtx_ctrl Updated decoder DTX control word + * rx_dtx_state Updated state of comfort noise interpolation + * period (global variable) + * L_pn_seed_rx Initialized pseudo noise generator shift + * register (global variable) + * + * RETURN VALUE: none + * + *************************************************************************/ + +void rx_dtx ( + Word16 *rxdtx_ctrl, + Word16 TAF, + Word16 bfi, + Word16 SID_flag +) +{ + Word16 frame_type; + + /* Frame classification according to bfi-flag and ternary-valued + SID flag. The frames between SID updates (not actually trans- + mitted) are also classified here; they will be discarded later + and provided with "NO TRANSMISSION"-flag */ + + test (); test (); + test (); test (); + test (); test (); + if ((sub (SID_flag, 2) == 0) && (bfi == 0)) + { + frame_type = VALID_SID_FRAME; move16 (); + } + else if ((SID_flag == 0) && (bfi == 0)) + { + frame_type = GOOD_SPEECH_FRAME; move16 (); + } + else if ((SID_flag == 0) && (bfi != 0)) + { + frame_type = UNUSABLE_FRAME; move16 (); + } + else + { + frame_type = INVALID_SID_FRAME; move16 (); + } + + /* Update of decoder state */ + /* Previous frame was classified as a speech frame */ + test (); logic16 (); + if ((*rxdtx_ctrl & RX_SP_FLAG) != 0) + { + test (); test (); test (); test (); + if (sub (frame_type, VALID_SID_FRAME) == 0) + { + *rxdtx_ctrl = RX_FIRST_SID_UPDATE; move16 (); + } + else if (sub (frame_type, INVALID_SID_FRAME) == 0) + { + *rxdtx_ctrl = RX_FIRST_SID_UPDATE + | RX_INVALID_SID_FRAME; move16 (); logic16(); + } + else if (sub (frame_type, UNUSABLE_FRAME) == 0) + { + *rxdtx_ctrl = RX_SP_FLAG; move16 (); + } + else if (sub (frame_type, GOOD_SPEECH_FRAME) == 0) + { + *rxdtx_ctrl = RX_SP_FLAG; move16 (); + } + } + else + { + test (); test (); test (); test (); + if (sub (frame_type, VALID_SID_FRAME) == 0) + { + *rxdtx_ctrl = RX_CONT_SID_UPDATE; move16 (); + } + else if (sub (frame_type, INVALID_SID_FRAME) == 0) + { + *rxdtx_ctrl = RX_CONT_SID_UPDATE + | RX_INVALID_SID_FRAME; move16 (); logic16 (); + } + else if (sub (frame_type, UNUSABLE_FRAME) == 0) + { + *rxdtx_ctrl = RX_CNI_BFI; move16 (); + } + else if (sub (frame_type, GOOD_SPEECH_FRAME) == 0) + { + /* If the previous frame (during CNI period) was muted, + raise the RX_PREV_DTX_MUTING flag */ + test (); logic16 (); + if ((*rxdtx_ctrl & RX_DTX_MUTING) != 0) + { + *rxdtx_ctrl = RX_SP_FLAG | RX_FIRST_SP_FLAG + | RX_PREV_DTX_MUTING; move16 (); logic16 (); + logic16 (); + } + else + { + *rxdtx_ctrl = RX_SP_FLAG | RX_FIRST_SP_FLAG; move16 (); + logic16 (); + } + } + } + + + test (); logic16 (); + if ((*rxdtx_ctrl & RX_SP_FLAG) != 0) + { + prev_SID_frames_lost = 0; move16 (); + rx_dtx_state = CN_INT_PERIOD - 1; move16 (); + } + else + { + /* First SID frame */ + test (); logic16 (); + if ((*rxdtx_ctrl & RX_FIRST_SID_UPDATE) != 0) + { + prev_SID_frames_lost = 0; move16 (); + rx_dtx_state = CN_INT_PERIOD - 1; move16 (); + } + + /* SID frame detected, but not the first SID */ + test (); logic16 (); + if ((*rxdtx_ctrl & RX_CONT_SID_UPDATE) != 0) + { + prev_SID_frames_lost = 0; move16 (); + + test (); test (); + if (sub (frame_type, VALID_SID_FRAME) == 0) + { + rx_dtx_state = 0; move16 (); + } + else if (sub (frame_type, INVALID_SID_FRAME) == 0) + { + test (); + if (sub(rx_dtx_state, (CN_INT_PERIOD - 1)) < 0) + { + rx_dtx_state = add(rx_dtx_state, 1); move16 (); + } + } + } + + /* Bad frame received in CNI mode */ + test (); logic16 (); + if ((*rxdtx_ctrl & RX_CNI_BFI) != 0) + { + test (); + if (sub (rx_dtx_state, (CN_INT_PERIOD - 1)) < 0) + { + rx_dtx_state = add (rx_dtx_state, 1); move16 (); + } + + /* If an unusable frame is received during CNI period + when TAF == 1, the frame is classified as a lost + SID frame */ + test (); + if (sub (TAF, 1) == 0) + { + *rxdtx_ctrl = *rxdtx_ctrl | RX_LOST_SID_FRAME; + move16 (); logic16 (); + prev_SID_frames_lost = add (prev_SID_frames_lost, 1); + } + else /* No transmission occurred */ + { + *rxdtx_ctrl = *rxdtx_ctrl | RX_NO_TRANSMISSION; + move16 (); logic16 (); + } + + test (); + if (sub (prev_SID_frames_lost, 1) > 0) + { + *rxdtx_ctrl = *rxdtx_ctrl | RX_DTX_MUTING; + move16 (); logic16 (); + } + } + } + + /* N_elapsed (frames since last SID update) is incremented. If SID + is updated N_elapsed is cleared later in this function */ + + rxdtx_N_elapsed = add (rxdtx_N_elapsed, 1); + + test (); logic16 (); + if ((*rxdtx_ctrl & RX_SP_FLAG) != 0) + { + rxdtx_aver_period = DTX_HANGOVER; move16 (); + } + else + { + test (); test (); + if (sub (rxdtx_N_elapsed, DTX_ELAPSED_THRESHOLD) > 0) + { + *rxdtx_ctrl |= RX_UPD_SID_QUANT_MEM; move16 (); logic16 (); + rxdtx_N_elapsed = 0; move16 (); + rxdtx_aver_period = 0; move16 (); + L_pn_seed_rx = PN_INITIAL_SEED; move32 (); + } + else if (rxdtx_aver_period == 0) + { + rxdtx_N_elapsed = 0; move16 (); + } + else + { + rxdtx_aver_period = sub (rxdtx_aver_period, 1); + } + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: CN_encoding + * + * PURPOSE: Encoding of the comfort noise parameters into a SID frame. + * Use old SID parameters if necessary. Set the parameter + * indices not used by comfort noise parameters to zero. + * + * INPUTS: params[0..56] Comfort noise parameter frame from the + * speech encoder + * txdtx_ctrl TX DTX handler control word + * + * OUTPUTS: params[0..56] Comfort noise encoded parameter frame + * + * RETURN VALUE: none + * + *************************************************************************/ + +void CN_encoding ( + Word16 params[], + Word16 txdtx_ctrl +) +{ + Word16 i; + + test (); logic16 (); + if ((txdtx_ctrl & TX_SID_UPDATE) != 0) + { + /* Store new CN parameters in memory to be used later as old + CN parameters */ + + /* LPC parameter indices */ + for (i = 0; i < 5; i++) + { + old_CN_mem_tx[i] = params[i]; move16 (); + } + /* Codebook index computed in last subframe */ + old_CN_mem_tx[5] = params[56]; move16 (); + } + test (); logic16 (); + if ((txdtx_ctrl & TX_USE_OLD_SID) != 0) + { + /* Use old CN parameters previously stored in memory */ + for (i = 0; i < 5; i++) + { + params[i] = old_CN_mem_tx[i]; move16 (); + } + params[17] = old_CN_mem_tx[5]; move16 (); + params[30] = old_CN_mem_tx[5]; move16 (); + params[43] = old_CN_mem_tx[5]; move16 (); + params[56] = old_CN_mem_tx[5]; move16 (); + } + /* Set all the rest of the parameters to zero (SID codeword will + be written later) */ + for (i = 0; i < 12; i++) + { + params[i + 5] = 0; move16 (); + params[i + 18] = 0; move16 (); + params[i + 31] = 0; move16 (); + params[i + 44] = 0; move16 (); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: sid_codeword_encoding + * + * PURPOSE: Encoding of the SID codeword into the SID frame. The SID + * codeword consists of 95 bits, all set to '1'. + * + * INPUTS: ser2[0..243] Serial-mode speech parameter frame before + * writing SID codeword into it + * + * OUTPUTS: ser2[0..243] Serial-mode speech parameter frame with + * SID codeword written into it + * + * RETURN VALUE: none + * + *************************************************************************/ + +void sid_codeword_encoding ( + Word16 ser2[] +) +{ + Word16 i; + + for (i = 0; i < 95; i++) + { + ser2[SID_codeword_bit_idx[i]] = 1; move16 (); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: sid_frame_detection + * + * PURPOSE: Detecting of SID codeword from a received frame. The frames + * are classified into three categories based on how many bit + * errors occur in the SID codeword: + * - VALID SID FRAME + * - INVALID SID FRAME + * - SPEECH FRAME + * + * INPUTS: ser2[0..243] Received serial-mode speech parameter frame + * + * OUTPUTS: none + * + * RETURN VALUE: Ternary-valued SID classification flag + * + *************************************************************************/ + +Word16 sid_frame_detection ( + Word16 ser2[] +) +{ + Word16 i, nbr_errors, sid; + + /* Search for bit errors in SID codeword */ + nbr_errors = 0; move16 (); + for (i = 0; i < 95; i++) + { + test (); + if (ser2[SID_codeword_bit_idx[i]] == 0) + { + nbr_errors = add (nbr_errors, 1); + } + } + + /* Frame classification */ + test (); test (); + if (sub (nbr_errors, VALID_SID_THRESH) < 0) + { /* Valid SID frame */ + sid = 2; move16 (); + } + else if (sub (nbr_errors, INVALID_SID_THRESH) < 0) + { /* Invalid SID frame */ + sid = 1; move16 (); + } + else + { /* Speech frame */ + sid = 0; move16 (); + } + + return sid; +} + +/************************************************************************* + * + * FUNCTION NAME: update_lsf_history + * + * PURPOSE: Update the LSF parameter history. The LSF parameters kept + * in the buffer are used later for computing the reference + * LSF parameter vector and the averaged LSF parameter vector. + * + * INPUTS: lsf1[0..9] LSF vector of the 1st half of the frame + * lsf2[0..9] LSF vector of the 2nd half of the frame + * lsf_old[0..DTX_HANGOVER-1][0..M-1] + * Old LSF history + * + * OUTPUTS: lsf_old[0..DTX_HANGOVER-1][0..M-1] + * Updated LSF history + * + * RETURN VALUE: none + * + *************************************************************************/ + +void update_lsf_history ( + Word16 lsf1[M], + Word16 lsf2[M], + Word16 lsf_old[DTX_HANGOVER][M] +) +{ + Word16 i, j, temp; + + /* shift LSF data to make room for LSFs from current frame */ + /* This can also be implemented by using circular buffering */ + + for (i = DTX_HANGOVER - 1; i > 0; i--) + { + for (j = 0; j < M; j++) + { + lsf_old[i][j] = lsf_old[i - 1][j]; move16 (); + } + } + + /* Store new LSF data to lsf_old buffer */ + + for (i = 0; i < M; i++) + { + temp = add (shr (lsf1[i], 1), shr (lsf2[i], 1)); + lsf_old[0][i] = temp; move16 (); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: update_lsf_p_CN + * + * PURPOSE: Update the reference LSF parameter vector. The reference + * vector is computed by averaging the quantized LSF parameter + * vectors which exist in the LSF parameter history. + * + * INPUTS: lsf_old[0..DTX_HANGOVER-1][0..M-1] + * LSF parameter history + * + * OUTPUTS: lsf_p_CN[0..9] Computed reference LSF parameter vector + * + * RETURN VALUE: none + * + *************************************************************************/ + +void update_lsf_p_CN ( + Word16 lsf_old[DTX_HANGOVER][M], + Word16 lsf_p_CN[M] +) +{ + Word16 i, j; + Word32 L_temp; + + for (j = 0; j < M; j++) + { + L_temp = L_mult (INV_DTX_HANGOVER, lsf_old[0][j]); + for (i = 1; i < DTX_HANGOVER; i++) + { + L_temp = L_mac (L_temp, INV_DTX_HANGOVER, lsf_old[i][j]); + } + lsf_p_CN[j] = round (L_temp); move16 (); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: aver_lsf_history + * + * PURPOSE: Compute the averaged LSF parameter vector. Computation is + * performed by averaging the LSF parameter vectors which exist + * in the LSF parameter history, together with the LSF + * parameter vectors of the current frame. + * + * INPUTS: lsf_old[0..DTX_HANGOVER-1][0..M-1] + * LSF parameter history + * lsf1[0..M-1] LSF vector of the 1st half of the frame + * lsf2[0..M-1] LSF vector of the 2nd half of the frame + * + * OUTPUTS: lsf_aver[0..M-1] Averaged LSF parameter vector + * + * RETURN VALUE: none + * + *************************************************************************/ + +void aver_lsf_history ( + Word16 lsf_old[DTX_HANGOVER][M], + Word16 lsf1[M], + Word16 lsf2[M], + Word16 lsf_aver[M] +) +{ + Word16 i, j; + Word32 L_temp; + + for (j = 0; j < M; j++) + { + L_temp = L_mult (0x3fff, lsf1[j]); + L_temp = L_mac (L_temp, 0x3fff, lsf2[j]); + L_temp = L_mult (INV_DTX_HANGOVER_P1, extract_h (L_temp)); + + for (i = 0; i < DTX_HANGOVER; i++) + { + L_temp = L_mac (L_temp, INV_DTX_HANGOVER_P1, lsf_old[i][j]); + } + + lsf_aver[j] = extract_h (L_temp); move16 (); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: update_gain_code_history_tx + * + * PURPOSE: Update the fixed codebook gain parameter history of the + * encoder. The fixed codebook gain parameters kept in the buffer + * are used later for computing the reference fixed codebook + * gain parameter value and the averaged fixed codebook gain + * parameter value. + * + * INPUTS: new_gain_code New fixed codebook gain value + * + * gain_code_old_tx[0..4*DTX_HANGOVER-1] + * Old fixed codebook gain history of encoder + * + * OUTPUTS: gain_code_old_tx[0..4*DTX_HANGOVER-1] + * Updated fixed codebook gain history of encoder + * + * RETURN VALUE: none + * + *************************************************************************/ + +void update_gain_code_history_tx ( + Word16 new_gain_code, + Word16 gain_code_old_tx[4 * DTX_HANGOVER] +) +{ + + /* Circular buffer */ + gain_code_old_tx[buf_p_tx] = new_gain_code; move16 (); + + test (); + if (sub (buf_p_tx, (4 * DTX_HANGOVER - 1)) == 0) + { + buf_p_tx = 0; move16 (); + } + else + { + buf_p_tx = add (buf_p_tx, 1); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: update_gain_code_history_rx + * + * PURPOSE: Update the fixed codebook gain parameter history of the + * decoder. The fixed codebook gain parameters kept in the buffer + * are used later for computing the reference fixed codebook + * gain parameter value. + * + * INPUTS: new_gain_code New fixed codebook gain value + * + * gain_code_old_tx[0..4*DTX_HANGOVER-1] + * Old fixed codebook gain history of decoder + * + * OUTPUTS: gain_code_old_tx[0..4*DTX_HANGOVER-1] + * Updated fixed codebk gain history of decoder + * + * RETURN VALUE: none + * + *************************************************************************/ + +void update_gain_code_history_rx ( + Word16 new_gain_code, + Word16 gain_code_old_rx[4 * DTX_HANGOVER] +) +{ + + /* Circular buffer */ + gain_code_old_rx[buf_p_rx] = new_gain_code; move16 (); + + test (); + if (sub (buf_p_rx, (4 * DTX_HANGOVER - 1)) == 0) + { + buf_p_rx = 0; move16 (); + } + else + { + buf_p_rx = add (buf_p_rx, 1); + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: compute_CN_excitation_gain + * + * PURPOSE: Compute the unquantized fixed codebook gain. Computation is + * based on the energy of the Linear Prediction residual signal. + * + * INPUTS: res2[0..39] Linear Prediction residual signal + * + * OUTPUTS: none + * + * RETURN VALUE: Unquantized fixed codebook gain + * + *************************************************************************/ + +Word16 compute_CN_excitation_gain ( + Word16 res2[L_SUBFR] +) +{ + Word16 i, norm, norm1, temp, overfl; + Word32 L_temp; + + /* Compute the energy of the LP residual signal */ + + norm = 0; move16 (); + do + { + overfl = 0; move16 (); + + L_temp = 0L; move32 (); + for (i = 0; i < L_SUBFR; i++) + { + temp = shr (res2[i], norm); + L_temp = L_mac (L_temp, temp, temp); + } + + test (); + if (L_sub (L_temp, MAX_32) == 0) + { + norm = add (norm, 1); + overfl = 1; move16 (); /* Set the overflow flag */ + } + test (); + } + while (overfl != 0); + + L_temp = L_add (L_temp, 1L); /* Avoid the case of all zeros */ + + /* Take the square root of the obtained energy value (sqroot is a 2nd + order Taylor series approximation) */ + + norm1 = norm_l (L_temp); + temp = extract_h (L_shl (L_temp, norm1)); + L_temp = L_mult (temp, temp); + L_temp = L_sub (805306368L, L_shr (L_temp, 3)); + L_temp = L_add (L_temp, L_mult (24576, temp)); + + temp = extract_h (L_temp); + test (); logic16 (); + if ((norm1 & 0x0001) != 0) + { + temp = mult_r (temp, 23170); + norm1 = sub (norm1, 1); + } + /* Divide the result of sqroot operation by sqroot(10) */ + + temp = mult_r (temp, 10362); + + /* Re-scale to get the final value */ + + norm1 = shr (norm1, 1); + norm1 = sub (norm1, norm); + + test (); + if (norm1 >= 0) + { + temp = shr (temp, norm1); + } + else + { + temp = shl (temp, abs_s (norm1)); + } + + return temp; +} + +/************************************************************************* + * + * FUNCTION NAME: update_gcode0_CN + * + * PURPOSE: Update the reference fixed codebook gain parameter value. + * The reference value is computed by averaging the quantized + * fixed codebook gain parameter values which exist in the + * fixed codebook gain parameter history. + * + * INPUTS: gain_code_old[0..4*DTX_HANGOVER-1] + * fixed codebook gain parameter history + * + * OUTPUTS: none + * + * RETURN VALUE: Computed reference fixed codebook gain + * + *************************************************************************/ + +Word16 update_gcode0_CN ( + Word16 gain_code_old[4 * DTX_HANGOVER] +) +{ + Word16 i, j; + Word32 L_temp, L_ret; + + L_ret = 0L; move32 (); + for (i = 0; i < DTX_HANGOVER; i++) + { + L_temp = L_mult (0x1fff, gain_code_old[4 * i]); + for (j = 1; j < 4; j++) + { + L_temp = L_mac (L_temp, 0x1fff, gain_code_old[4 * i + j]); + } + L_ret = L_mac (L_ret, INV_DTX_HANGOVER, extract_h (L_temp)); + } + + return extract_h (L_ret); +} + +/************************************************************************* + * + * FUNCTION NAME: aver_gain_code_history + * + * PURPOSE: Compute the averaged fixed codebook gain parameter value. + * Computation is performed by averaging the fixed codebook + * gain parameter values which exist in the fixed codebook + * gain parameter history, together with the fixed codebook + * gain parameter value of the current subframe. + * + * INPUTS: CN_excitation_gain + * Unquantized fixed codebook gain value + * of the current subframe + * gain_code_old[0..4*DTX_HANGOVER-1] + * fixed codebook gain parameter history + * + * OUTPUTS: none + * + * RETURN VALUE: Averaged fixed codebook gain value + * + *************************************************************************/ + +Word16 aver_gain_code_history ( + Word16 CN_excitation_gain, + Word16 gain_code_old[4 * DTX_HANGOVER] +) +{ + Word16 i; + Word32 L_ret; + + L_ret = L_mult (0x470, CN_excitation_gain); + + for (i = 0; i < (4 * DTX_HANGOVER); i++) + { + L_ret = L_mac (L_ret, 0x470, gain_code_old[i]); + } + return extract_h (L_ret); +} + +/************************************************************************* + * + * FUNCTION NAME: build_CN_code + * + * PURPOSE: Compute the comfort noise fixed codebook excitation. The + * gains of the pulses are always +/-1. + * + * INPUTS: *seed Old CN generator shift register state + * + * OUTPUTS: cod[0..39] Generated comfort noise fixed codebook vector + * *seed Updated CN generator shift register state + * + * RETURN VALUE: none + * + *************************************************************************/ + +void build_CN_code ( + Word16 cod[], + Word32 *seed +) +{ + Word16 i, j, k; + + for (i = 0; i < L_SUBFR; i++) + { + cod[i] = 0; move16 (); + } + + for (k = 0; k < NB_PULSE; k++) + { + i = pseudonoise (seed, 2); /* generate pulse position */ + i = shr (extract_l (L_mult (i, 10)), 1); + i = add (i, k); + + j = pseudonoise (seed, 1); /* generate sign */ + + test (); + if (j > 0) + { + cod[i] = 4096; move16 (); + } + else + { + cod[i] = -4096; move16 (); + } + } + + return; +} + +/************************************************************************* + * + * FUNCTION NAME: pseudonoise + * + * PURPOSE: Generate a random integer value to use in comfort noise + * generation. The algorithm uses polynomial x^31 + x^3 + 1 + * (length of PN sequence is 2^31 - 1). + * + * INPUTS: *shift_reg Old CN generator shift register state + * + * + * OUTPUTS: *shift_reg Updated CN generator shift register state + * + * RETURN VALUE: Generated random integer value + * + *************************************************************************/ + +Word16 pseudonoise ( + Word32 *shift_reg, + Word16 no_bits +) +{ + Word16 noise_bits, Sn, i; + + noise_bits = 0; move16 (); + for (i = 0; i < no_bits; i++) + { + /* State n == 31 */ + test (); logic32 (); + if ((*shift_reg & 0x00000001L) != 0) + { + Sn = 1; move16 (); + } + else + { + Sn = 0; move16 (); + } + + /* State n == 3 */ + test (); logic32 (); + if ((*shift_reg & 0x10000000L) != 0) + { + Sn = Sn ^ 1; logic16 (); + } + else + { + Sn = Sn ^ 0; logic16 (); + } + + noise_bits = shl (noise_bits, 1); + noise_bits = noise_bits | (extract_l (*shift_reg) & 1); + logic16 (); logic16 (); + + *shift_reg = L_shr (*shift_reg, 1); move32 (); + test (); logic16 (); + if (Sn & 1) + { + *shift_reg = *shift_reg | 0x40000000L; move32 (); logic32 (); + } + } + + return noise_bits; +} + +/************************************************************************* + * + * FUNCTION NAME: interpolate_CN_param + * + * PURPOSE: Interpolate a comfort noise parameter value over the comfort + * noise update period. + * + * INPUTS: old_param The older parameter of the interpolation + * (the endpoint the interpolation is started + * from) + * new_param The newer parameter of the interpolation + * (the endpoint the interpolation is ended to) + * rx_dtx_state State of the comfort noise insertion period + * + * OUTPUTS: none + * + * RETURN VALUE: Interpolated CN parameter value + * + *************************************************************************/ + +Word16 interpolate_CN_param ( + Word16 old_param, + Word16 new_param, + Word16 rx_dtx_state +) +{ + static const Word16 interp_factor[CN_INT_PERIOD] = + { + 0x0555, 0x0aaa, 0x1000, 0x1555, 0x1aaa, 0x2000, + 0x2555, 0x2aaa, 0x3000, 0x3555, 0x3aaa, 0x4000, + 0x4555, 0x4aaa, 0x5000, 0x5555, 0x5aaa, 0x6000, + 0x6555, 0x6aaa, 0x7000, 0x7555, 0x7aaa, 0x7fff}; + Word16 temp; + Word32 L_temp; + + L_temp = L_mult (interp_factor[rx_dtx_state], new_param); + temp = sub (0x7fff, interp_factor[rx_dtx_state]); + temp = add (temp, 1); + L_temp = L_mac (L_temp, temp, old_param); + temp = round (L_temp); + + return temp; +} + +/************************************************************************* + * + * FUNCTION NAME: interpolate_CN_lsf + * + * PURPOSE: Interpolate comfort noise LSF parameter vector over the comfort + * noise update period. + * + * INPUTS: lsf_old_CN[0..9] + * The older LSF parameter vector of the + * interpolation (the endpoint the interpolation + * is started from) + * lsf_new_CN[0..9] + * The newer LSF parameter vector of the + * interpolation (the endpoint the interpolation + * is ended to) + * rx_dtx_state State of the comfort noise insertion period + * + * OUTPUTS: lsf_interp_CN[0..9] + * Interpolated LSF parameter vector + * + * RETURN VALUE: none + * + *************************************************************************/ + +void interpolate_CN_lsf ( + Word16 lsf_old_CN[M], + Word16 lsf_new_CN[M], + Word16 lsf_interp_CN[M], + Word16 rx_dtx_state +) +{ + Word16 i; + + for (i = 0; i < M; i++) + { + lsf_interp_CN[i] = interpolate_CN_param (lsf_old_CN[i], + lsf_new_CN[i], + rx_dtx_state); move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/dtx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dtx.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,140 @@ +/*************************************************************************** + * + * File Name: dtx.h + * + * Purpose: Contains the prototypes for all the functions of DTX. + * Also contains definitions of constants used in DTX functions. + * + **************************************************************************/ + +#define PN_INITIAL_SEED 0x70816958L /* Pseudo noise generator seed value */ + +#define CN_INT_PERIOD 24 /* Comfort noise interpolation period + (nbr of frames between successive + SID updates in the decoder) */ + +#define DTX_HANGOVER 7 /* Period when SP=1 although VAD=0. + Used for comfort noise averaging */ + + +/* Frame classification constants */ + +#define VALID_SID_FRAME 1 +#define INVALID_SID_FRAME 2 +#define GOOD_SPEECH_FRAME 3 +#define UNUSABLE_FRAME 4 + +/* Encoder DTX control flags */ + +#define TX_SP_FLAG 0x0001 +#define TX_VAD_FLAG 0x0002 +#define TX_HANGOVER_ACTIVE 0x0004 +#define TX_PREV_HANGOVER_ACTIVE 0x0008 +#define TX_SID_UPDATE 0x0010 +#define TX_USE_OLD_SID 0x0020 + +/* Decoder DTX control flags */ + +#define RX_SP_FLAG 0x0001 +#define RX_UPD_SID_QUANT_MEM 0x0002 +#define RX_FIRST_SID_UPDATE 0x0004 +#define RX_CONT_SID_UPDATE 0x0008 +#define RX_LOST_SID_FRAME 0x0010 +#define RX_INVALID_SID_FRAME 0x0020 +#define RX_NO_TRANSMISSION 0x0040 +#define RX_DTX_MUTING 0x0080 +#define RX_PREV_DTX_MUTING 0x0100 +#define RX_CNI_BFI 0x0200 +#define RX_FIRST_SP_FLAG 0x0400 + +void reset_tx_dtx (void); /* Reset tx dtx variables */ +void reset_rx_dtx (void); /* Reset rx dtx variables */ + +void tx_dtx ( + Word16 VAD_flag, + Word16 *txdtx_ctrl +); + +void rx_dtx ( + Word16 *rxdtx_ctrl, + Word16 TAF, + Word16 bfi, + Word16 SID_flag +); + +void CN_encoding ( + Word16 params[], + Word16 txdtx_ctrl +); + +void sid_codeword_encoding ( + Word16 ser2[] +); + +Word16 sid_frame_detection ( + Word16 ser2[] +); + +void update_lsf_history ( + Word16 lsf1[M], + Word16 lsf2[M], + Word16 lsf_old[DTX_HANGOVER][M] +); + +void update_lsf_p_CN ( + Word16 lsf_old[DTX_HANGOVER][M], + Word16 lsf_p_CN[M] +); + +void aver_lsf_history ( + Word16 lsf_old[DTX_HANGOVER][M], + Word16 lsf1[M], + Word16 lsf2[M], + Word16 lsf_aver[M] +); + +void update_gain_code_history_tx ( + Word16 new_gain_code, + Word16 gain_code_old_tx[4 * DTX_HANGOVER] +); + +void update_gain_code_history_rx ( + Word16 new_gain_code, + Word16 gain_code_old_rx[4 * DTX_HANGOVER] +); + +Word16 compute_CN_excitation_gain ( + Word16 res2[L_SUBFR] +); + +Word16 update_gcode0_CN ( + Word16 gain_code_old_tx[4 * DTX_HANGOVER] +); + +Word16 aver_gain_code_history ( + Word16 CN_excitation_gain, + Word16 gain_code_old[4 * DTX_HANGOVER] +); + +void build_CN_code ( + Word16 cod[], + Word32 *seed +); + +Word16 pseudonoise ( + Word32 *shift_reg, + Word16 no_bits +); + +Word16 interpolate_CN_param ( + Word16 old_param, + Word16 new_param, + Word16 rx_dtx_state +); + +void interpolate_CN_lsf ( + Word16 lsf_old_CN[M], + Word16 lsf_new_CN[M], + Word16 lsf_interp_CN[M], + Word16 rx_dtx_state +); diff -r 000000000000 -r 56410792419a src/e_homing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/e_homing.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,163 @@ +/************************************************************************** + * + * File Name: e_homing.c + * + * Purpose: + * This file contains the following functions: + * + * encoder_homing_frame_test() checks if a frame of input samples + * matches the Encoder Homing Frame pattern. + * + * encoder_reset() called by reset_enc() to reset all + * the state variables for the encoder. + * + * reset_enc() calls functions to reset the state + * variables for the encoder and VAD, and + * for the transmit DTX and Comfort Noise. + * + **************************************************************************/ + +#include "typedef.h" +#include "cnst.h" +#include "vad.h" +#include "dtx.h" +#include "codec.h" +#include "sig_proc.h" +#include "e_homing.h" + +/*************************************************************************** + * + * FUNCTION NAME: encoder_homing_frame_test + * + * PURPOSE: + * Checks if a frame of input samples matches the Encoder Homing Frame + * pattern, which is 0x0008 for all 160 samples in the frame. + * + * INPUT: + * input_frame[] one frame of speech samples + * + * OUTPUT: + * None + * + * RETURN: + * 0 input frame does not match the Encoder Homing Frame pattern. + * 1 input frame matches the Encoder Homing Frame pattern. + * + **************************************************************************/ + +Word16 encoder_homing_frame_test (Word16 input_frame[]) +{ + Word16 i, j; + + for (i = 0; i < L_FRAME; i++) + { + j = input_frame[i] ^ EHF_MASK; + + if (j) + break; + } + + return !j; +} + +/*************************************************************************** + * + * FUNCTION NAME: encoder_reset + * + * PURPOSE: + * resets all of the state variables for the encoder + * + * INPUT: + * None + * + * OUTPUT: + * None + * + * RETURN: + * None + * + **************************************************************************/ + +void encoder_reset (void) +{ + /* External declarations for encoder variables which need to be reset */ + + /* Variables defined in levinson.c */ + /* ------------------------------- */ + extern Word16 old_A[M + 1]; /* Last A(z) for case of unstable filter */ + + /* Variables defined in q_gains.c */ + /* ------------------------------- */ + /* Memories of gain quantization: */ + extern Word16 past_qua_en[4], pred[4]; + + /* Variables defined in q_plsf_5.c */ + /* ------------------------------- */ + /* Past quantized prediction error */ + extern Word16 past_r2_q[M]; + + Word16 i; + + /* reset all the encoder state variables */ + /* ------------------------------------- */ + + /* Variables in cod_12k2.c: */ + Init_Coder_12k2 (); + + /* Variables in levinson.c: */ + old_A[0] = 4096; /* Last A(z) for case of unstable filter */ + for (i = 1; i < M + 1; i++) + { + old_A[i] = 0; + } + + /* Variables in pre_proc.c: */ + Init_Pre_Process (); + + /* Variables in q_gains.c: */ + for (i = 0; i < 4; i++) + { + past_qua_en[i] = -2381; /* past quantized energies */ + } + + pred[0] = 44; /* MA prediction coeff */ + pred[1] = 37; /* MA prediction coeff */ + pred[2] = 22; /* MA prediction coeff */ + pred[3] = 12; /* MA prediction coeff */ + + /* Variables in q_plsf_5.c: */ + for (i = 0; i < M; i++) + { + past_r2_q[i] = 0; /* Past quantized prediction error */ + } + + return; +} + +/*************************************************************************** + * + * FUNCTION NAME: reset_enc + * + * PURPOSE: + * resets all of the state variables for the encoder and VAD, and for + * the transmit DTX and Comfort Noise. + * + * INPUT: + * None + * + * OUTPUT: + * None + * + * RETURN: + * None + * + **************************************************************************/ + +void reset_enc (void) +{ + encoder_reset (); /* reset all the state variables in the speech encoder*/ + vad_reset (); /* reset all the VAD state variables */ + reset_tx_dtx (); /* reset all the transmit DTX and CN variables */ + + return; +} diff -r 000000000000 -r 56410792419a src/e_homing.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/e_homing.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,18 @@ +/************************************************************************** + * + * File Name: e_homing.h + * + * Purpose: Contains the prototypes for all the functions of + * encoder homing. + * + **************************************************************************/ + +#define EHF_MASK 0x0008 /* Encoder Homing Frame pattern */ + +/* Function Prototypes */ + +Word16 encoder_homing_frame_test (Word16 input_frame[]); + +void encoder_reset (void); + +void reset_enc (void); diff -r 000000000000 -r 56410792419a src/ed_iface.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ed_iface.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,312 @@ +/*************************************************************************** + * + * File Name: ed_iface.c + * + * Purpose: Speech encoder/decoder interface device + * + * This program transforms the output file format of the GSM Enhanced + * Full Rate Encoder module consisting of: + * * 244 speech parameter bits (see GSM TS 06.60) + * * 1 voice activity flag VAD (see GSM TS 06.82) + * * 1 speech flag SP (see GSM TS 06.81) + * + * to the input file format of the GSM Enhanced Full Rate Decoder module + * requiring: + * * 1 channel condition flag BFI (see GSM TS 06.61, 05.05) + * * 244 speech parameter bits (see GSM TS 06.60) + * * 1 SID flag (2 bits) (see GSM TS 06.81, 05.05) + * * 1 time alignment flag TAF (see GSM TS 06.81) + * + * Between SID updates the speech parameters are replaced by random + * values simulating an interrupted transmission on the air interface + * + * Below is a listing of all the functions appearing in the file, + * with a short description of their purpose. + * + * Convert single frame from encoder output format to decoder + * input format: + * enc_dec_interface() + * Receive single encoder output parameter frame: + * encoder_interface() + * Send single decoder input parameter frame: + * decoder_interface() + * Open file for binary read or write: + * open_bin_file() + * Set the speech parameters to random values: + * random_parameters() + * + **************************************************************************/ + +/*************************************************************************** + * + * Include-Files + * + **************************************************************************/ + +#include +#include +#include +#include "typedef.h" +#include "cnst.h" +#include "dtx.h" + +#define OPEN_WB "wb" +#define OPEN_RB "rb" + +/*************************************************************************** + * + * Local function prototypes + * + **************************************************************************/ + +static Word16 enc_dec_interface (FILE *infile, FILE *outfile); +static Word16 encoder_interface (FILE *infile, Word16 serial_in_para[]); +static Word16 decoder_interface (Word16 serial_out_para[], FILE *outfile); +FILE *open_bin_file (char *name, char *mode); +static void random_parameters (Word16 serial_params[]); + +/*************************************************************************** + * + * Local functions + * + **************************************************************************/ + +static Word16 enc_dec_interface (FILE *infile, FILE *outfile) +{ + +#define SPEECH 1 +#define CNIFIRSTSID 2 +#define CNICONT 3 +#define VALIDSID 11 +#define GOODSPEECH 33 + + static Word16 decoding_mode = {SPEECH}; + static Word16 TAF_count = {1}; + Word16 serial_in_para[246], i, frame_type; + Word16 serial_out_para[247]; + + if (encoder_interface (infile, serial_in_para) != 0) + { + return (1); + } + + /* Copy input parameters to output parameters */ + /* ------------------------------------------ */ + for (i = 0; i < 244; i++) + { + serial_out_para[i+1] = serial_in_para[i]; + } + + /* Set channel status (BFI) flag to zero */ + /* --------------------------------------*/ + serial_out_para[0] = 0; /* BFI flag */ + + /* Evaluate SID flag */ + /* Function sid_frame_detection() is defined in dtx.c */ + /* -------------------------------------------------- */ + serial_out_para[245] = sid_frame_detection (&serial_out_para[1]); + + /* Evaluate TAF flag */ + /* ----------------- */ + if (TAF_count == 0) + { + serial_out_para[246] = 1; + } + else + { + serial_out_para[246] = 0; + } + + TAF_count = (TAF_count + 1) % 24; + + /* Frame classification: */ + /* Since the transmission is error free, the received frames are either */ + /* valid speech or valid SID frames */ + /* -------------------------------------------------------------------- */ + if (serial_out_para[245] == 2) + { + frame_type = VALIDSID; + } + else if (serial_out_para[245] == 0) + { + frame_type = GOODSPEECH; + } + else { + fprintf (stderr, "Error in SID detection\n"); + return (1); + } + + /* Update of decoder state */ + /* ----------------------- */ + if (decoding_mode == SPEECH) /* State of previous frame */ + { + if (frame_type == VALIDSID) + { + decoding_mode = CNIFIRSTSID; + } + else if (frame_type == GOODSPEECH) + { + decoding_mode = SPEECH; + } + } + else /* comfort noise insertion mode */ + { + if (frame_type == VALIDSID) + { + decoding_mode = CNICONT; + } + else if (frame_type == GOODSPEECH) + { + decoding_mode = SPEECH; + } + } + + /* Replace parameters by random data if in CNICONT-mode and TAF=0 */ + /* -------------------------------------------------------------- */ + if ((decoding_mode == CNICONT) && (serial_out_para[246] == 0)) + { + random_parameters (&serial_out_para[1]); + + /* Set flags such that an "unusable frame" is produced */ + serial_out_para[0] = 1; /* BFI flag */ + serial_out_para[245] = 0; /* SID flag */ + } + + if (decoder_interface (serial_out_para, outfile) != 0) + { + fprintf (stderr, "Error writing File\n"); + return (1); + } + + return (0); +} + +static Word16 encoder_interface (FILE *infile, Word16 serial_in_para[]) +{ + size_t lgth_read = 0; + Word16 ret; + + lgth_read = fread (serial_in_para, sizeof (Word16), 246, infile); + + if (lgth_read == 0) + { + ret = 1; + } + else + { + ret = 0; + } + + return (ret); +} + +static Word16 decoder_interface (Word16 serial_out_file[], FILE *outfile) +{ + size_t lgth_written; + Word16 ret; + + lgth_written = fwrite (serial_out_file, sizeof (Word16), 247, outfile); + + if (lgth_written == 247) + { + ret = 0; + } + else + { + ret = 1; + } + + return (ret); +} + +FILE *open_bin_file (char *name, char *mode) +{ + FILE *fp; + + if (toupper (*mode) == 'W') /* Write access */ + { + if ((fp = fopen (name, OPEN_WB)) == NULL) + { + fprintf (stderr, "Can't open output file '%s'\n", name); + exit (1); + } + } + else /* Read access */ + { + if ((fp = fopen (name, OPEN_RB)) == NULL) + { + fprintf (stderr, "Can't open file '%s'\n", name); + exit (1); + } + } + + return (fp); +} + +static void random_parameters (Word16 serial_params[]) +{ + static Word32 L_PN_seed = 0x321CEDE2L; + Word16 i; + + /* Set the 244 speech parameter bits to random bit values */ + /* Function pseudonoise() is defined in dtx.c */ + /*--------------------------------------------------------*/ + + for (i = 0; i < 244; i++) + { + serial_params[i] = pseudonoise (&L_PN_seed, 1); + } + + return; +} + +/**************************************************************************** + * + * Main program of the encoder/decoder interface device + * + ***************************************************************************/ + +int main (int argc, char *argv[]) +{ + FILE *infile, *outfile; + Word16 i; + + if (argc != 3) + { + fprintf (stderr, "\n Usage:\n\n ed_iface input output\n\n"); + return (1); + } + + fprintf (stderr, " ____________________________________________________\n"); + fprintf (stderr, " | |\n"); + fprintf (stderr, " | Speech Encoder-Decoder Interface Device |\n"); + fprintf (stderr, " | |\n"); + fprintf (stderr, " | for |\n"); + fprintf (stderr, " | |\n"); + fprintf (stderr, " | GSM Enhanced Full Rate Speech Codec Simulation |\n"); + fprintf (stderr, " |____________________________________________________|\n\n"); + + fprintf (stderr, " Input File : %s\n", argv[1]); + fprintf (stderr, " Output File : %s\n\n", argv[2]); + + infile = open_bin_file (argv[1], "r"); + outfile = open_bin_file (argv[2], "w"); + + i = 0; + while (enc_dec_interface (infile, outfile) == 0) + { + if ((i % 50) == 0) + { + fprintf (stderr, "\r %d", i); + } + i++; + } + fprintf (stderr, "\r %d", i); + + fclose (infile); + fclose (outfile); + + fprintf (stderr, " Frame%s processed \n\n", ( i != 1 ) ? "s" : ""); + + return (0); +} diff -r 000000000000 -r 56410792419a src/enc_lag6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/enc_lag6.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,97 @@ +/************************************************************************* + * + * FUNCTION: Enc_lag6 + * + * PURPOSE: Encoding of fractional pitch lag with 1/6 resolution. + * + * DESCRIPTION: + * First and third subframes: + * -------------------------- + * The pitch range is divided as follows: + * 17 3/6 to 94 3/6 resolution 1/6 + * 95 to 143 resolution 1 + * + * The period is encoded with 9 bits. + * For the range with fractions: + * index = (T-17)*6 + frac - 3; + * where T=[17..94] and frac=[-2,-1,0,1,2,3] + * and for the integer only range + * index = (T - 95) + 463; where T=[95..143] + * + * Second and fourth subframes: + * ---------------------------- + * For the 2nd and 4th subframes a resolution of 1/6 is always used, + * and the search range is relative to the lag in previous subframe. + * If t0 is the lag in the previous subframe then + * t_min=t0-5 and t_max=t0+4 and the range is given by + * (t_min-1) 3/6 to (t_max) 3/6 + * + * The period in the 2nd (and 4th) subframe is encoded with 6 bits: + * index = (T-(t_min-1))*6 + frac - 3; + * where T=[t_min-1..t_max] and frac=[-2,-1,0,1,2,3] + * + * Note that only 61 values are used. If the decoder receives 61, 62, + * or 63 as the relative pitch index, it means that a transmission + * error occurred and the pitch from previous subframe should be used. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +Word16 Enc_lag6 ( /* output: Return index of encoding */ + Word16 T0, /* input : Pitch delay */ + Word16 *T0_frac, /* in/out: Fractional pitch delay */ + Word16 *T0_min, /* in/out: Minimum search delay */ + Word16 *T0_max, /* in/out: Maximum search delay */ + Word16 pit_min, /* input : Minimum pitch delay */ + Word16 pit_max, /* input : Maximum pitch delay */ + Word16 pit_flag /* input : Flag for 1st or 3rd subframe */ +) +{ + Word16 index, i; + + test (); + if (pit_flag == 0) /* if 1st or 3rd subframe */ + { + /* encode pitch delay (with fraction) */ + + test (); + if (sub (T0, 94) <= 0) + { + /* index = T0*6 - 105 + *T0_frac */ + i = add (add (T0, T0), T0); + index = add (sub (add (i, i), 105), *T0_frac); + } else + { /* set fraction to 0 for delays > 94 */ + *T0_frac = 0; move16 (); + index = add (T0, 368); + } + + /* find T0_min and T0_max for second (or fourth) subframe */ + + *T0_min = sub (T0, 5); move16 (); + test (); + if (sub (*T0_min, pit_min) < 0) + { + *T0_min = pit_min; move16 (); + } + *T0_max = add (*T0_min, 9); + test (); + if (sub (*T0_max, pit_max) > 0) + { + *T0_max = pit_max; move16 (); + *T0_min = sub (*T0_max, 9); move16 (); + } + } else + /* if second or fourth subframe */ + { + /* index = 6*(T0-*T0_min) + 3 + *T0_frac */ + i = sub (T0, *T0_min); + i = add (add (i, i), i); + index = add (add (add (i, i), 3), *T0_frac); + } + + return index; +} diff -r 000000000000 -r 56410792419a src/g_code.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g_code.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,77 @@ +/************************************************************************* + * + * FUNCTION: G_code + * + * PURPOSE: Compute the innovative codebook gain. + * + * DESCRIPTION: + * The innovative codebook gain is given by + * + * g = / + * + * where x[] is the target vector, y[] is the filtered innovative + * codevector, and <> denotes dot product. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" +#include "cnst.h" + +Word16 G_code ( /* out : Gain of innovation code */ + Word16 xn2[], /* in : target vector */ + Word16 y2[] /* in : filtered innovation vector */ +) +{ + Word16 i; + Word16 xy, yy, exp_xy, exp_yy, gain; + Word16 scal_y2[L_SUBFR]; + Word32 s; + + /* Scale down Y[] by 2 to avoid overflow */ + + for (i = 0; i < L_SUBFR; i++) + { + scal_y2[i] = shr (y2[i], 1); move16 (); + } + + /* Compute scalar product */ + + s = 1L; move32 (); /* Avoid case of all zeros */ + for (i = 0; i < L_SUBFR; i++) + { + s = L_mac (s, xn2[i], scal_y2[i]); + } + exp_xy = norm_l (s); + xy = extract_h (L_shl (s, exp_xy)); + + /* If (xy < 0) gain = 0 */ + + test (); + if (xy <= 0) + return ((Word16) 0); + + /* Compute scalar product */ + + s = 0L; move32 (); + for (i = 0; i < L_SUBFR; i++) + { + s = L_mac (s, scal_y2[i], scal_y2[i]); + } + exp_yy = norm_l (s); + yy = extract_h (L_shl (s, exp_yy)); + + /* compute gain = xy/yy */ + + xy = shr (xy, 1); /* Be sure xy < yy */ + gain = div_s (xy, yy); + + /* Denormalization of division */ + i = add (exp_xy, 5); /* 15-1+9-18 = 5 */ + i = sub (i, exp_yy); + + gain = shr (gain, i); + + return (gain); +} diff -r 000000000000 -r 56410792419a src/g_pitch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g_pitch.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,128 @@ +/************************************************************************* + * + * FUNCTION: G_pitch + * + * PURPOSE: Compute the pitch (adaptive codebook) gain. Result in Q12 + * + * DESCRIPTION: + * The adaptive codebook gain is given by + * + * g = / + * + * where x[] is the target vector, y[] is the filtered adaptive + * codevector, and <> denotes dot product. + * The gain is limited to the range [0,1.2] + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "sig_proc.h" + +Word16 G_pitch ( /* (o) : Gain of pitch lag saturated to 1.2 */ + Word16 xn[], /* (i) : Pitch target. */ + Word16 y1[], /* (i) : Filtered adaptive codebook. */ + Word16 L_subfr /* : Length of subframe. */ +) +{ + Word16 i; + Word16 xy, yy, exp_xy, exp_yy, gain; + Word32 s; + + Word16 scaled_y1[80]; /* Usually dynamic allocation of (L_subfr) */ + + /* divide by 2 "y1[]" to avoid overflow */ + + for (i = 0; i < L_subfr; i++) + { + scaled_y1[i] = shr (y1[i], 2); move16 (); + } + + /* Compute scalar product */ + + s = 0L; move32 (); /* Avoid case of all zeros */ + for (i = 0; i < L_subfr; i++) + { + s = L_mac (s, y1[i], y1[i]); + } + test (); + if (L_sub (s, MAX_32) != 0L) /* Test for overflow */ + { + s = L_add (s, 1L); /* Avoid case of all zeros */ + exp_yy = norm_l (s); + yy = round (L_shl (s, exp_yy)); + } + else + { + s = 1L; move32 (); /* Avoid case of all zeros */ + for (i = 0; i < L_subfr; i++) + { + s = L_mac (s, scaled_y1[i], scaled_y1[i]); + } + exp_yy = norm_l (s); + yy = round (L_shl (s, exp_yy)); + exp_yy = sub (exp_yy, 4); + } + + /* Compute scalar product */ + + Overflow = 0; move16 (); + s = 1L; move32 (); /* Avoid case of all zeros */ + for (i = 0; i < L_subfr; i++) + { + Carry = 0; move16 (); + s = L_macNs (s, xn[i], y1[i]); + + test (); + if (Overflow != 0) + { + break; + } + } + test (); + if (Overflow == 0) + { + exp_xy = norm_l (s); + xy = round (L_shl (s, exp_xy)); + } + else + { + s = 1L; move32 (); /* Avoid case of all zeros */ + for (i = 0; i < L_subfr; i++) + { + s = L_mac (s, xn[i], scaled_y1[i]); + } + exp_xy = norm_l (s); + xy = round (L_shl (s, exp_xy)); + exp_xy = sub (exp_xy, 2); + } + + /* If (xy < 4) gain = 0 */ + + i = sub (xy, 4); + + test (); + if (i < 0) + return ((Word16) 0); + + /* compute gain = xy/yy */ + + xy = shr (xy, 1); /* Be sure xy < yy */ + gain = div_s (xy, yy); + + i = add (exp_xy, 3 - 1); /* Denormalization of division */ + i = sub (i, exp_yy); + + gain = shr (gain, i); + + /* if(gain >1.2) gain = 1.2 */ + + test (); + if (sub (gain, 4915) > 0) + { + gain = 4915; move16 (); + } + return (gain); +} diff -r 000000000000 -r 56410792419a src/gains_tb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gains_tb.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,21 @@ +/*-----------------------------------------------------------------------* + * Scalar quantization tables of the pitch gain and the codebook gain. * + *-----------------------------------------------------------------------*/ + +#define NB_QUA_PITCH 16 + +static const Word16 qua_gain_pitch[NB_QUA_PITCH] = +{ + 0, 3277, 6556, 8192, 9830, 11469, 12288, 13107, + 13926, 14746, 15565, 16384, 17203, 18022, 18842, 19661 +}; + +#define NB_QUA_CODE 32 + +static const Word16 qua_gain_code[NB_QUA_CODE] = +{ + 159, 206, 268, 349, 419, 482, 554, 637, + 733, 842, 969, 1114, 1281, 1473, 1694, 1948, + 2241, 2577, 2963, 3408, 3919, 4507, 5183, 5960, + 6855, 7883, 9065, 10425, 12510, 16263, 21142, 27485 +}; diff -r 000000000000 -r 56410792419a src/grid.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/grid.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,26 @@ +/*-------------------------------------------------------------* + * Table for az_lsf() * + * * + * grid[0] = 1.0; * + * grid[grid_points+1] = -1.0; * + * for (i = 1; i < grid_points; i++) * + * grid[i] = cos((6.283185307*i)/(2.0*grid_points)); * + * * + *-------------------------------------------------------------*/ + +#define grid_points 60 + +static const Word16 grid[grid_points + 1] = +{ + 32760, 32723, 32588, 32364, 32051, 31651, + 31164, 30591, 29935, 29196, 28377, 27481, + 26509, 25465, 24351, 23170, 21926, 20621, + 19260, 17846, 16384, 14876, 13327, 11743, + 10125, 8480, 6812, 5126, 3425, 1714, + 0, -1714, -3425, -5126, -6812, -8480, + -10125, -11743, -13327, -14876, -16384, -17846, + -19260, -20621, -21926, -23170, -24351, -25465, + -26509, -27481, -28377, -29196, -29935, -30591, + -31164, -31651, -32051, -32364, -32588, -32723, + -32760 +}; diff -r 000000000000 -r 56410792419a src/int_lpc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/int_lpc.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,112 @@ +/************************************************************************* + * + * FUNCTION: Int_lpc() + * + * PURPOSE: Interpolates the LSPs and converts to LPC parameters to get + * a different LP filter in each subframe. + * + * DESCRIPTION: + * The 20 ms speech frame is divided into 4 subframes. + * The LSPs are quantized and transmitted at the 2nd and 4th subframes + * (twice per frame) and interpolated at the 1st and 3rd subframe. + * + * |------|------|------|------| + * sf1 sf2 sf3 sf4 + * F0 Fm F1 + * + * sf1: 1/2 Fm + 1/2 F0 sf3: 1/2 F1 + 1/2 Fm + * sf2: Fm sf4: F1 + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" +#include "sig_proc.h" + +#define M 10 /* LP order */ +#define MP1 11 /* M+1 */ + +void Int_lpc ( + Word16 lsp_old[], /* input : LSP vector at the 4th subframe + of past frame */ + Word16 lsp_mid[], /* input : LSP vector at the 2nd subframe + of present frame */ + Word16 lsp_new[], /* input : LSP vector at the 4th subframe of + present frame */ + Word16 Az[] /* output: interpolated LP parameters in + all subframes */ +) +{ + Word16 i; + Word16 lsp[M]; + + /* lsp[i] = lsp_mid[i] * 0.5 + lsp_old[i] * 0.5 */ + + for (i = 0; i < M; i++) + { + lsp[i] = add (shr (lsp_mid[i], 1), shr (lsp_old[i], 1)); + move16 (); + } + + Lsp_Az (lsp, Az); /* Subframe 1 */ + Az += MP1; move16 (); + + Lsp_Az (lsp_mid, Az); /* Subframe 2 */ + Az += MP1; move16 (); + + for (i = 0; i < M; i++) + { + lsp[i] = add (shr (lsp_mid[i], 1), shr (lsp_new[i], 1)); + move16 (); + } + + Lsp_Az (lsp, Az); /* Subframe 3 */ + Az += MP1; move16 (); + + Lsp_Az (lsp_new, Az); /* Subframe 4 */ + + return; +} + +/*----------------------------------------------------------------------* + * Function Int_lpc2() * + * ~~~~~~~~~~~~~~~~~~ * + * Interpolation of the LPC parameters. * + * Same as the previous function but we do not recompute Az() for * + * subframe 2 and 4 because it is already available. * + *----------------------------------------------------------------------*/ + +void Int_lpc2 ( + Word16 lsp_old[], /* input : LSP vector at the 4th subframe + of past frame */ + Word16 lsp_mid[], /* input : LSP vector at the 2nd subframe + of present frame */ + Word16 lsp_new[], /* input : LSP vector at the 4th subframe of + present frame */ + Word16 Az[] /* output: interpolated LP parameters + in subframes 1 and 3 */ +) +{ + Word16 i; + Word16 lsp[M]; + + /* lsp[i] = lsp_mid[i] * 0.5 + lsp_old[i] * 0.5 */ + + for (i = 0; i < M; i++) + { + lsp[i] = add (shr (lsp_mid[i], 1), shr (lsp_old[i], 1)); + move16 (); + } + Lsp_Az (lsp, Az); /* Subframe 1 */ + Az += MP1 * 2; move16 (); + + for (i = 0; i < M; i++) + { + lsp[i] = add (shr (lsp_mid[i], 1), shr (lsp_new[i], 1)); + move16 (); + } + Lsp_Az (lsp, Az); /* Subframe 3 */ + + return; +} diff -r 000000000000 -r 56410792419a src/inter_6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/inter_6.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,57 @@ +/************************************************************************* + * + * FUNCTION: Interpol_6() + * + * PURPOSE: Interpolating the normalized correlation with 1/6 resolution. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +#define UP_SAMP 6 +#define L_INTERPOL 4 +#define FIR_SIZE (UP_SAMP*L_INTERPOL+1) + +/* 1/6 resolution interpolation filter (-3 dB at 3600 Hz) */ + +static const Word16 inter_6[FIR_SIZE] = +{ + 29519, + 28316, 24906, 19838, 13896, 7945, 2755, + -1127, -3459, -4304, -3969, -2899, -1561, + -336, 534, 970, 1023, 823, 516, + 220, 0, -131, -194, -215, 0 +}; + +Word16 Interpol_6 ( /* (o) : interpolated value */ + Word16 *x, /* (i) : input vector */ + Word16 frac /* (i) : fraction */ +) +{ + Word16 i, k; + Word16 *x1, *x2; + const Word16 *c1, *c2; + Word32 s; + + test (); + if (frac < 0) + { + frac = add (frac, UP_SAMP); + x--; + } + x1 = &x[0]; move16 (); + x2 = &x[1]; move16 (); + c1 = &inter_6[frac]; move16 (); + c2 = &inter_6[sub (UP_SAMP, frac)]; move16 (); + + s = 0; move32 (); + for (i = 0, k = 0; i < L_INTERPOL; i++, k += UP_SAMP) + { + s = L_mac (s, x1[-i], c1[k]); + s = L_mac (s, x2[i], c2[k]); + } + + return round (s); +} diff -r 000000000000 -r 56410792419a src/inv_sqrt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/inv_sqrt.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,67 @@ +/************************************************************************* + * + * FUNCTION: Inv_sqrt + * + * PURPOSE: Computes 1/sqrt(L_x), where L_x is positive. + * If L_x is negative or zero, the result is 1 (3fff ffff). + * + * DESCRIPTION: + * The function 1/sqrt(L_x) is approximated by a table and linear + * interpolation. The inverse square root is computed using the + * following steps: + * 1- Normalization of L_x. + * 2- If (30-exponent) is even then shift right once. + * 3- exponent = (30-exponent)/2 +1 + * 4- i = bit25-b31 of L_x; 16<=i<=63 because of normalization. + * 5- a = bit10-b24 + * 6- i -=16 + * 7- L_y = table[i]<<16 - (table[i] - table[i+1]) * a * 2 + * 8- L_y >>= exponent + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +#include "inv_sqrt.tab" /* Table for inv_sqrt() */ + +Word32 Inv_sqrt ( /* (o) : output value */ + Word32 L_x /* (i) : input value */ +) +{ + Word16 exp, i, a, tmp; + Word32 L_y; + + test (); + if (L_x <= (Word32) 0) + return ((Word32) 0x3fffffffL); + + exp = norm_l (L_x); + L_x = L_shl (L_x, exp); /* L_x is normalize */ + + exp = sub (30, exp); + test (); logic16 (); + if ((exp & 1) == 0) /* If exponent even -> shift right */ + { + L_x = L_shr (L_x, 1); + } + exp = shr (exp, 1); + exp = add (exp, 1); + + L_x = L_shr (L_x, 9); + i = extract_h (L_x); /* Extract b25-b31 */ + L_x = L_shr (L_x, 1); + a = extract_l (L_x); /* Extract b10-b24 */ + a = a & (Word16) 0x7fff; logic16 (); + + i = sub (i, 16); + + L_y = L_deposit_h (table[i]); /* table[i] << 16 */ + tmp = sub (table[i], table[i + 1]); /* table[i] - table[i+1]) */ + L_y = L_msu (L_y, tmp, a); /* L_y -= tmp*a*2 */ + + L_y = L_shr (L_y, exp); /* denormalization */ + + return (L_y); +} diff -r 000000000000 -r 56410792419a src/inv_sqrt.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/inv_sqrt.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,13 @@ +/*-----------------------------------------------------* + | Table for routine Inv_sqrt(). | + -----------------------------------------------------*/ + +static const Word16 table[49] = +{ + + 32767, 31790, 30894, 30070, 29309, 28602, 27945, 27330, 26755, 26214, + 25705, 25225, 24770, 24339, 23930, 23541, 23170, 22817, 22479, 22155, + 21845, 21548, 21263, 20988, 20724, 20470, 20225, 19988, 19760, 19539, + 19326, 19119, 18919, 18725, 18536, 18354, 18176, 18004, 17837, 17674, + 17515, 17361, 17211, 17064, 16921, 16782, 16646, 16514, 16384 +}; diff -r 000000000000 -r 56410792419a src/lag_wind.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lag_wind.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,37 @@ +/************************************************************************* + * + * FUNCTION: Lag_window() + * + * PURPOSE: Lag windowing of autocorrelations. + * + * DESCRIPTION: + * r[i] = r[i]*lag_wind[i], i=1,...,10 + * + * r[i] and lag_wind[i] are in special double precision format. + * See "oper_32b.c" for the format. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" + +#include "lag_wind.tab" + +void Lag_window ( + Word16 m, /* (i) : LPC order */ + Word16 r_h[], /* (i/o) : Autocorrelations (msb) */ + Word16 r_l[] /* (i/o) : Autocorrelations (lsb) */ +) +{ + Word16 i; + Word32 x; + + for (i = 1; i <= m; i++) + { + x = Mpy_32 (r_h[i], r_l[i], lag_h[i - 1], lag_l[i - 1]); + L_Extract (x, &r_h[i], &r_l[i]); + } + return; +} diff -r 000000000000 -r 56410792419a src/lag_wind.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lag_wind.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,46 @@ +/*-----------------------------------------------------* + | Table of lag_window for autocorrelation. | + | noise floor = 1.0001 = (0.9999 on r[1] ..r[10]) | + | Bandwitdh expansion = 60 Hz | + | | + | | + | lag_wind[0] = 1.00000000 (not stored) | + | lag_wind[1] = 0.99879038 | + | lag_wind[2] = 0.99546897 | + | lag_wind[3] = 0.98995781 | + | lag_wind[4] = 0.98229337 | + | lag_wind[5] = 0.97252619 | + | lag_wind[6] = 0.96072036 | + | lag_wind[7] = 0.94695264 | + | lag_wind[8] = 0.93131179 | + | lag_wind[9] = 0.91389757 | + | lag_wind[10]= 0.89481968 | + -----------------------------------------------------*/ + +static const Word16 lag_h[10] = +{ + 32728, + 32619, + 32438, + 32187, + 31867, + 31480, + 31029, + 30517, + 29946, + 29321 +}; + +static const Word16 lag_l[10] = +{ + 11904, + 17280, + 30720, + 25856, + 24192, + 28992, + 24384, + 7360, + 19520, + 14784 +}; diff -r 000000000000 -r 56410792419a src/levinson.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/levinson.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,194 @@ +/************************************************************************* + * + * FUNCTION: Levinson() + * + * PURPOSE: Levinson-Durbin algorithm in double precision. To compute the + * LP filter parameters from the speech autocorrelations. + * + * DESCRIPTION: + * R[i] autocorrelations. + * A[i] filter coefficients. + * K reflection coefficients. + * Alpha prediction gain. + * + * Initialisation: + * A[0] = 1 + * K = -R[1]/R[0] + * A[1] = K + * Alpha = R[0] * (1-K**2] + * + * Do for i = 2 to M + * + * S = SUM ( R[j]*A[i-j] ,j=1,i-1 ) + R[i] + * + * K = -S / Alpha + * + * An[j] = A[j] + K*A[i-j] for j=1 to i-1 + * where An[i] = new A[i] + * An[i]=K + * + * Alpha=Alpha * (1-K**2) + * + * END + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" + +/* Lpc order == 10 */ + +#define M 10 + +/* Last A(z) for case of unstable filter */ + +Word16 old_A[M + 1]; + +void Levinson ( + Word16 Rh[], /* (i) : Rh[m+1] Vector of autocorrelations (msb) */ + Word16 Rl[], /* (i) : Rl[m+1] Vector of autocorrelations (lsb) */ + Word16 A[], /* (o) : A[m] LPC coefficients (m = 10) */ + Word16 rc[] /* (o) : rc[4] First 4 reflection coefficients */ + +) +{ + Word16 i, j; + Word16 hi, lo; + Word16 Kh, Kl; /* reflexion coefficient; hi and lo */ + Word16 alp_h, alp_l, alp_exp; /* Prediction gain; hi lo and exponent */ + Word16 Ah[M + 1], Al[M + 1]; /* LPC coef. in double prec. */ + Word16 Anh[M + 1], Anl[M + 1];/* LPC coef.for next iteration in double + prec. */ + Word32 t0, t1, t2; /* temporary variable */ + + /* K = A[1] = -R[1] / R[0] */ + + t1 = L_Comp (Rh[1], Rl[1]); + t2 = L_abs (t1); /* abs R[1] */ + t0 = Div_32 (t2, Rh[0], Rl[0]); /* R[1]/R[0] */ + test (); + if (t1 > 0) + t0 = L_negate (t0); /* -R[1]/R[0] */ + L_Extract (t0, &Kh, &Kl); /* K in DPF */ + + rc[0] = round (t0); move16 (); + + t0 = L_shr (t0, 4); /* A[1] in */ + L_Extract (t0, &Ah[1], &Al[1]); /* A[1] in DPF */ + + /* Alpha = R[0] * (1-K**2) */ + + t0 = Mpy_32 (Kh, Kl, Kh, Kl); /* K*K */ + t0 = L_abs (t0); /* Some case <0 !! */ + t0 = L_sub ((Word32) 0x7fffffffL, t0); /* 1 - K*K */ + L_Extract (t0, &hi, &lo); /* DPF format */ + t0 = Mpy_32 (Rh[0], Rl[0], hi, lo); /* Alpha in */ + + /* Normalize Alpha */ + + alp_exp = norm_l (t0); + t0 = L_shl (t0, alp_exp); + L_Extract (t0, &alp_h, &alp_l); /* DPF format */ + + /*--------------------------------------* + * ITERATIONS I=2 to M * + *--------------------------------------*/ + + for (i = 2; i <= M; i++) + { + /* t0 = SUM ( R[j]*A[i-j] ,j=1,i-1 ) + R[i] */ + + t0 = 0; move32 (); + for (j = 1; j < i; j++) + { + t0 = L_add (t0, Mpy_32 (Rh[j], Rl[j], Ah[i - j], Al[i - j])); + } + t0 = L_shl (t0, 4); + + t1 = L_Comp (Rh[i], Rl[i]); + t0 = L_add (t0, t1); /* add R[i] */ + + /* K = -t0 / Alpha */ + + t1 = L_abs (t0); + t2 = Div_32 (t1, alp_h, alp_l); /* abs(t0)/Alpha */ + test (); + if (t0 > 0) + t2 = L_negate (t2); /* K =-t0/Alpha */ + t2 = L_shl (t2, alp_exp); /* denormalize; compare to Alpha */ + L_Extract (t2, &Kh, &Kl); /* K in DPF */ + + test (); + if (sub (i, 5) < 0) + { + rc[i - 1] = round (t2); move16 (); + } + /* Test for unstable filter. If unstable keep old A(z) */ + + test (); + if (sub (abs_s (Kh), 32750) > 0) + { + for (j = 0; j <= M; j++) + { + A[j] = old_A[j]; move16 (); + } + + for (j = 0; j < 4; j++) + { + rc[j] = 0; move16 (); + } + + return; + } + /*------------------------------------------* + * Compute new LPC coeff. -> An[i] * + * An[j]= A[j] + K*A[i-j] , j=1 to i-1 * + * An[i]= K * + *------------------------------------------*/ + + for (j = 1; j < i; j++) + { + t0 = Mpy_32 (Kh, Kl, Ah[i - j], Al[i - j]); + t0 = L_mac (t0, Ah[j], 32767); + t0 = L_mac (t0, Al[j], 1); + L_Extract (t0, &Anh[j], &Anl[j]); + } + t2 = L_shr (t2, 4); + L_Extract (t2, &Anh[i], &Anl[i]); + + /* Alpha = Alpha * (1-K**2) */ + + t0 = Mpy_32 (Kh, Kl, Kh, Kl); /* K*K */ + t0 = L_abs (t0); /* Some case <0 !! */ + t0 = L_sub ((Word32) 0x7fffffffL, t0); /* 1 - K*K */ + L_Extract (t0, &hi, &lo); /* DPF format */ + t0 = Mpy_32 (alp_h, alp_l, hi, lo); + + /* Normalize Alpha */ + + j = norm_l (t0); + t0 = L_shl (t0, j); + L_Extract (t0, &alp_h, &alp_l); /* DPF format */ + alp_exp = add (alp_exp, j); /* Add normalization to + alp_exp */ + + /* A[j] = An[j] */ + + for (j = 1; j <= i; j++) + { + Ah[j] = Anh[j]; move16 (); + Al[j] = Anl[j]; move16 (); + } + } + + A[0] = 4096; move16 (); + for (i = 1; i <= M; i++) + { + t0 = L_Comp (Ah[i], Al[i]); + old_A[i] = A[i] = round (L_shl (t0, 1));move16 (); move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/log2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/log2.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,63 @@ +/************************************************************************* + * + * FUNCTION: Log2() + * + * PURPOSE: Computes log2(L_x), where L_x is positive. + * If L_x is negative or zero, the result is 0. + * + * DESCRIPTION: + * The function Log2(L_x) is approximated by a table and linear + * interpolation. The following steps are used to compute Log2(L_x) + * + * 1- Normalization of L_x. + * 2- exponent = 30-exponent + * 3- i = bit25-b31 of L_x; 32<=i<=63 (because of normalization). + * 4- a = bit10-b24 + * 5- i -=32 + * 6- fraction = table[i]<<16 - (table[i] - table[i+1]) * a * 2 + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +#include "log2.tab" /* Table for Log2() */ + +void Log2 ( + Word32 L_x, /* (i) : input value */ + Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */ + Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1) */ +) +{ + Word16 exp, i, a, tmp; + Word32 L_y; + + test (); + if (L_x <= (Word32) 0) + { + *exponent = 0; move16 (); + *fraction = 0; move16 (); + return; + } + exp = norm_l (L_x); + L_x = L_shl (L_x, exp); /* L_x is normalized */ + + *exponent = sub (30, exp); move16 (); + + L_x = L_shr (L_x, 9); + i = extract_h (L_x); /* Extract b25-b31 */ + L_x = L_shr (L_x, 1); + a = extract_l (L_x); /* Extract b10-b24 of fraction */ + a = a & (Word16) 0x7fff; logic16 (); + + i = sub (i, 32); + + L_y = L_deposit_h (table[i]); /* table[i] << 16 */ + tmp = sub (table[i], table[i + 1]); /* table[i] - table[i+1] */ + L_y = L_msu (L_y, tmp, a); /* L_y -= tmp*a*2 */ + + *fraction = extract_h (L_y);move16 (); + + return; +} diff -r 000000000000 -r 56410792419a src/log2.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/log2.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,11 @@ +/*-----------------------------------------------------* + | Table for routine Log2(). | + -----------------------------------------------------*/ + +static const Word16 table[33] = +{ + 0, 1455, 2866, 4236, 5568, 6863, 8124, 9352, 10549, 11716, + 12855, 13967, 15054, 16117, 17156, 18172, 19167, 20142, 21097, 22033, + 22951, 23852, 24735, 25603, 26455, 27291, 28113, 28922, 29716, 30497, + 31266, 32023, 32767 +}; diff -r 000000000000 -r 56410792419a src/lsp_az.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lsp_az.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,117 @@ +/************************************************************************* + * + * FUNCTION: Lsp_Az + * + * PURPOSE: Converts from the line spectral pairs (LSP) to + * LP coefficients, for a 10th order filter. + * + * DESCRIPTION: + * - Find the coefficients of F1(z) and F2(z) (see Get_lsp_pol) + * - Multiply F1(z) by 1+z^{-1} and F2(z) by 1-z^{-1} + * - A(z) = ( F1(z) + F2(z) ) / 2 + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "sig_proc.h" + +/* local function */ + +static void Get_lsp_pol (Word16 *lsp, Word32 *f); + +void Lsp_Az ( + Word16 lsp[], /* (i) : line spectral frequencies */ + Word16 a[] /* (o) : predictor coefficients (order = 10) */ +) +{ + Word16 i, j; + Word32 f1[6], f2[6]; + Word32 t0; + + Get_lsp_pol (&lsp[0], f1); + Get_lsp_pol (&lsp[1], f2); + + for (i = 5; i > 0; i--) + { + f1[i] = L_add (f1[i], f1[i - 1]); move32 (); /* f1[i] += f1[i-1]; */ + f2[i] = L_sub (f2[i], f2[i - 1]); move32 (); /* f2[i] -= f2[i-1]; */ + } + + a[0] = 4096; move16 (); + for (i = 1, j = 10; i <= 5; i++, j--) + { + t0 = L_add (f1[i], f2[i]); /* f1[i] + f2[i] */ + a[i] = extract_l (L_shr_r (t0, 13)); move16 (); + t0 = L_sub (f1[i], f2[i]); /* f1[i] - f2[i] */ + a[j] = extract_l (L_shr_r (t0, 13)); move16 (); + } + + return; +} + +/************************************************************************* + * + * FUNCTION: Get_lsp_pol + * + * PURPOSE: Find the polynomial F1(z) or F2(z) from the LSPs. + * If the LSP vector is passed at address 0 F1(z) is computed + * and if it is passed at address 1 F2(z) is computed. + * + * DESCRIPTION: + * This is performed by expanding the product polynomials: + * + * F1(z) = product ( 1 - 2 lsp[i] z^-1 + z^-2 ) + * i=0,2,4,6,8 + * F2(z) = product ( 1 - 2 lsp[i] z^-1 + z^-2 ) + * i=1,3,5,7,9 + * + * where lsp[] is the LSP vector in the cosine domain. + * + * The expansion is performed using the following recursion: + * + * f[0] = 1 + * b = -2.0 * lsp[0] + * f[1] = b + * for i=2 to 5 do + * b = -2.0 * lsp[2*i-2]; + * f[i] = b*f[i-1] + 2.0*f[i-2]; + * for j=i-1 down to 2 do + * f[j] = f[j] + b*f[j-1] + f[j-2]; + * f[1] = f[1] + b; + * + *************************************************************************/ + +static void Get_lsp_pol (Word16 *lsp, Word32 *f) +{ + Word16 i, j, hi, lo; + Word32 t0; + + /* f[0] = 1.0; */ + *f = L_mult (4096, 2048); move32 (); + f++; move32 (); + *f = L_msu ((Word32) 0, *lsp, 512); /* f[1] = -2.0 * lsp[0]; */ + f++; move32 (); + lsp += 2; /* Advance lsp pointer */ + + for (i = 2; i <= 5; i++) + { + *f = f[-2]; move32 (); + + for (j = 1; j < i; j++, f--) + { + L_Extract (f[-1], &hi, &lo); + t0 = Mpy_32_16 (hi, lo, *lsp); /* t0 = f[-1] * lsp */ + t0 = L_shl (t0, 1); + *f = L_add (*f, f[-2]); move32 (); /* *f += f[-2] */ + *f = L_sub (*f, t0);move32 (); /* *f -= t0 */ + } + *f = L_msu (*f, *lsp, 512); move32 (); /* *f -= lsp<<9 */ + f += i; /* Advance f pointer */ + lsp += 2; /* Advance lsp pointer */ + } + + return; +} diff -r 000000000000 -r 56410792419a src/lsp_lsf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lsp_lsf.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,76 @@ +/************************************************************************* + * + * FUNCTIONS: Lsp_lsf and Lsf_lsp + * + * PURPOSE: + * Lsp_lsf: Transformation lsp to lsf + * Lsf_lsp: Transformation lsf to lsp + * + * DESCRIPTION: + * lsp[i] = cos(2*pi*lsf[i]) and lsf[i] = arccos(lsp[i])/(2*pi) + * + * The transformation from lsp[i] to lsf[i] and lsf[i] to lsp[i] are + * approximated by a look-up table and interpolation. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +#include "lsp_lsf.tab" /* Look-up table for transformations */ + +void Lsf_lsp ( + Word16 lsf[], /* (i) : lsf[m] normalized (range: 0.0<=val<=0.5) */ + Word16 lsp[], /* (o) : lsp[m] (range: -1<=val<1) */ + Word16 m /* (i) : LPC order */ +) +{ + Word16 i, ind, offset; + Word32 L_tmp; + + for (i = 0; i < m; i++) + { + ind = shr (lsf[i], 8); /* ind = b8-b15 of lsf[i] */ + offset = lsf[i] & 0x00ff; logic16 (); /* offset = b0-b7 of lsf[i] */ + + /* lsp[i] = table[ind]+ ((table[ind+1]-table[ind])*offset) / 256 */ + + L_tmp = L_mult (sub (table[ind + 1], table[ind]), offset); + lsp[i] = add (table[ind], extract_l (L_shr (L_tmp, 9))); + move16 (); + } + return; +} + +void Lsp_lsf ( + Word16 lsp[], /* (i) : lsp[m] (range: -1<=val<1) */ + Word16 lsf[], /* (o) : lsf[m] normalized (range: 0.0<=val<=0.5) */ + Word16 m /* (i) : LPC order */ +) +{ + Word16 i, ind; + Word32 L_tmp; + + ind = 63; /* begin at end of table -1 */ + + for (i = m - 1; i >= 0; i--) + { + /* find value in table that is just greater than lsp[i] */ + test (); + while (sub (table[ind], lsp[i]) < 0) + { + ind--; + test (); + } + + /* acos(lsp[i])= ind*256 + ( ( lsp[i]-table[ind] ) * + slope[ind] )/4096 */ + + L_tmp = L_mult (sub (lsp[i], table[ind]), slope[ind]); + /*(lsp[i]-table[ind])*slope[ind])>>12*/ + lsf[i] = round (L_shl (L_tmp, 3)); move16 (); + lsf[i] = add (lsf[i], shl (ind, 8)); move16 (); + } + return; +} diff -r 000000000000 -r 56410792419a src/lsp_lsf.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lsp_lsf.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,34 @@ +/*-----------------------------------------------------* + | Tables for function Lsf_lsp() and Lsp_lsf() | + -----------------------------------------------------*/ + +/* table of cos(x) */ + +static const Word16 table[65] = +{ + 32767, 32729, 32610, 32413, 32138, 31786, 31357, 30853, + 30274, 29622, 28899, 28106, 27246, 26320, 25330, 24279, + 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010, + 12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608, + 0, -1608, -3212, -4808, -6393, -7962, -9512, -11039, + -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006, + -23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622, + -30274, -30853, -31357, -31786, -32138, -32413, -32610, -32729, + (Word16) 0x8000 +}; + +/* 0x8000 = -32768 (used to silence the compiler) */ + +/* slope used to compute y = acos(x) */ + +static const Word16 slope[64] = +{ + -26887, -8812, -5323, -3813, -2979, -2444, -2081, -1811, + -1608, -1450, -1322, -1219, -1132, -1059, -998, -946, + -901, -861, -827, -797, -772, -750, -730, -713, + -699, -687, -677, -668, -662, -657, -654, -652, + -652, -654, -657, -662, -668, -677, -687, -699, + -713, -730, -750, -772, -797, -827, -861, -901, + -946, -998, -1059, -1132, -1219, -1322, -1450, -1608, + -1811, -2081, -2444, -2979, -3813, -5323, -8812, -26887 +}; diff -r 000000000000 -r 56410792419a src/n_proc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/n_proc.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,14 @@ +#include +#include + +void proc_head (char *mes) +{ + fprintf(stderr, "\n/**************************************************************\n\n"); + fprintf(stderr, " European digital cellular telecommunications system\n"); + fprintf(stderr, " 12200 bits/s speech codec for\n"); + fprintf(stderr, " enhanced full rate speech traffic channels\n\n"); + fprintf(stderr, " Bit-Exact C Simulation Code - %s\n", mes); + fprintf(stderr, " Version 5.1.0\n"); + fprintf(stderr, " June 26, 1996\n\n"); + fprintf(stderr, "**************************************************************/\n\n"); +} diff -r 000000000000 -r 56410792419a src/n_stack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/n_stack.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,7 @@ +#if defined(__BORLANDC__) +#include +extern unsigned _stklen = 32000U; + +#endif + +void proc_head (char *mes); diff -r 000000000000 -r 56410792419a src/oper_32b.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/oper_32b.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,208 @@ +/***************************************************************************** + * * + * This file contains operations in double precision. * + * These operations are not standard double precision operations. * + * They are used where single precision is not enough but the full 32 bits * + * precision is not necessary. For example, the function Div_32() has a * + * 24 bits precision which is enough for our purposes. * + * * + * The double precision numbers use a special representation: * + * * + * L_32 = hi<<16 + lo<<1 * + * * + * L_32 is a 32 bit integer. * + * hi and lo are 16 bit signed integers. * + * As the low part also contains the sign, this allows fast multiplication. * + * * + * 0x8000 0000 <= L_32 <= 0x7fff fffe. * + * * + * We will use DPF (Double Precision Format )in this file to specify * + * this special format. * + ***************************************************************************** +*/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" + +/***************************************************************************** + * * + * Function L_Extract() * + * * + * Extract from a 32 bit integer two 16 bit DPF. * + * * + * Arguments: * + * * + * L_32 : 32 bit integer. * + * 0x8000 0000 <= L_32 <= 0x7fff ffff. * + * hi : b16 to b31 of L_32 * + * lo : (L_32 - hi<<16)>>1 * + ***************************************************************************** +*/ + +void L_Extract (Word32 L_32, Word16 *hi, Word16 *lo) +{ + *hi = extract_h (L_32); + *lo = extract_l (L_msu (L_shr (L_32, 1), *hi, 16384)); + return; +} + +/***************************************************************************** + * * + * Function L_Comp() * + * * + * Compose from two 16 bit DPF a 32 bit integer. * + * * + * L_32 = hi<<16 + lo<<1 * + * * + * Arguments: * + * * + * hi msb * + * lo lsf (with sign) * + * * + * Return Value : * + * * + * 32 bit long signed integer (Word32) whose value falls in the * + * range : 0x8000 0000 <= L_32 <= 0x7fff fff0. * + * * + ***************************************************************************** +*/ + +Word32 L_Comp (Word16 hi, Word16 lo) +{ + Word32 L_32; + + L_32 = L_deposit_h (hi); + return (L_mac (L_32, lo, 1)); /* = hi<<16 + lo<<1 */ +} + +/***************************************************************************** + * Function Mpy_32() * + * * + * Multiply two 32 bit integers (DPF). The result is divided by 2**31 * + * * + * L_32 = (hi1*hi2)<<1 + ( (hi1*lo2)>>15 + (lo1*hi2)>>15 )<<1 * + * * + * This operation can also be viewed as the multiplication of two Q31 * + * number and the result is also in Q31. * + * * + * Arguments: * + * * + * hi1 hi part of first number * + * lo1 lo part of first number * + * hi2 hi part of second number * + * lo2 lo part of second number * + * * + ***************************************************************************** +*/ + +Word32 Mpy_32 (Word16 hi1, Word16 lo1, Word16 hi2, Word16 lo2) +{ + Word32 L_32; + + L_32 = L_mult (hi1, hi2); + L_32 = L_mac (L_32, mult (hi1, lo2), 1); + L_32 = L_mac (L_32, mult (lo1, hi2), 1); + + return (L_32); +} + +/***************************************************************************** + * Function Mpy_32_16() * + * * + * Multiply a 16 bit integer by a 32 bit (DPF). The result is divided * + * by 2**15 * + * * + * * + * L_32 = (hi1*lo2)<<1 + ((lo1*lo2)>>15)<<1 * + * * + * Arguments: * + * * + * hi hi part of 32 bit number. * + * lo lo part of 32 bit number. * + * n 16 bit number. * + * * + ***************************************************************************** +*/ + +Word32 Mpy_32_16 (Word16 hi, Word16 lo, Word16 n) +{ + Word32 L_32; + + L_32 = L_mult (hi, n); + L_32 = L_mac (L_32, mult (lo, n), 1); + + return (L_32); +} + +/***************************************************************************** + * * + * Function Name : Div_32 * + * * + * Purpose : * + * Fractional integer division of two 32 bit numbers. * + * L_num / L_denom. * + * L_num and L_denom must be positive and L_num < L_denom. * + * L_denom = denom_hi<<16 + denom_lo<<1 * + * denom_hi is a normalize number. * + * * + * Inputs : * + * * + * L_num * + * 32 bit long signed integer (Word32) whose value falls in the * + * range : 0x0000 0000 < L_num < L_denom * + * * + * L_denom = denom_hi<<16 + denom_lo<<1 (DPF) * + * * + * denom_hi * + * 16 bit positive normalized integer whose value falls in the * + * range : 0x4000 < hi < 0x7fff * + * denom_lo * + * 16 bit positive integer whose value falls in the * + * range : 0 < lo < 0x7fff * + * * + * Return Value : * + * * + * L_div * + * 32 bit long signed integer (Word32) whose value falls in the * + * range : 0x0000 0000 <= L_div <= 0x7fff ffff. * + * * + * Algorithm: * + * * + * - find = 1/L_denom. * + * First approximation: approx = 1 / denom_hi * + * 1/L_denom = approx * (2.0 - L_denom * approx ) * + * * + * - result = L_num * (1/L_denom) * + ***************************************************************************** +*/ + +Word32 Div_32 (Word32 L_num, Word16 denom_hi, Word16 denom_lo) +{ + Word16 approx, hi, lo, n_hi, n_lo; + Word32 L_32; + + /* First approximation: 1 / L_denom = 1/denom_hi */ + + approx = div_s ((Word16) 0x3fff, denom_hi); + + /* 1/L_denom = approx * (2.0 - L_denom * approx) */ + + L_32 = Mpy_32_16 (denom_hi, denom_lo, approx); + + L_32 = L_sub ((Word32) 0x7fffffffL, L_32); + + L_Extract (L_32, &hi, &lo); + + L_32 = Mpy_32_16 (hi, lo, approx); + + /* L_num * (1/L_denom) */ + + L_Extract (L_32, &hi, &lo); + L_Extract (L_num, &n_hi, &n_lo); + L_32 = Mpy_32 (n_hi, n_lo, hi, lo); + L_32 = L_shl (L_32, 2); + + return (L_32); +} diff -r 000000000000 -r 56410792419a src/oper_32b.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/oper_32b.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,7 @@ +/* Double precision operations */ + +void L_Extract (Word32 L_32, Word16 *hi, Word16 *lo); +Word32 L_Comp (Word16 hi, Word16 lo); +Word32 Mpy_32 (Word16 hi1, Word16 lo1, Word16 hi2, Word16 lo2); +Word32 Mpy_32_16 (Word16 hi, Word16 lo, Word16 n); +Word32 Div_32 (Word32 L_num, Word16 denom_hi, Word16 denom_lo); diff -r 000000000000 -r 56410792419a src/pitch_f6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pitch_f6.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,227 @@ +/************************************************************************* + * + * FUNCTION: Pitch_fr6() + * + * PURPOSE: Find the pitch period with 1/6 subsample resolution (closed loop). + * + * DESCRIPTION: + * - find the normalized correlation between the target and filtered + * past excitation in the search range. + * - select the delay with maximum normalized correlation. + * - interpolate the normalized correlation at fractions -3/6 to 3/6 + * with step 1/6 around the chosen delay. + * - The fraction which gives the maximum interpolated value is chosen. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "sig_proc.h" +#include "codec.h" + + /* L_inter = Length for fractional interpolation = nb.coeff/2 */ + +#define L_inter 4 + + /* Local functions */ + +void Norm_Corr (Word16 exc[], Word16 xn[], Word16 h[], Word16 L_subfr, + Word16 t_min, Word16 t_max, Word16 corr_norm[]); + +Word16 Pitch_fr6 ( /* (o) : pitch period. */ + Word16 exc[], /* (i) : excitation buffer */ + Word16 xn[], /* (i) : target vector */ + Word16 h[], /* (i) : impulse response of synthesis and + weighting filters */ + Word16 L_subfr, /* (i) : Length of subframe */ + Word16 t0_min, /* (i) : minimum value in the searched range. */ + Word16 t0_max, /* (i) : maximum value in the searched range. */ + Word16 i_subfr, /* (i) : indicator for first subframe. */ + Word16 *pit_frac /* (o) : chosen fraction. */ +) +{ + Word16 i; + Word16 t_min, t_max; + Word16 max, lag, frac; + Word16 *corr; + Word16 corr_int; + Word16 corr_v[40]; /* Total length = t0_max-t0_min+1+2*L_inter */ + + /* Find interval to compute normalized correlation */ + + t_min = sub (t0_min, L_inter); + t_max = add (t0_max, L_inter); + + corr = &corr_v[-t_min]; move16 (); + + /* Compute normalized correlation between target and filtered excitation */ + + Norm_Corr (exc, xn, h, L_subfr, t_min, t_max, corr); + + /* Find integer pitch */ + + max = corr[t0_min]; move16 (); + lag = t0_min; move16 (); + + for (i = t0_min + 1; i <= t0_max; i++) + { + test (); + if (sub (corr[i], max) >= 0) + { + max = corr[i]; move16 (); + lag = i; move16 (); + } + } + + /* If first subframe and lag > 94 do not search fractional pitch */ + + test (); test (); + if ((i_subfr == 0) && (sub (lag, 94) > 0)) + { + *pit_frac = 0; move16 (); + return (lag); + } + /* Test the fractions around T0 and choose the one which maximizes */ + /* the interpolated normalized correlation. */ + + max = Interpol_6 (&corr[lag], -3); + frac = -3; move16 (); + + for (i = -2; i <= 3; i++) + { + corr_int = Interpol_6 (&corr[lag], i); move16 (); + test (); + if (sub (corr_int, max) > 0) + { + max = corr_int; move16 (); + frac = i; move16 (); + } + } + + /* Limit the fraction value in the interval [-2,-1,0,1,2,3] */ + + test (); + if (sub (frac, -3) == 0) + { + frac = 3; move16 (); + lag = sub (lag, 1); + } + *pit_frac = frac; move16 (); + + return (lag); +} + +/************************************************************************* + * + * FUNCTION: Norm_Corr() + * + * PURPOSE: Find the normalized correlation between the target vector + * and the filtered past excitation. + * + * DESCRIPTION: + * The normalized correlation is given by the correlation between the + * target and filtered past excitation divided by the square root of + * the energy of filtered excitation. + * corr[k] = /sqrt(y_k[],y_k[]) + * where x[] is the target vector and y_k[] is the filtered past + * excitation at delay k. + * + *************************************************************************/ + +void +Norm_Corr (Word16 exc[], Word16 xn[], Word16 h[], Word16 L_subfr, + Word16 t_min, Word16 t_max, Word16 corr_norm[]) +{ + Word16 i, j, k; + Word16 corr_h, corr_l, norm_h, norm_l; + Word32 s; + + /* Usally dynamic allocation of (L_subfr) */ + Word16 excf[80]; + Word16 scaling, h_fac, *s_excf, scaled_excf[80]; + + k = -t_min; move16 (); + + /* compute the filtered excitation for the first delay t_min */ + + Convolve (&exc[k], h, excf, L_subfr); + + /* scale "excf[]" to avoid overflow */ + + for (j = 0; j < L_subfr; j++) + { + scaled_excf[j] = shr (excf[j], 2); move16 (); + } + + /* Compute 1/sqrt(energy of excf[]) */ + + s = 0; move32 (); + for (j = 0; j < L_subfr; j++) + { + s = L_mac (s, excf[j], excf[j]); + } + test (); + if (L_sub (s, 67108864L) <= 0) /* if (s <= 2^26) */ + { + s_excf = excf; move16 (); + h_fac = 15 - 12; move16 (); + scaling = 0; move16 (); + } + else + { + /* "excf[]" is divided by 2 */ + s_excf = scaled_excf; move16 (); + h_fac = 15 - 12 - 2; move16 (); + scaling = 2; move16 (); + } + + /* loop for every possible period */ + + for (i = t_min; i <= t_max; i++) + { + /* Compute 1/sqrt(energy of excf[]) */ + + s = 0; move32 (); + for (j = 0; j < L_subfr; j++) + { + s = L_mac (s, s_excf[j], s_excf[j]); + } + + s = Inv_sqrt (s); move16 (); + L_Extract (s, &norm_h, &norm_l); + + /* Compute correlation between xn[] and excf[] */ + + s = 0; move32 (); + for (j = 0; j < L_subfr; j++) + { + s = L_mac (s, xn[j], s_excf[j]); + } + L_Extract (s, &corr_h, &corr_l); + + /* Normalize correlation = correlation * (1/sqrt(energy)) */ + + s = Mpy_32 (corr_h, corr_l, norm_h, norm_l); + + corr_norm[i] = extract_h (L_shl (s, 16)); + move16 (); + + /* modify the filtered excitation excf[] for the next iteration */ + + test (); + if (sub (i, t_max) != 0) + { + k--; + for (j = L_subfr - 1; j > 0; j--) + { + s = L_mult (exc[k], h[j]); + s = L_shl (s, h_fac); + s_excf[j] = add (extract_h (s), s_excf[j - 1]); move16 (); + } + s_excf[0] = shr (exc[k], scaling); move16 (); + } + } + return; +} diff -r 000000000000 -r 56410792419a src/pitch_ol.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pitch_ol.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,214 @@ +/************************************************************************* + * + * FUNCTION: Pitch_ol + * + * PURPOSE: Compute the open loop pitch lag. + * + * DESCRIPTION: + * The open-loop pitch lag is determined based on the perceptually + * weighted speech signal. This is done in the following steps: + * - find three maxima of the correlation in the + * follwing three ranges of T : [18,35], [36,71], and [72, 143] + * - divide each maximum by where t is the delay at + * that maximum correlation. + * - select the delay of maximum normalized correlation (among the + * three candidates) while favoring the lower delay ranges. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "sig_proc.h" + +#define THRESHOLD 27853 + +/* local function */ + +static Word16 Lag_max ( /* output: lag found */ + Word16 scal_sig[], /* input : scaled signal */ + Word16 scal_fac, /* input : scaled signal factor */ + Word16 L_frame, /* input : length of frame to compute pitch */ + Word16 lag_max, /* input : maximum lag */ + Word16 lag_min, /* input : minimum lag */ + Word16 *cor_max); /* output: normalized correlation of selected lag */ + +Word16 Pitch_ol ( /* output: open loop pitch lag */ + Word16 signal[], /* input : signal used to compute the open loop pitch */ + /* signal[-pit_max] to signal[-1] should be known */ + Word16 pit_min, /* input : minimum pitch lag */ + Word16 pit_max, /* input : maximum pitch lag */ + Word16 L_frame /* input : length of frame to compute pitch */ +) +{ + Word16 i, j; + Word16 max1, max2, max3; + Word16 p_max1, p_max2, p_max3; + Word32 t0; + + /* Scaled signal */ + /* Can be allocated with memory allocation of(pit_max+L_frame) */ + + Word16 scaled_signal[512]; + Word16 *scal_sig, scal_fac; + + scal_sig = &scaled_signal[pit_max]; move16 (); + + t0 = 0L; move32 (); + for (i = -pit_max; i < L_frame; i++) + { + t0 = L_mac (t0, signal[i], signal[i]); + } + /*--------------------------------------------------------* + * Scaling of input signal. * + * * + * if Overflow -> scal_sig[i] = signal[i]>>2 * + * else if t0 < 1^22 -> scal_sig[i] = signal[i]<<2 * + * else -> scal_sig[i] = signal[i] * + *--------------------------------------------------------*/ + + /*--------------------------------------------------------* + * Verification for risk of overflow. * + *--------------------------------------------------------*/ + + test (); test (); + if (L_sub (t0, MAX_32) == 0L) /* Test for overflow */ + { + for (i = -pit_max; i < L_frame; i++) + { + scal_sig[i] = shr (signal[i], 3); move16 (); + } + scal_fac = 3; move16 (); + } + else if (L_sub (t0, (Word32) 1048576L) < (Word32) 0) + /* if (t0 < 2^20) */ + { + for (i = -pit_max; i < L_frame; i++) + { + scal_sig[i] = shl (signal[i], 3); move16 (); + } + scal_fac = -3; move16 (); + } + else + { + for (i = -pit_max; i < L_frame; i++) + { + scal_sig[i] = signal[i]; move16 (); + } + scal_fac = 0; move16 (); + } + + /*--------------------------------------------------------------------* + * The pitch lag search is divided in three sections. * + * Each section cannot have a pitch multiple. * + * We find a maximum for each section. * + * We compare the maximum of each section by favoring small lags. * + * * + * First section: lag delay = pit_max downto 4*pit_min * + * Second section: lag delay = 4*pit_min-1 downto 2*pit_min * + * Third section: lag delay = 2*pit_min-1 downto pit_min * + *-------------------------------------------------------------------*/ + + j = shl (pit_min, 2); + p_max1 = Lag_max (scal_sig, scal_fac, L_frame, pit_max, j, &max1); + + i = sub (j, 1); + j = shl (pit_min, 1); + p_max2 = Lag_max (scal_sig, scal_fac, L_frame, i, j, &max2); + + i = sub (j, 1); + p_max3 = Lag_max (scal_sig, scal_fac, L_frame, i, pit_min, &max3); + + /*--------------------------------------------------------------------* + * Compare the 3 sections maximum, and favor small lag. * + *-------------------------------------------------------------------*/ + + test (); + if (sub (mult (max1, THRESHOLD), max2) < 0) + { + max1 = max2; move16 (); + p_max1 = p_max2; move16 (); + } + test (); + if (sub (mult (max1, THRESHOLD), max3) < 0) + { + p_max1 = p_max3; move16 (); + } + return (p_max1); +} + +/************************************************************************* + * + * FUNCTION: Lag_max + * + * PURPOSE: Find the lag that has maximum correlation of scal_sig[] in a + * given delay range. + * + * DESCRIPTION: + * The correlation is given by + * cor[t] = , t=lag_min,...,lag_max + * The functions outputs the maximum correlation after normalization + * and the corresponding lag. + * + *************************************************************************/ + +static Word16 Lag_max ( /* output: lag found */ + Word16 scal_sig[], /* input : scaled signal. */ + Word16 scal_fac, /* input : scaled signal factor. */ + Word16 L_frame, /* input : length of frame to compute pitch */ + Word16 lag_max, /* input : maximum lag */ + Word16 lag_min, /* input : minimum lag */ + Word16 *cor_max) /* output: normalized correlation of selected lag */ +{ + Word16 i, j; + Word16 *p, *p1; + Word32 max, t0; + Word16 max_h, max_l, ener_h, ener_l; + Word16 p_max; + + max = MIN_32; move32 (); + + for (i = lag_max; i >= lag_min; i--) + { + p = scal_sig; move16 (); + p1 = &scal_sig[-i]; move16 (); + t0 = 0; move32 (); + + for (j = 0; j < L_frame; j++, p++, p1++) + { + t0 = L_mac (t0, *p, *p1); + } + test (); + if (L_sub (t0, max) >= 0) + { + max = t0; move32 (); + p_max = i; move16 (); + } + } + + /* compute energy */ + + t0 = 0; move32 (); + p = &scal_sig[-p_max]; move16 (); + for (i = 0; i < L_frame; i++, p++) + { + t0 = L_mac (t0, *p, *p); + } + /* 1/sqrt(energy) */ + + t0 = Inv_sqrt (t0); + t0 = L_shl (t0, 1); + + /* max = max/sqrt(energy) */ + + L_Extract (max, &max_h, &max_l); + L_Extract (t0, &ener_h, &ener_l); + + t0 = Mpy_32 (max_h, max_l, ener_h, ener_l); + t0 = L_shr (t0, scal_fac); + + *cor_max = extract_h (L_shl (t0, 15)); move16 (); /* divide by 2 */ + + return (p_max); +} diff -r 000000000000 -r 56410792419a src/pow2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pow2.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,45 @@ +/************************************************************************* + * + * FUNCTION: Pow2() + * + * PURPOSE: computes L_x = pow(2.0, exponent.fraction) + * + * DESCRIPTION: + * The function Pow2(L_x) is approximated by a table and linear + * interpolation. + * 1- i = bit10-b15 of fraction, 0 <= i <= 31 + * 2- a = bit0-b9 of fraction + * 3- L_x = table[i]<<16 - (table[i] - table[i+1]) * a * 2 + * 4- L_x = L_x >> (30-exponent) (with rounding) + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +#include "pow2.tab" /* Table for Pow2() */ + +Word32 Pow2 ( /* (o) : result (range: 0<=val<=0x7fffffff) */ + Word16 exponent, /* (i) : Integer part. (range: 0<=val<=30) */ + Word16 fraction /* (i) : Fractional part. (range: 0.0<=val<1.0) */ +) +{ + Word16 exp, i, a, tmp; + Word32 L_x; + + L_x = L_mult (fraction, 32);/* L_x = fraction<<6 */ + i = extract_h (L_x); /* Extract b10-b16 of fraction */ + L_x = L_shr (L_x, 1); + a = extract_l (L_x); /* Extract b0-b9 of fraction */ + a = a & (Word16) 0x7fff; logic16 (); + + L_x = L_deposit_h (table[i]); /* table[i] << 16 */ + tmp = sub (table[i], table[i + 1]); /* table[i] - table[i+1] */ + L_x = L_msu (L_x, tmp, a); /* L_x -= tmp*a*2 */ + + exp = sub (30, exponent); + L_x = L_shr_r (L_x, exp); + + return (L_x); +} diff -r 000000000000 -r 56410792419a src/pow2.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pow2.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,11 @@ +/*-----------------------------------------------------* + | Table for routine Pow2(). | + -----------------------------------------------------*/ + +static const Word16 table[33] = +{ + 16384, 16743, 17109, 17484, 17867, 18258, 18658, 19066, 19484, 19911, + 20347, 20792, 21247, 21713, 22188, 22674, 23170, 23678, 24196, 24726, + 25268, 25821, 26386, 26964, 27554, 28158, 28774, 29405, 30048, 30706, + 31379, 32066, 32767 +}; diff -r 000000000000 -r 56410792419a src/pre_proc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pre_proc.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,80 @@ +/************************************************************************* + * + * FUNCTION: Pre_Process() + * + * PURPOSE: Preprocessing of input speech. + * + * DESCRIPTION: + * - 2nd order high pass filtering with cut off frequency at 80 Hz. + * - Divide input by two. + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" + +/*------------------------------------------------------------------------* + * * + * Algorithm: * + * * + * y[i] = b[0]*x[i]/2 + b[1]*x[i-1]/2 + b[2]*x[i-2]/2 * + * + a[1]*y[i-1] + a[2]*y[i-2]; * + * * + * * + * Input is divided by two in the filtering process. * + *------------------------------------------------------------------------*/ + +/* filter coefficients (fc = 80 Hz, coeff. b[] is divided by 2) */ + +static const Word16 b[3] = {1899, -3798, 1899}; +static const Word16 a[3] = {4096, 7807, -3733}; + +/* Static values to be preserved between calls */ +/* y[] values are kept in double precision */ + +static Word16 y2_hi, y2_lo, y1_hi, y1_lo, x0, x1; + +/* Initialization of static values */ + +void Init_Pre_Process (void) +{ + y2_hi = 0; + y2_lo = 0; + y1_hi = 0; + y1_lo = 0; + x0 = 0; + x1 = 0; +} + +void Pre_Process ( + Word16 signal[], /* input/output signal */ + Word16 lg) /* lenght of signal */ +{ + Word16 i, x2; + Word32 L_tmp; + + for (i = 0; i < lg; i++) + { + x2 = x1; move16 (); + x1 = x0; move16 (); + x0 = signal[i]; move16 (); + + /* y[i] = b[0]*x[i]/2 + b[1]*x[i-1]/2 + b140[2]*x[i-2]/2 */ + /* + a[1]*y[i-1] + a[2] * y[i-2]; */ + + L_tmp = Mpy_32_16 (y1_hi, y1_lo, a[1]); + L_tmp = L_add (L_tmp, Mpy_32_16 (y2_hi, y2_lo, a[2])); + L_tmp = L_mac (L_tmp, x0, b[0]); + L_tmp = L_mac (L_tmp, x1, b[1]); + L_tmp = L_mac (L_tmp, x2, b[2]); + L_tmp = L_shl (L_tmp, 3); + signal[i] = round (L_tmp); move16 (); + + y2_hi = y1_hi; move16 (); + y2_lo = y1_lo; move16 (); + L_Extract (L_tmp, &y1_hi, &y1_lo); + } + return; +} diff -r 000000000000 -r 56410792419a src/pred_lt6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pred_lt6.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,80 @@ +/************************************************************************* + * + * FUNCTION: Pred_lt_6() + * + * PURPOSE: Compute the result of long term prediction with fractional + * interpolation of resolution 1/6. (Interpolated past excitation). + * + * DESCRIPTION: + * The past excitation signal at the given delay is interpolated at + * the given fraction to build the adaptive codebook excitation. + * On return exc[0..L_subfr-1] contains the interpolated signal + * (adaptive codebook excitation). + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +#define UP_SAMP 6 +#define L_INTERPOL 10 +#define FIR_SIZE (UP_SAMP*L_INTERPOL+1) + +/* 1/6 resolution interpolation filter (-3 dB at 3600 Hz) */ + +static const Word16 inter_6[FIR_SIZE] = +{ + 29443, + 28346, 25207, 20449, 14701, 8693, 3143, + -1352, -4402, -5865, -5850, -4673, -2783, + -672, 1211, 2536, 3130, 2991, 2259, + 1170, 0, -1001, -1652, -1868, -1666, + -1147, -464, 218, 756, 1060, 1099, + 904, 550, 135, -245, -514, -634, + -602, -451, -231, 0, 191, 308, + 340, 296, 198, 78, -36, -120, + -163, -165, -132, -79, -19, 34, + 73, 91, 89, 70, 38, 0 +}; + +void Pred_lt_6 ( + Word16 exc[], /* in/out: excitation buffer */ + Word16 T0, /* input : integer pitch lag */ + Word16 frac, /* input : fraction of lag */ + Word16 L_subfr /* input : subframe size */ +) +{ + Word16 i, j, k; + Word16 *x0, *x1, *x2; + const Word16 *c1, *c2; + Word32 s; + + x0 = &exc[-T0]; move16 (); + + frac = negate (frac); + test (); + if (frac < 0) + { + frac = add (frac, UP_SAMP); + x0--; + } + for (j = 0; j < L_subfr; j++) + { + x1 = x0++; move16 (); + x2 = x0; move16 (); + c1 = &inter_6[frac]; + c2 = &inter_6[sub (UP_SAMP, frac)]; + + s = 0; move32 (); + for (i = 0, k = 0; i < L_INTERPOL; i++, k += UP_SAMP) + { + s = L_mac (s, x1[-i], c1[k]); + s = L_mac (s, x2[i], c2[k]); + } + + exc[j] = round (s); move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/preemph.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/preemph.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------* + * routine preemphasis() * + * ~~~~~~~~~~~~~~~~~~~~~ * + * Preemphasis: filtering through 1 - g z^-1 * + *---------------------------------------------------------------------*/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +Word16 mem_pre; + +void preemphasis ( + Word16 *signal, /* (i/o) : input signal overwritten by the output */ + Word16 g, /* (i) : preemphasis coefficient */ + Word16 L /* (i) : size of filtering */ +) +{ + Word16 *p1, *p2, temp, i; + + p1 = signal + L - 1; move16 (); + p2 = p1 - 1; move16 (); + temp = *p1; move16 (); + + for (i = 0; i <= L - 2; i++) + { + *p1 = sub (*p1, mult (g, *p2--)); move16 (); + p1--; + } + + *p1 = sub (*p1, mult (g, mem_pre)); move16 (); + + mem_pre = temp; move16 (); + + return; +} diff -r 000000000000 -r 56410792419a src/prm2bits.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/prm2bits.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,105 @@ +/************************************************************************* + * + * FUNCTION: Prm2bits_12k2 + * + * PURPOSE: converts the encoder parameter vector into a vector of serial + * bits. + * + * DESCRIPTION: The encoder parameters are: + * + * LPC: + * 1st codebook 7 bit + * 2nd codebook 8 bit + * 3rd codebook 8+1 bit + * 4th codebook 8 bit + * 5th codebook 6 bit + * + * 1st and 3rd subframes: + * pitch period 9 bit + * pitch gain 4 bit + * codebook index 35 bit + * codebook gain 5 bit + * + * 2nd and 4th subframes: + * pitch period 6 bit + * pitch gain 4 bit + * codebook index 35 bit + * codebook gain 5 bit + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +/* Local function */ + +void Int2bin ( + Word16 value, /* input : value to be converted to binary */ + Word16 no_of_bits, /* input : number of bits associated with value */ + Word16 *bitstream /* output: address where bits are written */ +); + +#define BIT_0 0 +#define BIT_1 1 +#define MASK 0x0001 +#define PRM_NO 57 + +void Prm2bits_12k2 ( + Word16 prm[], /* input : analysis parameters (57 parameters) */ + Word16 bits[] /* output: 244 serial bits */ +) +{ + Word16 i; + + static const Word16 bitno[PRM_NO] = + { + 7, 8, 9, 8, 6, /* LSP VQ */ + 9, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, /* first subframe */ + 6, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, /* second subframe */ + 9, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5, /* third subframe */ + 6, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 5 /* fourth subframe */ + }; + for (i = 0; i < PRM_NO; i++) + { + Int2bin (prm[i], bitno[i], bits); + bits += bitno[i]; + } + + return; +} + +/************************************************************************* + * + * FUNCTION: Int2bin + * + * PURPOSE: convert integer to binary and write the bits to the array + * bitstream[]. The most significant bits are written first. + * + *************************************************************************/ + +void Int2bin ( + Word16 value, /* input : value to be converted to binary */ + Word16 no_of_bits, /* input : number of bits associated with value */ + Word16 *bitstream /* output: address where bits are written */ +) +{ + Word16 *pt_bitstream, i, bit; + + pt_bitstream = &bitstream[no_of_bits]; move16 (); + + for (i = 0; i < no_of_bits; i++) + { + bit = value & MASK; logic16 (); + test (); + if (bit == 0) + { + *--pt_bitstream = BIT_0; move16 (); + } + else + { + *--pt_bitstream = BIT_1; move16 (); + } + value = shr (value, 1); + } +} diff -r 000000000000 -r 56410792419a src/pstfilt2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pstfilt2.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,182 @@ +/************************************************************************* + * + * FILE NAME: pstfilt2.c + * + * Performs adaptive postfiltering on the synthesis speech + * + * FUNCTIONS INCLUDED: Init_Post_Filter() and Post_Filter() + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "sig_proc.h" +#include "count.h" +#include "codec.h" +#include "cnst.h" + +/*---------------------------------------------------------------* + * Postfilter constant parameters (defined in "cnst.h") * + *---------------------------------------------------------------* + * L_FRAME : Frame size. * + * L_SUBFR : Sub-frame size. * + * M : LPC order. * + * MP1 : LPC order+1 * + * MU : Factor for tilt compensation filter * + * AGC_FAC : Factor for automatic gain control * + *---------------------------------------------------------------*/ + +#define L_H 22 /* size of truncated impulse response of A(z/g1)/A(z/g2) */ + +/*------------------------------------------------------------* + * static vectors * + *------------------------------------------------------------*/ + + /* inverse filtered synthesis */ + +static Word16 res2[L_SUBFR]; + + /* memory of filter 1/A(z/0.75) */ + +static Word16 mem_syn_pst[M]; + + /* Spectral expansion factors */ + +const Word16 F_gamma3[M] = +{ + 22938, 16057, 11240, 7868, 5508, + 3856, 2699, 1889, 1322, 925 +}; +const Word16 F_gamma4[M] = +{ + 24576, 18432, 13824, 10368, 7776, + 5832, 4374, 3281, 2461, 1846 +}; + +/************************************************************************* + * + * FUNCTION: Init_Post_Filter + * + * PURPOSE: Initializes the postfilter parameters. + * + *************************************************************************/ + +void Init_Post_Filter (void) +{ + Set_zero (mem_syn_pst, M); + + Set_zero (res2, L_SUBFR); + + return; +} + +/************************************************************************* + * FUNCTION: Post_Filter() + * + * PURPOSE: postfiltering of synthesis speech. + * + * DESCRIPTION: + * The postfiltering process is described as follows: + * + * - inverse filtering of syn[] through A(z/0.7) to get res2[] + * - tilt compensation filtering; 1 - MU*k*z^-1 + * - synthesis filtering through 1/A(z/0.75) + * - adaptive gain control + * + *************************************************************************/ + +void Post_Filter ( + Word16 *syn, /* in/out: synthesis speech (postfiltered is output) */ + Word16 *Az_4 /* input: interpolated LPC parameters in all subframes */ +) +{ + /*-------------------------------------------------------------------* + * Declaration of parameters * + *-------------------------------------------------------------------*/ + + Word16 syn_pst[L_FRAME]; /* post filtered synthesis speech */ + Word16 Ap3[MP1], Ap4[MP1]; /* bandwidth expanded LP parameters */ + Word16 *Az; /* pointer to Az_4: */ + /* LPC parameters in each subframe */ + Word16 i_subfr; /* index for beginning of subframe */ + Word16 h[L_H]; + + Word16 i; + Word16 temp1, temp2; + Word32 L_tmp; + + /*-----------------------------------------------------* + * Post filtering * + *-----------------------------------------------------*/ + + Az = Az_4; + + for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) + { + /* Find weighted filter coefficients Ap3[] and ap[4] */ + + Weight_Ai (Az, F_gamma3, Ap3); + Weight_Ai (Az, F_gamma4, Ap4); + + /* filtering of synthesis speech by A(z/0.7) to find res2[] */ + + Residu (Ap3, &syn[i_subfr], res2, L_SUBFR); + + /* tilt compensation filter */ + + /* impulse response of A(z/0.7)/A(z/0.75) */ + + Copy (Ap3, h, M + 1); + Set_zero (&h[M + 1], L_H - M - 1); + Syn_filt (Ap4, h, h, L_H, &h[M + 1], 0); + + /* 1st correlation of h[] */ + + L_tmp = L_mult (h[0], h[0]); + for (i = 1; i < L_H; i++) + { + L_tmp = L_mac (L_tmp, h[i], h[i]); + } + temp1 = extract_h (L_tmp); + + L_tmp = L_mult (h[0], h[1]); + for (i = 1; i < L_H - 1; i++) + { + L_tmp = L_mac (L_tmp, h[i], h[i + 1]); + } + temp2 = extract_h (L_tmp); + + test (); + if (temp2 <= 0) + { + temp2 = 0; move16 (); + } + else + { + temp2 = mult (temp2, MU); + temp2 = div_s (temp2, temp1); + } + + preemphasis (res2, temp2, L_SUBFR); + + /* filtering through 1/A(z/0.75) */ + + Syn_filt (Ap4, res2, &syn_pst[i_subfr], L_SUBFR, mem_syn_pst, 1); + + /* scale output to input */ + + agc (&syn[i_subfr], &syn_pst[i_subfr], AGC_FAC, L_SUBFR); + + Az += MP1; + } + + /* update syn[] buffer */ + + Copy (&syn[L_FRAME - M], &syn[-M], M); + + /* overwrite synthesis speech by postfiltered synthesis speech */ + + Copy (syn_pst, syn, L_FRAME); + + return; +} diff -r 000000000000 -r 56410792419a src/q_gains.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/q_gains.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,218 @@ +/*--------------------------------------------------------------------------* + * Function q_gain_pitch(), q_gain_code() * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + * Scalar quantization of the pitch gain and the innovative codebook gain. * + * * + * MA prediction is performed on the innovation energy * + * (in dB/(20*log10(2))) with mean removed. * + *-------------------------------------------------------------------------*/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "sig_proc.h" + +#include "gains_tb.h" + +#include "cnst.h" +#include "dtx.h" + +/* past quantized energies. */ +/* initialized to -14.0/constant, constant = 20*Log10(2) */ +Word16 past_qua_en[4]; + +/* MA prediction coeff */ +Word16 pred[4]; + +extern Word16 CN_excitation_gain, gain_code_old_tx[4 * DTX_HANGOVER]; + +Word16 q_gain_pitch ( /* Return index of quantization */ + Word16 *gain /* (i) : Pitch gain to quantize */ +) +{ + Word16 i, index, gain_q14, err, err_min; + + gain_q14 = shl (*gain, 2); + + err_min = abs_s (sub (gain_q14, qua_gain_pitch[0])); + index = 0; move16 (); + + for (i = 1; i < NB_QUA_PITCH; i++) + { + err = abs_s (sub (gain_q14, qua_gain_pitch[i])); + + test (); + if (sub (err, err_min) < 0) + { + err_min = err; move16 (); + index = i; move16 (); + } + } + + *gain = shr (qua_gain_pitch[index], 2); move16 (); + + return index; +} + +/* average innovation energy. */ +/* MEAN_ENER = 36.0/constant, constant = 20*Log10(2) */ + +#define MEAN_ENER 783741L /* 36/(20*log10(2)) */ + +Word16 q_gain_code ( /* Return quantization index */ + Word16 code[], /* (i) : fixed codebook excitation */ + Word16 lcode, /* (i) : codevector size */ + Word16 *gain, /* (i/o) : quantized fixed codebook gain */ + Word16 txdtx_ctrl, + Word16 i_subfr +) +{ + Word16 i, index; + Word16 gcode0, err, err_min, exp, frac; + Word32 ener, ener_code; + Word16 aver_gain; + static Word16 gcode0_CN; + + logic16 (); test (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + + /*-------------------------------------------------------------------* + * energy of code: * + * ~~~~~~~~~~~~~~~ * + * ener_code(Q17) = 10 * Log10(energy/lcode) / constant * + * = 1/2 * Log2(energy/lcode) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------------*/ + + /* ener_code = log10(ener_code/lcode) / (20*log10(2)) */ + ener_code = 0; move32 (); + for (i = 0; i < lcode; i++) + { + ener_code = L_mac (ener_code, code[i], code[i]); + } + /* ener_code = ener_code / lcode */ + ener_code = L_mult (round (ener_code), 26214); + + /* ener_code = 1/2 * Log2(ener_code) */ + Log2 (ener_code, &exp, &frac); + ener_code = L_Comp (sub (exp, 30), frac); + + /* predicted energy */ + + ener = MEAN_ENER; move32 (); + for (i = 0; i < 4; i++) + { + ener = L_mac (ener, past_qua_en[i], pred[i]); + } + + /*-------------------------------------------------------------------* + * predicted codebook gain * + * ~~~~~~~~~~~~~~~~~~~~~~~ * + * gcode0(Qx) = Pow10( (ener*constant - ener_code*constant) / 20 ) * + * = Pow2(ener-ener_code) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------------*/ + + ener = L_shr (L_sub (ener, ener_code), 1); + L_Extract (ener, &exp, &frac); + + gcode0 = extract_l (Pow2 (exp, frac)); /* predicted gain */ + + gcode0 = shl (gcode0, 4); + + /*-------------------------------------------------------------------* + * Search for best quantizer * + *-------------------------------------------------------------------*/ + + err_min = abs_s (sub (*gain, mult (gcode0, qua_gain_code[0]))); + index = 0; move16 (); + + for (i = 1; i < NB_QUA_CODE; i++) + { + err = abs_s (sub (*gain, mult (gcode0, qua_gain_code[i]))); + + test (); + if (sub (err, err_min) < 0) + { + err_min = err; move16 (); + index = i; move16 (); + } + } + + *gain = mult (gcode0, qua_gain_code[index]); + move16 (); + + /*------------------------------------------------------------------* + * update table of past quantized energies * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + * past_qua_en(Q12) = 20 * Log10(qua_gain_code) / constant * + * = Log2(qua_gain_code) * + * constant = 20*Log10(2) * + *------------------------------------------------------------------*/ + + for (i = 3; i > 0; i--) + { + past_qua_en[i] = past_qua_en[i - 1];move16 (); + } + Log2 (L_deposit_l (qua_gain_code[index]), &exp, &frac); + + past_qua_en[0] = shr (frac, 5); move16 (); + past_qua_en[0] = add (past_qua_en[0], shl (sub (exp, 11), 10)); + move16 (); + + update_gain_code_history_tx (*gain, gain_code_old_tx); + } + else + { + logic16 (); test (); test (); + if ((txdtx_ctrl & TX_PREV_HANGOVER_ACTIVE) != 0 && (i_subfr == 0)) + { + gcode0_CN = update_gcode0_CN (gain_code_old_tx); + gcode0_CN = shl (gcode0_CN, 4); + } + *gain = CN_excitation_gain; move16 (); + + logic16 (); test (); test (); + if ((txdtx_ctrl & TX_SID_UPDATE) != 0) + { + aver_gain = aver_gain_code_history (CN_excitation_gain, + gain_code_old_tx); + + /*---------------------------------------------------------------* + * Search for best quantizer * + *---------------------------------------------------------------*/ + + err_min = abs_s (sub (aver_gain, + mult (gcode0_CN, qua_gain_code[0]))); + index = 0; move16 (); + + for (i = 1; i < NB_QUA_CODE; i++) + { + err = abs_s (sub (aver_gain, + mult (gcode0_CN, qua_gain_code[i]))); + + test (); + if (sub (err, err_min) < 0) + { + err_min = err; move16 (); + index = i; move16 (); + } + } + } + update_gain_code_history_tx (*gain, gain_code_old_tx); + + /*-------------------------------------------------------------------* + * reset table of past quantized energies * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * + *-------------------------------------------------------------------*/ + + for (i = 0; i < 4; i++) + { + past_qua_en[i] = -2381; move16 (); + } + } + + return index; +} diff -r 000000000000 -r 56410792419a src/q_plsf_5.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/q_plsf_5.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,448 @@ +/************************************************************************* + * FUNCTION: Q_plsf_5() + * + * PURPOSE: Quantization of 2 sets of LSF parameters using 1st order MA + * prediction and split by 5 matrix quantization (split-MQ) + * + * DESCRIPTION: + * + * p[i] = pred_factor*past_r2q[i]; i=0,...,m-1 + * r1[i]= lsf1[i] - p[i]; i=0,...,m-1 + * r2[i]= lsf2[i] - p[i]; i=0,...,m-1 + * where: + * lsf1[i] 1st mean-removed LSF vector. + * lsf2[i] 2nd mean-removed LSF vector. + * r1[i] 1st residual prediction vector. + * r2[i] 2nd residual prediction vector. + * past_r2q[i] Past quantized residual (2nd vector). + * + * The residual vectors r1[i] and r2[i] are jointly quantized using + * split-MQ with 5 codebooks. Each 4th dimension submatrix contains 2 + * elements from each residual vector. The 5 submatrices are as follows: + * {r1[0], r1[1], r2[0], r2[1]}; {r1[2], r1[3], r2[2], r2[3]}; + * {r1[4], r1[5], r2[4], r2[5]}; {r1[6], r1[7], r2[6], r2[7]}; + * {r1[8], r1[9], r2[8], r2[9]}; + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" +#include "sig_proc.h" + +#include "cnst.h" +#include "dtx.h" + +/* Locals functions */ + +void Lsf_wt ( + Word16 *lsf, /* input : LSF vector */ + Word16 *wf2 /* output: square of weighting factors */ +); + +Word16 Vq_subvec ( /* output: return quantization index */ + Word16 *lsf_r1, /* input : 1st LSF residual vector */ + Word16 *lsf_r2, /* input : and LSF residual vector */ + const Word16 *dico,/* input : quantization codebook */ + Word16 *wf1, /* input : 1st LSF weighting factors */ + Word16 *wf2, /* input : 2nd LSF weighting factors */ + Word16 dico_size /* input : size of quantization codebook */ +); +Word16 Vq_subvec_s ( /* output: return quantization index */ + Word16 *lsf_r1, /* input : 1st LSF residual vector */ + Word16 *lsf_r2, /* input : and LSF residual vector */ + const Word16 *dico,/* input : quantization codebook */ + Word16 *wf1, /* input : 1st LSF weighting factors */ + Word16 *wf2, /* input : 2nd LSF weighting factors */ + Word16 dico_size /* input : size of quantization codebook */ +); +/* M ->order of linear prediction filter */ +/* LSF_GAP -> Minimum distance between LSF after quantization */ +/* 50 Hz = 205 */ +/* PRED_FAC -> Predcition factor */ + +#define M 10 +#define LSF_GAP 205 +#define PRED_FAC 21299 + +#include "q_plsf_5.tab" /* Codebooks of LSF prediction residual */ + + /* Past quantized prediction error */ + +Word16 past_r2_q[M]; + +extern Word16 lsf_old_tx[DTX_HANGOVER][M]; + +void Q_plsf_5 ( + Word16 *lsp1, /* input : 1st LSP vector */ + Word16 *lsp2, /* input : 2nd LSP vector */ + Word16 *lsp1_q, /* output: quantized 1st LSP vector */ + Word16 *lsp2_q, /* output: quantized 2nd LSP vector */ + Word16 *indice, /* output: quantization indices of 5 matrices */ + Word16 txdtx_ctrl /* input : tx dtx control word */ +) +{ + Word16 i; + Word16 lsf1[M], lsf2[M], wf1[M], wf2[M], lsf_p[M], lsf_r1[M], lsf_r2[M]; + Word16 lsf1_q[M], lsf2_q[M]; + Word16 lsf_aver[M]; + static Word16 lsf_p_CN[M]; + + /* convert LSFs to normalize frequency domain 0..16384 */ + + Lsp_lsf (lsp1, lsf1, M); + Lsp_lsf (lsp2, lsf2, M); + + /* Update LSF CN quantizer "memory" */ + + logic16 (); logic16 (); test (); test (); + if ((txdtx_ctrl & TX_SP_FLAG) == 0 + && (txdtx_ctrl & TX_PREV_HANGOVER_ACTIVE) != 0) + { + update_lsf_p_CN (lsf_old_tx, lsf_p_CN); + } + logic16 (); test (); + if ((txdtx_ctrl & TX_SID_UPDATE) != 0) + { + /* New SID frame is to be sent: + Compute average of the current LSFs and the LSFs in the history */ + + aver_lsf_history (lsf_old_tx, lsf1, lsf2, lsf_aver); + } + /* Update LSF history with unquantized LSFs when no speech activity + is present */ + + logic16 (); test (); + if ((txdtx_ctrl & TX_SP_FLAG) == 0) + { + update_lsf_history (lsf1, lsf2, lsf_old_tx); + } + logic16 (); test (); + if ((txdtx_ctrl & TX_SID_UPDATE) != 0) + { + /* Compute LSF weighting factors for lsf2, using averaged LSFs */ + /* Set LSF weighting factors for lsf1 to zero */ + /* Replace lsf1 and lsf2 by the averaged LSFs */ + + Lsf_wt (lsf_aver, wf2); + for (i = 0; i < M; i++) + { + wf1[i] = 0; move16 (); + lsf1[i] = lsf_aver[i]; move16 (); + lsf2[i] = lsf_aver[i]; move16 (); + } + } + else + { + /* Compute LSF weighting factors */ + + Lsf_wt (lsf1, wf1); + Lsf_wt (lsf2, wf2); + } + + /* Compute predicted LSF and prediction error */ + + logic16 (); test (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + for (i = 0; i < M; i++) + { + lsf_p[i] = add (mean_lsf[i], mult (past_r2_q[i], PRED_FAC)); + move16 (); + lsf_r1[i] = sub (lsf1[i], lsf_p[i]); move16 (); + lsf_r2[i] = sub (lsf2[i], lsf_p[i]); move16 (); + } + } + else + { + for (i = 0; i < M; i++) + { + lsf_r1[i] = sub (lsf1[i], lsf_p_CN[i]); move16 (); + lsf_r2[i] = sub (lsf2[i], lsf_p_CN[i]); move16 (); + } + } + + /*---- Split-VQ of prediction error ----*/ + + indice[0] = Vq_subvec (&lsf_r1[0], &lsf_r2[0], dico1_lsf, + &wf1[0], &wf2[0], DICO1_SIZE); + move16 (); + + indice[1] = Vq_subvec (&lsf_r1[2], &lsf_r2[2], dico2_lsf, + &wf1[2], &wf2[2], DICO2_SIZE); + move16 (); + + indice[2] = Vq_subvec_s (&lsf_r1[4], &lsf_r2[4], dico3_lsf, + &wf1[4], &wf2[4], DICO3_SIZE); + move16 (); + + indice[3] = Vq_subvec (&lsf_r1[6], &lsf_r2[6], dico4_lsf, + &wf1[6], &wf2[6], DICO4_SIZE); + move16 (); + + indice[4] = Vq_subvec (&lsf_r1[8], &lsf_r2[8], dico5_lsf, + &wf1[8], &wf2[8], DICO5_SIZE); + move16 (); + + /* Compute quantized LSFs and update the past quantized residual */ + /* In case of no speech activity, skip computing the quantized LSFs, + and set past_r2_q to zero (initial value) */ + + logic16 (); test (); + if ((txdtx_ctrl & TX_SP_FLAG) != 0) + { + for (i = 0; i < M; i++) + { + lsf1_q[i] = add (lsf_r1[i], lsf_p[i]); move16 (); + lsf2_q[i] = add (lsf_r2[i], lsf_p[i]); move16 (); + past_r2_q[i] = lsf_r2[i]; move16 (); + } + + /* verification that LSFs has minimum distance of LSF_GAP */ + + Reorder_lsf (lsf1_q, LSF_GAP, M); + Reorder_lsf (lsf2_q, LSF_GAP, M); + + /* Update LSF history with quantized LSFs + when hangover period is active */ + + logic16 (); test (); + if ((txdtx_ctrl & TX_HANGOVER_ACTIVE) != 0) + { + update_lsf_history (lsf1_q, lsf2_q, lsf_old_tx); + } + /* convert LSFs to the cosine domain */ + + Lsf_lsp (lsf1_q, lsp1_q, M); + Lsf_lsp (lsf2_q, lsp2_q, M); + } + else + { + for (i = 0; i < M; i++) + { + past_r2_q[i] = 0; move16 (); + } + } + + return; +} + +/* Quantization of a 4 dimensional subvector */ + +Word16 Vq_subvec ( /* output: return quantization index */ + Word16 *lsf_r1, /* input : 1st LSF residual vector */ + Word16 *lsf_r2, /* input : and LSF residual vector */ + const Word16 *dico, /* input : quantization codebook */ + Word16 *wf1, /* input : 1st LSF weighting factors */ + Word16 *wf2, /* input : 2nd LSF weighting factors */ + Word16 dico_size /* input : size of quantization codebook */ +) +{ + Word16 i, index, temp; + const Word16 *p_dico; + Word32 dist_min, dist; + + dist_min = MAX_32; move32 (); + p_dico = dico; move16 (); + + for (i = 0; i < dico_size; i++) + { + temp = sub (lsf_r1[0], *p_dico++); + temp = mult (wf1[0], temp); + dist = L_mult (temp, temp); + + temp = sub (lsf_r1[1], *p_dico++); + temp = mult (wf1[1], temp); + dist = L_mac (dist, temp, temp); + + temp = sub (lsf_r2[0], *p_dico++); + temp = mult (wf2[0], temp); + dist = L_mac (dist, temp, temp); + + temp = sub (lsf_r2[1], *p_dico++); + temp = mult (wf2[1], temp); + dist = L_mac (dist, temp, temp); + + test (); + if (L_sub (dist, dist_min) < (Word32) 0) + { + dist_min = dist; move32 (); + index = i; move16 (); + } + } + + /* Reading the selected vector */ + + p_dico = &dico[shl (index, 2)]; move16 (); + lsf_r1[0] = *p_dico++; move16 (); + lsf_r1[1] = *p_dico++; move16 (); + lsf_r2[0] = *p_dico++; move16 (); + lsf_r2[1] = *p_dico++; move16 (); + + return index; + +} + +/* Quantization of a 4 dimensional subvector with a signed codebook */ + +Word16 Vq_subvec_s ( /* output: return quantization index */ + Word16 *lsf_r1, /* input : 1st LSF residual vector */ + Word16 *lsf_r2, /* input : and LSF residual vector */ + const Word16 *dico, /* input : quantization codebook */ + Word16 *wf1, /* input : 1st LSF weighting factors */ + Word16 *wf2, /* input : 2nd LSF weighting factors */ + Word16 dico_size) /* input : size of quantization codebook */ +{ + Word16 i, index, sign, temp; + const Word16 *p_dico; + Word32 dist_min, dist; + + dist_min = MAX_32; move32 (); + p_dico = dico; move16 (); + + for (i = 0; i < dico_size; i++) + { + /* test positive */ + + temp = sub (lsf_r1[0], *p_dico++); + temp = mult (wf1[0], temp); + dist = L_mult (temp, temp); + + temp = sub (lsf_r1[1], *p_dico++); + temp = mult (wf1[1], temp); + dist = L_mac (dist, temp, temp); + + temp = sub (lsf_r2[0], *p_dico++); + temp = mult (wf2[0], temp); + dist = L_mac (dist, temp, temp); + + temp = sub (lsf_r2[1], *p_dico++); + temp = mult (wf2[1], temp); + dist = L_mac (dist, temp, temp); + + test (); + if (L_sub (dist, dist_min) < (Word32) 0) + { + dist_min = dist; move32 (); + index = i; move16 (); + sign = 0; move16 (); + } + /* test negative */ + + p_dico -= 4; move16 (); + temp = add (lsf_r1[0], *p_dico++); + temp = mult (wf1[0], temp); + dist = L_mult (temp, temp); + + temp = add (lsf_r1[1], *p_dico++); + temp = mult (wf1[1], temp); + dist = L_mac (dist, temp, temp); + + temp = add (lsf_r2[0], *p_dico++); + temp = mult (wf2[0], temp); + dist = L_mac (dist, temp, temp); + + temp = add (lsf_r2[1], *p_dico++); + temp = mult (wf2[1], temp); + dist = L_mac (dist, temp, temp); + + test (); + if (L_sub (dist, dist_min) < (Word32) 0) + { + dist_min = dist; move32 (); + index = i; move16 (); + sign = 1; move16 (); + } + } + + /* Reading the selected vector */ + + p_dico = &dico[shl (index, 2)]; move16 (); + test (); + if (sign == 0) + { + lsf_r1[0] = *p_dico++; move16 (); + lsf_r1[1] = *p_dico++; move16 (); + lsf_r2[0] = *p_dico++; move16 (); + lsf_r2[1] = *p_dico++; move16 (); + } + else + { + lsf_r1[0] = negate (*p_dico++); move16 (); + lsf_r1[1] = negate (*p_dico++); move16 (); + lsf_r2[0] = negate (*p_dico++); move16 (); + lsf_r2[1] = negate (*p_dico++); move16 (); + } + + index = shl (index, 1); + index = add (index, sign); + + return index; + +} + +/**************************************************** + * FUNCTION Lsf_wt * + * * + **************************************************** + * Compute LSF weighting factors * + * * + * d[i] = lsf[i+1] - lsf[i-1] * + * * + * The weighting factors are approximated by two line segment. * + * * + * First segment passes by the following 2 points: * + * * + * d[i] = 0Hz wf[i] = 3.347 * + * d[i] = 450Hz wf[i] = 1.8 * + * * + * Second segment passes by the following 2 points: * + * * + * d[i] = 450Hz wf[i] = 1.8 * + * d[i] = 1500Hz wf[i] = 1.0 * + * * + * if( d[i] < 450Hz ) * + * wf[i] = 3.347 - ( (3.347-1.8) / (450-0)) * d[i] * + * else * + * wf[i] = 1.8 - ( (1.8-1.0) / (1500-450)) * (d[i] - 450) * + * * + * * + * if( d[i] < 1843) * + * wf[i] = 3427 - (28160*d[i])>>15 * + * else * + * wf[i] = 1843 - (6242*(d[i]-1843))>>15 * + * * + *--------------------------------------------------------------------------*/ + +void Lsf_wt ( + Word16 *lsf, /* input : LSF vector */ + Word16 *wf) /* output: square of weighting factors */ +{ + Word16 temp; + Word16 i; + /* wf[0] = lsf[1] - 0 */ + wf[0] = lsf[1]; move16 (); + for (i = 1; i < 9; i++) + { + wf[i] = sub (lsf[i + 1], lsf[i - 1]); move16 (); + } + /* wf[9] = 0.5 - lsf[8] */ + wf[9] = sub (16384, lsf[8]);move16 (); + + for (i = 0; i < 10; i++) + { + temp = sub (wf[i], 1843); + test (); + if (temp < 0) + { + wf[i] = sub (3427, mult (wf[i], 28160)); move16 (); + } + else + { + wf[i] = sub (1843, mult (temp, 6242)); move16 (); + } + + wf[i] = shl (wf[i], 3); move16 (); + } + return; +} diff -r 000000000000 -r 56410792419a src/q_plsf_5.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/q_plsf_5.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,1010 @@ +/*--------------------------------------------------------------------------* +* Quantization tables for split_MQ of 2 sets of LSFs in a 20 ms frame. * +* See "q_plsf_5.c" * +*--------------------------------------------------------------------------*/ + +/* LSF means ->normalize frequency domain */ + +static const Word16 mean_lsf[10] = +{ + 1384, + 2077, + 3420, + 5108, + 6742, + 8122, + 9863, + 11092, + 12714, + 13701 +}; + +#ifndef D_HOMING + +#define DICO1_SIZE 128 +#define DICO2_SIZE 256 +#define DICO3_SIZE 256 +#define DICO4_SIZE 256 +#define DICO5_SIZE 64 + +static const Word16 dico1_lsf[DICO1_SIZE * 4] = +{ + -451, -1065, -529, -1305, + -450, -756, -497, -863, + -384, -619, -413, -669, + -317, -538, -331, -556, + -414, -508, -424, -378, + -274, -324, -434, -614, + -226, -500, -232, -514, + -263, -377, -298, -410, + -151, -710, -174, -818, + -149, -412, -156, -429, + -288, -462, -186, -203, + -170, -302, -191, -321, + -131, -147, -297, -395, + -228, -214, -245, -192, + -67, -316, -71, -327, + -104, -205, -94, -183, + -143, -38, -193, -95, + 16, -76, -124, -248, + 23, -237, 24, -244, + 18, -136, 44, -111, + -33, -24, -25, 0, + 149, 19, 23, -143, + 158, -169, 174, -181, + 133, -55, 165, -26, + 111, 84, 98, 75, + 87, 183, -115, -11, + -8, 130, 11, 170, + 254, 77, 205, 17, + 183, 112, 262, 194, + 202, 287, 95, 189, + -42, -105, 234, 179, + 39, 186, 163, 345, + 332, 199, 299, 161, + -54, 285, -78, 281, + -133, 141, -182, 111, + 249, 341, 271, 364, + 93, 403, 75, 391, + 92, 510, -138, 220, + -185, -29, -34, 361, + -115, 320, 3, 554, + 99, 286, 218, 591, + -245, 406, -268, 453, + 0, 580, 25, 606, + 275, 532, 148, 450, + -73, 739, -285, 518, + -288, 94, -203, 674, + -140, -74, 205, 714, + -114, 299, 176, 923, + 182, 557, 240, 705, + -16, 513, 485, 593, + 293, 384, 451, 617, + -38, 50, 563, 529, + 303, 209, 459, 363, + 433, 452, 450, 454, + 367, 606, 477, 741, + 432, 353, 368, 267, + 361, 716, 273, 583, + 453, 166, 510, 172, + 201, 629, 274, 191, + 568, 639, 302, 298, + 634, 387, 643, 350, + 587, 560, 612, 565, + 600, 788, 487, 672, + 512, 1015, 321, 333, + 357, 854, -125, 413, + 474, 712, 17, -151, + 564, 285, 270, -241, + 971, 889, 489, 220, + 510, 896, 549, 924, + 327, 825, 290, 911, + 540, 1108, 158, 805, + 199, 957, 511, 730, + 100, 874, 13, 791, + 435, 632, 676, 972, + 249, 900, 467, 1218, + 781, 1074, 585, 785, + -23, 669, 267, 1043, + 619, 1084, 615, 1145, + 622, 905, 916, 1049, + 80, 331, 584, 1075, + 89, 639, 988, 961, + 770, 720, 798, 699, + 492, 447, 899, 627, + 271, 1188, 725, 1333, + 87, 603, 832, 1603, + 616, 1127, 890, 1505, + 1000, 1156, 866, 1009, + 995, 827, 1149, 858, + 817, 1450, 773, 1320, + 500, 1389, 312, 1153, + -20, 1084, 64, 1283, + 2, 1172, 399, 1869, + 514, 1706, 502, 1636, + 886, 1522, 416, 600, + 1131, 1350, 1275, 1390, + 889, 1795, 914, 1766, + 227, 1183, 1250, 1826, + 505, 1854, 919, 2353, + -199, 431, 152, 1735, + -213, -28, 392, 1334, + -153, -52, 978, 1151, + -323, -400, 813, 1703, + -136, 84, 1449, 2015, + -331, -143, -137, 1192, + -256, 534, -157, 1031, + -307, -439, 542, 731, + -329, -420, -97, 616, + -362, -168, -322, 366, + -247, -110, -211, 89, + -196, -309, 20, 59, + -364, -463, -286, 89, + -336, 175, -432, 141, + -379, -190, -434, -196, + -79, 150, -278, -227, + -280, 166, -555, -422, + -155, 541, -366, 54, + -29, -83, -301, -774, + 186, 628, -397, -264, + 242, 293, -197, -585, + 124, 410, 53, -133, + 10, 340, -570, -1065, + 65, -446, 68, -493, + 383, 937, -357, -711, + -359, -250, -677, -1068, + 292, -26, 363, 6, + 607, 1313, -127, -10, + 1513, 1886, 713, 972, + 1469, 2181, 1443, 2016 +}; + +static const Word16 dico2_lsf[DICO2_SIZE * 4] = +{ + -1631, -1600, -1796, -2290, + -1027, -1770, -1100, -2025, + -1277, -1388, -1367, -1534, + -947, -1461, -972, -1524, + -999, -1222, -1020, -1172, + -815, -987, -992, -1371, + -1216, -1006, -1289, -1094, + -744, -1268, -755, -1293, + -862, -923, -905, -984, + -678, -1051, -685, -1050, + -1087, -985, -1062, -679, + -989, -641, -1127, -976, + -762, -654, -890, -806, + -833, -1091, -706, -629, + -621, -806, -640, -812, + -775, -634, -779, -543, + -996, -565, -1075, -580, + -546, -611, -572, -619, + -760, -290, -879, -526, + -823, -462, -795, -253, + -553, -415, -589, -439, + -533, -340, -692, -935, + -505, -772, -702, -1131, + -263, -306, -971, -483, + -445, -74, -555, -548, + -614, -129, -693, -234, + -396, -246, -475, -250, + -265, -404, -376, -514, + -417, -510, -300, -313, + -334, -664, -463, -814, + -386, -704, -337, -615, + -234, -201, -233, -239, + -167, -567, -203, -619, + -147, -415, -115, -352, + -166, -750, -171, -761, + -270, -879, -264, -903, + -367, -744, 43, -475, + 14, -653, 43, -670, + 11, -448, -59, -521, + -126, -119, -155, -613, + -42, -863, -27, -931, + 136, -483, 183, -468, + 55, -298, 55, -304, + 313, -609, 313, -720, + 322, -167, 100, -541, + -3, -119, -111, -187, + 233, -236, 260, -234, + 26, -165, 134, -45, + -40, -549, 360, -203, + 378, -388, 450, -383, + 275, 20, 182, -103, + 246, -111, 431, 37, + 462, -146, 487, -157, + -284, -59, 503, -184, + 24, 53, -3, 54, + 122, 259, 333, 66, + 484, 104, 436, 68, + 195, 116, 190, 206, + 269, -9, 482, 352, + 382, 285, 399, 277, + 452, 256, 69, 186, + 13, 297, -13, 259, + -95, 30, 56, 394, + 196, 425, 205, 456, + 281, 577, 15, 191, + 375, 290, 407, 576, + -56, 227, 544, 405, + 0, 549, -92, 528, + -229, 351, -245, 338, + -362, 435, 167, 527, + -75, 302, 91, 824, + 129, 599, 496, 679, + 186, 749, 153, 737, + -281, 600, -348, 615, + -236, 769, 41, 881, + 38, 890, -220, 841, + -357, 883, -393, 903, + -634, 474, -444, 850, + -175, 678, -493, 242, + -519, 785, -714, 582, + -541, 366, -543, 434, + -597, 500, -765, 222, + -702, 917, -743, 962, + -869, 501, -899, 548, + -379, 200, -435, 157, + -819, 214, -861, 157, + -614, 40, -632, 94, + -883, -54, -741, 516, + -501, 298, -614, -171, + -870, -161, -865, -23, + -818, 93, -1015, -267, + -662, -359, -549, 2, + -442, -121, -377, 0, + -227, 33, -414, -126, + -129, 212, -934, 34, + -1082, -282, -1119, -268, + -710, -825, -420, -191, + -1076, -928, -917, -93, + -628, -358, 97, 7, + -206, -393, -101, 24, + -203, 38, -168, 83, + -599, -423, -279, 426, + -700, 118, -75, 206, + -981, -673, -680, 417, + -367, 37, -279, 474, + -129, -318, 319, 296, + -626, -39, 343, 602, + -696, -39, -303, 940, + 104, 233, -380, 137, + -36, 269, -75, -214, + 120, 43, -529, -477, + 459, 164, -202, -229, + -49, -167, 609, 792, + 98, -220, 915, 148, + 293, 283, 869, 91, + 575, 394, 326, -78, + 717, 67, 365, -323, + 616, -36, 731, 27, + 619, 238, 632, 273, + 448, 99, 801, 476, + 869, 273, 685, 64, + 789, 72, 1021, 217, + 793, 459, 734, 360, + 646, 480, 360, 322, + 429, 464, 638, 430, + 756, 363, 1000, 404, + 683, 528, 602, 615, + 655, 413, 946, 687, + 937, 602, 904, 604, + 555, 737, 786, 662, + 467, 654, 362, 589, + 929, 710, 498, 478, + 415, 420, 693, 883, + 813, 683, 781, 925, + 913, 939, 726, 732, + 491, 853, 531, 948, + 734, 963, 315, 808, + 761, 755, 1144, 760, + 655, 1076, 826, 1057, + 1091, 838, 1003, 808, + 1047, 1133, 659, 1101, + 992, 1050, 1074, 1075, + 971, 694, 1226, 1054, + 571, 841, 884, 1404, + 1379, 1096, 1080, 861, + 1231, 735, 1284, 760, + 1272, 991, 1367, 1053, + 1257, 700, 1050, 534, + 988, 453, 1264, 599, + 1140, 679, 1621, 815, + 1384, 521, 1317, 393, + 1564, 805, 1448, 686, + 1068, 648, 875, 307, + 1083, 361, 1047, 317, + 1417, 964, 675, 571, + 1152, 79, 1114, -47, + 1530, 311, 1721, 314, + 1166, 689, 514, -94, + 349, 282, 1412, 328, + 1025, 487, -65, 57, + 805, 970, 36, 62, + 769, -263, 791, -346, + 637, 699, -137, 620, + 534, 541, -735, 194, + 711, 300, -268, -863, + 926, 769, -708, -428, + 506, 174, -892, -630, + 435, 547, -1435, -258, + 621, 471, -1018, -1368, + -393, 521, -920, -686, + -25, 20, -982, -1156, + 340, 9, -1558, -1135, + -352, 48, -1579, -402, + -887, 6, -1156, -888, + -548, -352, -1643, -1168, + -159, 610, -2024, -963, + -225, 193, -1656, -1960, + -245, -493, -964, -1680, + -936, -635, -1299, -1744, + -1388, -604, -1540, -835, + -1397, -135, -1588, -290, + -1670, -712, -2011, -1632, + -1663, -27, -2258, -811, + -1157, 184, -1265, 189, + -1367, 586, -2011, 201, + -790, 712, -1210, 3, + -1033, 808, -1251, 830, + -111, 635, -1636, 447, + -463, -949, -445, -928, + -504, -1162, -501, -1211, + 144, -351, -372, -1052, + -283, -1059, -279, -1123, + -575, -1438, -587, -1614, + -935, -984, 229, 690, + -921, -719, -403, 1362, + -685, -465, 874, 397, + -509, -46, 317, 1334, + -485, 456, 813, 439, + -411, 339, 898, 1067, + -425, 46, 1441, 497, + -909, -800, 1465, 1046, + -254, -321, 1430, 1165, + 68, 350, 1034, 666, + 370, 11, 1311, 790, + 143, 232, 1041, 1562, + -114, 663, 1616, 1078, + 454, 579, 1275, 1040, + -76, 909, 752, 1067, + 153, 512, 348, 1214, + 614, 385, 1843, 808, + 269, 1034, 203, 1086, + 652, 1017, 1783, 1130, + 429, 1327, 387, 1384, + -49, 1183, -72, 1215, + -416, 1001, 544, 1749, + -352, 1223, -502, 1199, + -589, 569, -227, 1630, + -142, 1578, -230, 1715, + -714, 1288, -838, 1398, + 1131, 1357, -208, 1232, + 437, 965, -929, 818, + 811, 1410, 859, 1507, + 164, 1212, 1387, 1793, + 484, 1874, 456, 2063, + 996, 1170, 1326, 1402, + 1316, 1360, 1135, 1262, + 1234, 1618, 1361, 1768, + 1421, 1227, 1584, 1347, + 854, 672, 1685, 1566, + 1139, 1270, 2016, 1825, + 1773, 1581, 1532, 1460, + 1487, 946, 1659, 1021, + 1744, 1212, 1392, 977, + 1772, 1161, 1826, 1164, + 1718, 1429, 1973, 1591, + 1185, 864, 2132, 1061, + 1799, 814, 1838, 757, + 2104, 1315, 2054, 1258, + 2113, 915, 2331, 930, + 1467, 1147, 2590, 1439, + 2245, 1744, 2090, 1620, + 2358, 1454, 2666, 1506, + 1876, 1837, 2070, 1975, + 1739, 1577, 682, 1289, + 1584, 2045, 1454, 2098, + 2498, 2004, 2711, 2066, + 726, 1588, 2756, 2336, + 228, 847, 2456, 1659, + 36, 301, 1942, 1957, + -446, -96, 2154, 1396, + 1533, 1101, 14, 608, + -923, -732, 1383, 1982, + 1345, 952, -680, 321, + 1281, 1268, -1594, 365, + 941, 946, -1737, -822, + 2374, 2787, 1821, 2788 +}; + +static const Word16 dico3_lsf[DICO3_SIZE * 4] = +{ + -1812, -2275, -1879, -2537, + -1640, -1848, -1695, -2004, + -1220, -1912, -1221, -2106, + -1559, -1588, -1573, -1556, + -1195, -1615, -1224, -1727, + -1359, -1151, -1616, -1948, + -1274, -1391, -1305, -1403, + -1607, -1179, -1676, -1311, + -1443, -1478, -1367, -898, + -1256, -1059, -1331, -1134, + -982, -1133, -1149, -1504, + -1080, -1308, -1020, -1183, + -980, -1486, -967, -1495, + -988, -922, -1047, -1077, + -838, -1179, -858, -1222, + -1131, -1041, -1064, -767, + -872, -1157, -701, -880, + -706, -906, -774, -1016, + -578, -1080, -801, -1478, + -591, -1111, -592, -1146, + -713, -1388, -640, -1376, + -597, -1059, -416, -903, + -686, -832, -661, -708, + -444, -868, -490, -921, + -374, -776, -619, -1170, + -585, -549, -769, -795, + -435, -659, -530, -741, + -498, -837, -357, -597, + -279, -871, -243, -887, + -282, -665, -280, -667, + -165, -560, -394, -903, + -362, -410, -448, -583, + -409, -574, -313, -357, + -637, -548, -570, -436, + -896, -504, -382, -757, + -58, -481, -165, -618, + -191, -374, -234, -382, + -222, -683, -25, -480, + -418, -359, -730, -353, + -324, -157, -432, -322, + -394, -303, -284, -104, + -601, -289, -556, -196, + -588, -150, -659, -608, + -473, -24, -68, -448, + -474, -8, -506, -45, + -748, -184, -844, -252, + -901, -91, -584, -97, + -652, 138, -764, -131, + -678, -12, -670, 165, + -259, -3, -840, -107, + -909, 37, -992, 44, + -854, -415, -839, 13, + -1001, -271, -1026, -309, + -798, -478, -832, -488, + -943, 168, -1112, -387, + -1185, -101, -1183, -40, + -941, -316, -1030, -770, + -1044, -625, -1081, -538, + -1224, -299, -1312, -436, + -1197, -663, -1167, -161, + -1216, -690, -1237, -831, + -1432, -720, -1403, -493, + -898, -740, -922, -801, + -1102, -402, -1579, -964, + -1061, -638, -1269, -1438, + -1499, -934, -1502, -895, + -1598, -564, -1723, -717, + -606, -597, -1166, -1085, + -1369, -468, -1946, -1493, + -1838, -953, -1932, -931, + -1499, -188, -1635, -421, + -1457, -338, -1448, -22, + -1942, -422, -2006, -249, + -496, -114, -1910, -755, + -1289, 174, -1451, -109, + -482, -257, -1221, -508, + -1617, 151, -1694, 208, + -654, 107, -1651, 29, + -1141, 279, -1215, 306, + -1228, -506, -730, -175, + -1236, -101, -969, 551, + -870, 278, -823, 315, + -563, 376, -1051, 228, + -507, 280, -599, 281, + -758, 253, -305, 379, + -755, -134, -611, 660, + -824, 536, -817, 646, + -413, 49, -341, 177, + -453, 526, -482, 589, + -71, 339, -657, 264, + -244, 295, -237, 315, + -387, 569, -506, -9, + -377, 14, -160, 661, + -216, 40, -308, -46, + 95, 214, -242, 167, + -86, 192, -56, 27, + -76, 31, 36, 309, + -106, -182, -113, 74, + -441, -22, 23, 139, + 81, -11, 44, 15, + -87, -137, -118, -207, + -158, -58, 272, -92, + -156, -441, 8, -136, + 128, -221, 101, -218, + 40, -197, -76, -456, + 9, -445, 33, -423, + 226, 60, 73, -222, + 156, -399, 280, -318, + 245, -341, 166, -499, + 339, -190, 327, -219, + 325, -137, -89, -596, + 100, -627, 144, -677, + 487, 28, 252, -391, + 214, -41, 282, -28, + 99, -286, 331, 49, + 459, -388, 565, -369, + 436, 28, 336, -9, + 397, -167, 618, 34, + 596, -17, 561, -140, + 299, 79, 522, 125, + 203, 2, 244, 288, + 255, 211, 175, 82, + 596, 187, 517, 108, + 381, 255, 365, 297, + 497, 352, 327, -82, + 25, 210, 371, 245, + 261, 3, 545, 449, + 140, 294, 44, 295, + 212, 347, 244, 494, + 331, 528, 201, 307, + 349, 411, 613, 284, + 614, 413, 464, 322, + 624, 397, 97, 200, + -160, 384, 149, 362, + 495, 525, 269, 585, + 33, 491, -121, 433, + 427, 611, 498, 516, + 171, 443, 497, 666, + 440, 275, 566, 575, + 146, 639, 155, 670, + -33, 173, 212, 696, + -166, 601, -191, 695, + -489, 503, 175, 742, + 214, 476, 372, 1083, + 578, 530, 586, 777, + 425, 874, 315, 841, + 374, 848, -165, 565, + 35, 991, -39, 1062, + 329, 712, 786, 840, + 645, 795, 661, 676, + 571, 918, 632, 1079, + 673, 817, 318, 388, + 874, 1012, 564, 848, + 880, 620, 557, 479, + 671, 453, 692, 468, + 840, 642, 844, 645, + 506, 428, 897, 567, + 837, 387, 962, 499, + 691, 561, 939, 926, + 783, 296, 790, 268, + 1028, 530, 874, 329, + 548, 143, 675, 291, + 503, 66, 1041, 359, + 786, 97, 805, 33, + 837, 470, 511, 49, + 1092, 327, 1174, 323, + 3, 242, 872, 474, + 689, 429, 1329, 678, + 1042, 620, 1109, 664, + 321, 193, 889, 950, + 1153, 874, 893, 635, + 877, 862, 948, 913, + 1293, 665, 1320, 639, + 997, 793, 1402, 1030, + 1176, 1012, 1110, 959, + 1410, 925, 1403, 915, + 543, 862, 1116, 1222, + 835, 1190, 835, 1190, + 959, 1148, 1147, 1376, + 1300, 1193, 1415, 1231, + 1335, 1341, 746, 1092, + 1711, 1283, 1389, 1073, + 1334, 1566, 1153, 1475, + 1645, 1137, 1825, 1220, + 1056, 1382, 1521, 1730, + 1632, 1545, 1620, 1542, + 855, 1596, 865, 1667, + 693, 885, 1716, 1519, + 1167, 1296, 2209, 1760, + 1952, 1493, 2020, 1482, + 1534, 1866, 1694, 2008, + 1566, 748, 1761, 825, + 294, 1392, 1084, 2058, + 621, 1315, 365, 1287, + 198, 1028, 488, 1408, + 249, 403, 1014, 1561, + 324, 363, 1645, 1044, + 193, 367, 2034, 1859, + -251, 579, 750, 994, + -243, 30, 1325, 879, + -28, -169, 624, 917, + -453, 159, 186, 1370, + -614, 6, 537, 392, + -94, -291, 781, 229, + -128, -298, 245, 491, + -701, -648, 972, 789, + -501, -640, 178, 255, + -365, -390, -255, 317, + -958, -294, -191, 228, + -775, -447, 157, -237, + -657, -720, -407, 92, + -117, -611, 334, -230, + -679, -1084, -144, -317, + -901, -861, -738, -360, + -85, -727, -90, -787, + 100, -22, -391, -263, + -56, -73, -337, -754, + 5, -189, -706, -624, + 89, -344, -135, -1113, + -353, -237, -684, -1135, + -275, -1102, -269, -1203, + 152, 145, -722, -1232, + 49, 80, -1248, -776, + -248, 391, -732, -547, + 469, 218, -255, -864, + 69, 366, -166, -485, + -688, 191, -1212, -1196, + -170, -169, -1308, -1631, + 321, 470, -1419, -1243, + -64, 272, -1361, -248, + 492, 565, -721, -609, + 195, 485, -573, -133, + 427, 202, -171, -118, + 199, 575, 2, -31, + 694, 755, -1366, -39, + 552, 557, -489, 271, + 680, 537, 13, -453, + 855, 954, -133, -52, + -81, 738, -1169, 637, + 1055, 1059, -95, 676, + 1259, 1081, 489, 305, + -449, 954, -534, 996, + -969, 866, -1058, 1059, + -1294, 618, -1416, 617, + -458, 1366, -159, 1821, + -774, -528, -14, 1110, + -1202, -901, -772, 433, + -1256, -1255, -1011, -302, + -602, -585, -759, -1618, + -760, -1549, -840, -1921, + -816, -539, -1769, -2235, + -227, -36, -2034, -1831, + -2107, -1126, -2471, -1816, + -1470, 252, -2701, -415, + -571, -467, 1509, 1554, + 2180, 1975, 2326, 2020 +}; + +static const Word16 dico4_lsf[DICO4_SIZE * 4] = +{ + -1857, -1681, -1857, -1755, + -2056, -1150, -2134, -1654, + -1619, -1099, -1704, -1131, + -1345, -1608, -1359, -1638, + -1338, -1293, -1325, -1265, + -1664, -1649, -1487, -851, + -1346, -1832, -1413, -2188, + -1282, -681, -1785, -1649, + -966, -1082, -1183, -1676, + -1054, -1073, -1142, -1158, + -1207, -744, -1274, -997, + -934, -1383, -927, -1416, + -1010, -1305, -783, -955, + -1049, -900, -993, -817, + -737, -823, -972, -1189, + -738, -1094, -738, -1154, + -784, -801, -810, -786, + -892, -520, -1000, -818, + -644, -965, -577, -882, + -541, -694, -671, -917, + -595, -642, -646, -615, + -956, -621, -925, -515, + -727, -483, -815, -485, + -840, -578, -440, -713, + -578, -325, -657, -670, + -386, -570, -441, -666, + -514, -787, -392, -529, + -522, -453, -487, -423, + -616, -585, -617, -157, + -662, -268, -680, -348, + -322, -323, -632, -444, + -304, -430, -332, -458, + -277, -468, -659, -793, + -319, -636, -227, -554, + -373, -347, -334, -210, + -456, -192, -530, -242, + -216, -198, -366, -370, + -338, -161, -409, -748, + -107, -380, -294, -643, + -223, -665, -234, -741, + -141, -496, -130, -510, + -139, -327, -172, -305, + -306, -580, -164, -263, + -262, -172, -67, -402, + 31, -366, -10, -436, + -86, -527, 71, -377, + -22, -609, -12, -678, + -67, -319, 63, -191, + 35, -181, -39, -242, + 126, -167, -140, -544, + 155, -297, 174, -297, + 38, -8, 117, -380, + 197, -452, 240, -522, + 223, -103, 110, -187, + 87, -155, 169, -47, + 157, 26, -83, -100, + 128, 80, 209, -62, + 6, 7, 22, 5, + 318, -20, 248, -45, + -200, -63, 156, -69, + 250, -183, 369, -126, + -113, -76, -142, -122, + -64, -254, -31, 35, + -177, -71, -7, 171, + 93, 27, 108, 212, + -330, -209, -123, -70, + -279, 95, -96, 20, + -188, -61, -314, 87, + -300, -78, -354, -134, + 11, 122, -140, 122, + -275, 152, -293, 140, + -82, 138, -321, -111, + -480, -156, -359, 76, + -254, -40, -635, -96, + -522, 79, -507, 8, + -268, 303, -539, 68, + -446, 61, -522, 306, + 111, 189, -435, 122, + -379, 166, -571, -398, + -632, -74, -747, -95, + -455, 194, -952, 83, + -798, 192, -755, 192, + -781, -162, -619, 234, + -663, -297, -488, -109, + -964, -132, -838, -68, + -843, 58, -1112, -86, + -805, -299, -944, -253, + -778, -50, -965, -549, + -352, -98, -992, -343, + -1117, -315, -1117, -307, + -1155, -374, -637, -230, + -1166, -43, -1299, -100, + -925, -393, -1274, -600, + -689, -130, -1479, -312, + -1321, -254, -1464, -442, + -1292, -613, -1261, -503, + -1501, -368, -1322, 26, + -1432, -66, -1743, -161, + -1644, -467, -1760, -548, + -1393, -568, -1556, -871, + -1495, -1034, -1387, -571, + -1917, -528, -1783, -123, + -1897, -231, -2054, -323, + -2052, -906, -1976, -567, + -1917, -620, -2047, -989, + -1077, -370, -2031, -704, + -2355, -749, -2740, -1089, + -1909, 159, -2012, 248, + -626, -123, -2339, -962, + -669, -408, -1379, -1174, + -452, -364, -1044, -735, + -132, 183, -1620, -752, + -547, -307, -777, -1261, + -98, 41, -880, -1091, + -257, 97, -1602, -1833, + 31, -26, -644, -561, + -180, -546, -385, -1095, + -410, -802, -414, -827, + -457, -970, -490, -1109, + -215, -916, -144, -937, + -493, -1269, -517, -1507, + 181, 101, -332, -889, + -836, -937, -559, -429, + -629, -547, -183, -337, + -545, -82, -250, -286, + 5, -132, -348, -252, + -293, -472, -158, 100, + -29, 197, -236, -424, + -861, -213, -140, -7, + -427, -443, 187, -97, + -684, -736, -293, 258, + -368, -152, -150, 392, + -609, 175, -142, 299, + -138, 152, -119, 329, + -486, -52, 293, 198, + -183, 117, 175, 331, + -58, -274, 231, 300, + -288, 330, -305, 372, + -111, 409, -9, 423, + 83, 256, 67, 367, + -19, 248, 91, 113, + -35, 406, -191, 154, + 238, 296, 5, 197, + 141, 221, 313, 198, + 211, 421, 244, 334, + 88, 426, -243, 454, + 202, 552, -5, 403, + 291, 185, 219, 301, + 251, 138, 128, 69, + 197, 288, -140, -61, + 188, 361, 197, 598, + 442, 273, 290, 143, + 472, 482, 157, 370, + 415, 321, 372, 385, + 402, 552, 155, 24, + 550, 263, -11, 21, + 360, 227, 147, -254, + 424, 97, 366, -13, + 375, 141, 449, 232, + 396, 507, 474, 272, + 701, 324, 362, -47, + 587, 148, 543, 69, + 400, -51, 561, 59, + 220, -10, 352, 147, + 206, 211, 653, 185, + 563, 297, 565, 284, + 594, 121, 766, 192, + 398, 118, 642, 434, + 233, 264, 481, 467, + 129, -165, 699, 239, + 90, 26, 342, 474, + -55, 27, 388, 94, + -172, 0, 725, 379, + -60, 337, 370, 465, + 95, 319, 806, 595, + 78, 260, 497, 851, + 210, 560, 458, 574, + -464, 202, 497, 625, + -202, 152, 48, 712, + -20, 566, 100, 715, + 455, 468, 411, 605, + 319, 646, 195, 615, + 401, 538, 680, 739, + 201, 667, 434, 954, + 454, 425, 646, 491, + 606, 681, 416, 508, + 497, 822, 426, 815, + 660, 647, 628, 716, + 697, 466, 618, 457, + 685, 460, 365, 309, + 721, 567, 836, 601, + 609, 300, 825, 459, + 943, 687, 681, 533, + 915, 598, 591, 243, + 876, 451, 874, 420, + 786, 317, 732, 220, + 922, 317, 1108, 367, + 531, 466, 1028, 649, + 1053, 615, 1034, 553, + 829, 602, 1021, 799, + 927, 803, 878, 763, + 799, 496, 1373, 773, + 585, 770, 803, 930, + 1099, 793, 1222, 862, + 1209, 895, 1025, 727, + 772, 845, 1172, 1115, + 867, 1021, 830, 1013, + 841, 910, 506, 703, + 1239, 1077, 620, 819, + 1196, 1083, 1155, 1081, + 1142, 907, 1547, 1121, + 1309, 648, 1343, 612, + 1484, 988, 1479, 937, + 985, 1328, 955, 1341, + 429, 910, 841, 1338, + 564, 1179, 412, 1156, + 1427, 1320, 1434, 1330, + 640, 760, 1726, 1410, + 190, 555, 1073, 1005, + 426, 257, 839, 980, + 235, 231, 1520, 1167, + 109, 293, 1014, 1569, + 305, 142, 1148, 539, + -291, -108, 1213, 972, + 22, -216, 667, 828, + -482, 438, 453, 1431, + -581, -422, 789, 387, + -358, -454, 174, 780, + -36, -372, 390, -134, + -629, 160, -306, 751, + -1258, -331, 177, 522, + -248, 574, -251, 639, + -531, 407, -596, 394, + -419, 789, -617, 801, + -986, 399, -857, 727, + -7, 518, -703, 310, + -1143, -24, -1002, 287, + -960, 363, -1299, 312, + -1534, 245, -1557, 305, + 28, 153, -859, -175, + -33, 332, -1398, -154, + 212, 410, -593, -197, + -1092, -704, -904, -65, + 282, 367, -918, -686, + 345, 93, -258, -357, + 696, 644, -693, -28, + 448, 493, -273, 193, + 527, 546, -243, -513, + 384, -136, 273, -353, + 512, -142, 537, -198, + 941, 750, 83, 248, + 578, 861, -56, 592, + 842, 44, 892, 24, + 33, 890, -16, 982, + 831, 1398, 1535, 1898, + 1716, 1376, 1948, 1465 +}; + +static const Word16 dico5_lsf[DICO5_SIZE * 4] = +{ + -1002, -929, -1096, -1203, + -641, -931, -604, -961, + -779, -673, -835, -788, + -416, -664, -458, -766, + -652, -521, -662, -495, + -1023, -509, -1023, -428, + -444, -552, -368, -449, + -479, -211, -1054, -903, + -316, -249, -569, -591, + -569, -275, -541, -191, + -716, -188, -842, -264, + -333, -248, -318, -228, + -275, 1, -567, -228, + -115, -221, -238, -374, + -197, -507, -222, -579, + -258, -432, -61, -244, + -345, 2, -338, 39, + -215, -169, -58, 0, + -56, -6, -203, -131, + 1, -186, -5, -211, + 6, -380, 11, -418, + -116, 131, -134, 113, + 89, -4, 71, -2, + -19, -192, 262, 24, + 189, 151, -133, -109, + 186, -153, 166, -219, + 37, 139, 193, 171, + 337, 124, 158, -61, + 141, 226, -13, 190, + 231, 34, 354, 109, + 316, 201, 244, 164, + 330, -85, 390, -84, + 254, 327, 257, 335, + 491, 147, 476, 105, + 54, 77, 437, 370, + 421, 314, 449, 342, + 329, 126, 673, 292, + 571, 388, 243, 193, + 653, 320, 621, 280, + 194, 380, 517, 581, + 45, 323, 111, 422, + 489, 395, 734, 534, + 622, 546, 486, 502, + 318, 572, 189, 550, + 385, 422, -157, 153, + -125, 382, -197, 386, + -263, 334, 228, 697, + -188, 1, 51, 297, + -507, 213, -376, 397, + -24, 255, -547, 89, + -502, -94, 387, 179, + -620, 68, -684, 112, + -642, -350, -260, 172, + -438, -324, 264, 648, + -964, -4, -1121, 7, + -134, 134, -1133, -306, + 143, 96, -420, -497, + -1221, -350, -1527, -685, + -161, 72, 873, 691, + 732, 283, 921, 353, + 334, 475, 1095, 821, + 864, 524, 843, 497, + 714, 711, 788, 750, + 1076, 714, 1204, 753 +}; + +#endif diff -r 000000000000 -r 56410792419a src/reorder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/reorder.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,34 @@ +/************************************************************************* + * + * FUNCTION: Reorder_lsf() + * + * PURPOSE: To make sure that the LSFs are properly ordered and to keep a + * certain minimum distance between adjacent LSFs. * + * The LSFs are in the frequency range 0-0.5 and represented in Q15 + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +void Reorder_lsf ( + Word16 *lsf, /* (i/o) : vector of LSFs (range: 0<=val<=0.5) */ + Word16 min_dist, /* (i) : minimum required distance */ + Word16 n /* (i) : LPC order */ +) +{ + Word16 i; + Word16 lsf_min; + + lsf_min = min_dist; move16 (); + for (i = 0; i < n; i++) + { + test (); + if (sub (lsf[i], lsf_min) < 0) + { + lsf[i] = lsf_min; move16 (); + } + lsf_min = add (lsf[i], min_dist); + } +} diff -r 000000000000 -r 56410792419a src/residu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/residu.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,41 @@ +/************************************************************************* + * + * FUNCTION: Residu + * + * PURPOSE: Computes the LP residual. + * + * DESCRIPTION: + * The LP residual is computed by filtering the input speech through + * the LP inverse filter A(z). + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +/* m = LPC order == 10 */ +#define m 10 + +void Residu ( + Word16 a[], /* (i) : prediction coefficients */ + Word16 x[], /* (i) : speech signal */ + Word16 y[], /* (o) : residual signal */ + Word16 lg /* (i) : size of filtering */ +) +{ + Word16 i, j; + Word32 s; + + for (i = 0; i < lg; i++) + { + s = L_mult (x[i], a[0]); + for (j = 1; j <= m; j++) + { + s = L_mac (s, a[j], x[i - j]); + } + s = L_shl (s, 3); + y[i] = round (s); move16 (); + } + return; +} diff -r 000000000000 -r 56410792419a src/set_zero.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/set_zero.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,26 @@ +/************************************************************************* + * + * FUNCTION: Set zero() + * + * PURPOSE: Set vector x[] to zero + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +void Set_zero ( + Word16 x[], /* (o) : vector to clear */ + Word16 L /* (i) : length of vector */ +) +{ + Word16 i; + + for (i = 0; i < L; i++) + { + x[i] = 0; move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/sig_proc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sig_proc.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,126 @@ +/*--------------------------------------------------------------* +* Function prototypes for general SIGnal PROCessing functions. * +*--------------------------------------------------------------*/ + +/* Mathematic functions */ + +Word32 Inv_sqrt ( /* (o) : output value (range: 0<=val<1) */ + Word32 L_x /* (i) : input value (range: 0<=val<=7fffffff) */ +); +void Log2 ( + Word32 L_x, /* (i) : input value */ + Word16 *exponent, /* (o) : Integer part of Log2. (range: 0<=val<=30) */ + Word16 *fraction /* (o) : Fractional part of Log2. (range: 0<=val<1)*/ +); +Word32 Pow2 ( /* (o) : result (range: 0<=val<=0x7fffffff) */ + Word16 exponent, /* (i) : Integer part. (range: 0<=val<=30) */ + Word16 fraction /* (i) : Fractional part. (range: 0.0<=val<1.0) */ +); + +/* General signal processing */ + +void Init_Pre_Process (void); +void Pre_Process ( + Word16 signal[], /* Input/output signal */ + Word16 lg /* Lenght of signal */ +); + +Word16 Autocorr ( + Word16 x[], /* (i) : Input signal */ + Word16 m, /* (i) : LPC order */ + Word16 r_h[], /* (o) : Autocorrelations (msb) */ + Word16 r_l[], /* (o) : Autocorrelations (lsb) */ + const Word16 wind[]/* (i) : window for LPC analysis. */ +); +void Lag_window ( + Word16 m, /* (i) : LPC order */ + Word16 r_h[], /* (i/o) : Autocorrelations (msb) */ + Word16 r_l[] /* (i/o) : Autocorrelations (lsb) */ +); +void Levinson ( + Word16 Rh[], /* (i) : Rh[m+1] Vector of autocorrelations (msb) */ + Word16 Rl[], /* (i) : Rl[m+1] Vector of autocorrelations (lsb) */ + Word16 A[], /* (o) : A[m] LPC coefficients (m = 10) */ + Word16 rc[] /* (o) : rc[4] First 4 reflection coefficients */ +); +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) */ +); +void Lsp_Az ( + Word16 lsp[], /* (i) : line spectral frequencies */ + Word16 a[] /* (o) : predictor coefficients (order = 10) */ +); +void Lsf_lsp ( + Word16 lsf[], /* (i) : lsf[m] normalized (range: 0.0<=val<=0.5) */ + Word16 lsp[], /* (o) : lsp[m] (range: -1<=val<1) */ + Word16 m /* (i) : LPC order */ +); +void Lsp_lsf ( + Word16 lsp[], /* (i) : lsp[m] (range: -1<=val<1) */ + Word16 lsf[], /* (o) : lsf[m] normalized (range: 0.0<=val<=0.5) */ + Word16 m /* (i) : LPC order */ +); +void Reorder_lsf ( + Word16 *lsf, /* (i/o) : vector of LSFs (range: 0<=val<=0.5) */ + Word16 min_dist, /* (i) : minimum required distance */ + Word16 n /* (i) : LPC order */ +); +void Weight_Fac ( + Word16 gamma, /* (i) : Spectral expansion. */ + Word16 fac[] /* (i/o) : Computed factors. */ +); +void Weight_Ai ( + Word16 a[], /* (i) : a[m+1] LPC coefficients (m=10) */ + const Word16 fac[],/* (i) : Spectral expansion factors. */ + Word16 a_exp[] /* (o) : Spectral expanded LPC coefficients */ +); +void Residu ( + Word16 a[], /* (i) : prediction coefficients */ + Word16 x[], /* (i) : speech signal */ + Word16 y[], /* (o) : residual signal */ + Word16 lg /* (i) : size of filtering */ +); +void Syn_filt ( + Word16 a[], /* (i) : a[m+1] prediction coefficients (m=10) */ + Word16 x[], /* (i) : input signal */ + Word16 y[], /* (o) : output signal */ + Word16 lg, /* (i) : size of filtering */ + Word16 mem[], /* (i/o): memory associated with this filtering. */ + Word16 update /* (i) : 0=no update, 1=update of memory. */ +); +void Convolve ( + Word16 x[], /* (i) : input vector */ + Word16 h[], /* (i) : impulse response */ + Word16 y[], /* (o) : output vector */ + Word16 L /* (i) : vector size */ +); +void agc ( + Word16 *sig_in, /* (i) : postfilter input signal */ + Word16 *sig_out, /* (i/o): postfilter output signal */ + Word16 agc_fac, /* (i) : AGC factor */ + Word16 l_trm /* (i) : subframe size */ +); +void agc2 ( + Word16 *sig_in, /* (i) : postfilter input signal */ + Word16 *sig_out, /* (i/o): postfilter output signal */ + Word16 l_trm /* (i) : subframe size */ +); +void preemphasis ( + Word16 *signal, /* (i/o): input signal overwritten by the output */ + Word16 g, /* (i) : preemphasis coefficient */ + Word16 L /* (i) : size of filtering */ +); + +/* General */ + +void Copy ( + Word16 x[], /* (i) : input vector */ + Word16 y[], /* (o) : output vector */ + Word16 L /* (i) : vector length */ +); +void Set_zero ( + Word16 x[], /* (o) : vector to clear */ + Word16 L /* (i) : length of vector */ +); diff -r 000000000000 -r 56410792419a src/syn_filt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/syn_filt.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,68 @@ +/************************************************************************* + * + * FUNCTION: Syn_filt: + * + * PURPOSE: Perform synthesis filtering through 1/A(z). + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +/* m = LPC order == 10 */ +#define m 10 + +void Syn_filt ( + Word16 a[], /* (i) : a[m+1] prediction coefficients (m=10) */ + Word16 x[], /* (i) : input signal */ + Word16 y[], /* (o) : output signal */ + Word16 lg, /* (i) : size of filtering */ + Word16 mem[], /* (i/o) : memory associated with this filtering. */ + Word16 update /* (i) : 0=no update, 1=update of memory. */ +) +{ + Word16 i, j; + Word32 s; + Word16 tmp[80]; /* This is usually done by memory allocation (lg+m) */ + Word16 *yy; + + /* Copy mem[] to yy[] */ + + yy = tmp; move16 (); + + for (i = 0; i < m; i++) + { + *yy++ = mem[i]; move16 (); + } + + /* Do the filtering. */ + + for (i = 0; i < lg; i++) + { + s = L_mult (x[i], a[0]); + for (j = 1; j <= m; j++) + { + s = L_msu (s, a[j], yy[-j]); + } + s = L_shl (s, 3); + *yy++ = round (s); move16 (); + } + + for (i = 0; i < lg; i++) + { + y[i] = tmp[i + m]; move16 (); + } + + /* Update of memory if update==1 */ + + test (); + if (update != 0) + { + for (i = 0; i < m; i++) + { + mem[i] = y[lg - m + i]; move16 (); + } + } + return; +} diff -r 000000000000 -r 56410792419a src/typedef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/typedef.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,22 @@ +/*_____________________ + | | + | Basic types. | + |_____________________| +*/ + +#if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__ZTC__) +typedef short Word16; +typedef long Word32; +typedef int Flag; + +#elif defined(__sun) +typedef short Word16; +typedef long Word32; +typedef int Flag; + +#elif defined(__unix__) || defined(__unix) +typedef short Word16; +typedef int Word32; +typedef int Flag; + +#endif diff -r 000000000000 -r 56410792419a src/vad.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vad.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,1223 @@ +/*************************************************************************** + * + * File Name: vad.c + * + * Purpose: Contains all functions for voice activity detection, as + * described in the high level specification of VAD. + * + * Below is a listing of all the functions appearing in the file. + * The functions are arranged according to their purpose. Under + * each heading, the ordering is hierarchical. + * + * Resetting of static variables of VAD: + * reset_vad() + * + * Main routine of VAD (called by the speech encoder): + * vad_computation() + * Adaptive filtering and energy computation: + * energy_computation() + * Averaging of autocorrelation function values: + * acf_averaging() + * Computation of predictor values: + * predictor_values() + * schur_recursion() + * step_up() + * compute_rav1() + * Spectral comparison: + * spectral_comparison() + * Information tone detection: + * tone_detection() + * step_up() + * Threshold adaptation: + * threshold_adaptation() + * VAD decision: + * vad_decision() + * VAD hangover addition: + * vad_hangover() + * + * Periodicity detection routine (called by the speech encoder): + * periodicity_detection() + * + **************************************************************************/ + +#include "typedef.h" +#include "cnst.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "vad.h" + +/* Constants of VAD hangover addition */ + +#define HANGCONST 10 +#define BURSTCONST 3 + +/* Constant of spectral comparison */ + +#define STAT_THRESH 3670L /* 0.056 */ + +/* Constants of periodicity detection */ + +#define LTHRESH 2 +#define NTHRESH 4 + +/* Pseudo floating point representations of constants + for threshold adaptation */ + +#define M_PTH 32500 /*** 130000.0 ***/ +#define E_PTH 17 +#define M_PLEV 21667 /*** 346666.7 ***/ +#define E_PLEV 19 +#define M_MARGIN 16927 /*** 69333340 ***/ +#define E_MARGIN 27 + +#define FAC 17203 /* 2.1 */ + +/* Constants of tone detection */ + +#define FREQTH 3189 +#define PREDTH 1464 + +/* Static variables of VAD */ + +static Word16 rvad[9], scal_rvad; +static Pfloat thvad; +static Word32 L_sacf[27]; +static Word32 L_sav0[36]; +static Word16 pt_sacf, pt_sav0; +static Word32 L_lastdm; +static Word16 adaptcount; +static Word16 burstcount, hangcount; +static Word16 oldlagcount, veryoldlagcount, oldlag; + +Word16 ptch; + +/************************************************************************* + * + * FUNCTION NAME: vad_reset + * + * PURPOSE: Resets the static variables of the VAD to their + * initial values + * + *************************************************************************/ + +void vad_reset () +{ + Word16 i; + + /* Initialize rvad variables */ + rvad[0] = 0x6000; + for (i = 1; i < 9; i++) + { + rvad[i] = 0; + } + scal_rvad = 7; + + /* Initialize threshold level */ + thvad.e = 20; /*** exponent ***/ + thvad.m = 27083; /*** mantissa ***/ + + /* Initialize ACF averaging variables */ + for (i = 0; i < 27; i++) + { + L_sacf[i] = 0L; + } + for (i = 0; i < 36; i++) + { + L_sav0[i] = 0L; + } + pt_sacf = 0; + pt_sav0 = 0; + + /* Initialize spectral comparison variable */ + L_lastdm = 0L; + + /* Initialize threshold adaptation variable */ + adaptcount = 0; + + /* Initialize VAD hangover addition variables */ + burstcount = 0; + hangcount = -1; + + /* Initialize periodicity detection variables */ + oldlagcount = 0; + veryoldlagcount = 0; + oldlag = 18; + + ptch = 1; + + return; +} + +/**************************************************************************** + * + * FUNCTION: vad_computation + * + * PURPOSE: Returns a decision as to whether the current frame being + * processed by the speech encoder contains speech or not. + * + * INPUTS: r_h[0..8] autocorrelation of input signal frame (msb) + * r_l[0..8] autocorrelation of input signal frame (lsb) + * scal_acf scaling factor for the autocorrelations + * rc[0..3] speech encoder reflection coefficients + * ptch flag to indicate a periodic signal component + * + * OUTPUTS: none + * + * RETURN VALUE: vad decision + * + ***************************************************************************/ + +Word16 vad_computation ( + Word16 r_h[], + Word16 r_l[], + Word16 scal_acf, + Word16 rc[], + Word16 ptch +) +{ + Word32 L_av0[9], L_av1[9]; + Word16 vad, vvad, rav1[9], scal_rav1, stat, tone; + Pfloat acf0, pvad; + + energy_computation (r_h, scal_acf, rvad, scal_rvad, &acf0, &pvad); + acf_averaging (r_h, r_l, scal_acf, L_av0, L_av1); + predictor_values (L_av1, rav1, &scal_rav1); + stat = spectral_comparison (rav1, scal_rav1, L_av0); move16 (); + tone_detection (rc, &tone); + threshold_adaptation (stat, ptch, tone, rav1, scal_rav1, pvad, acf0, + rvad, &scal_rvad, &thvad); + vvad = vad_decision (pvad, thvad); move16 (); + vad = vad_hangover (vvad); move16 (); + + return vad; +} + +/**************************************************************************** + * + * FUNCTION: energy_computation + * + * PURPOSE: Computes the input and residual energies of the adaptive + * filter in a floating point representation. + * + * INPUTS: r_h[0..8] autocorrelation of input signal frame (msb) + * scal_acf scaling factor for the autocorrelations + * rvad[0..8] autocorrelated adaptive filter coefficients + * scal_rvad scaling factor for rvad[] + * + * OUTPUTS: *acf0 signal frame energy (mantissa+exponent) + * *pvad filtered signal energy (mantissa+exponent) + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void energy_computation ( + Word16 r_h[], + Word16 scal_acf, + Word16 rvad[], + Word16 scal_rvad, + Pfloat * acf0, + Pfloat * pvad +) +{ + Word16 i, temp, norm_prod; + Word32 L_temp; + + /* r[0] is always greater than zero (no need to test for r[0] == 0) */ + + /* Computation of acf0 (exponent and mantissa) */ + + acf0->e = sub (32, scal_acf); move16 (); + acf0->m = r_h[0] & 0x7ff8; move16 (); logic16 (); + + /* Computation of pvad (exponent and mantissa) */ + + pvad->e = add (acf0->e, 14); move16 (); + pvad->e = sub (pvad->e, scal_rvad); move16 (); + + L_temp = 0L; move32 (); + + for (i = 1; i <= 8; i++) + { + temp = shr (r_h[i], 3); + L_temp = L_mac (L_temp, temp, rvad[i]); + } + + temp = shr (r_h[0], 3); + L_temp = L_add (L_temp, L_shr (L_mult (temp, rvad[0]), 1)); + + test (); + if (L_temp <= 0L) + { + L_temp = 1L; move32 (); + } + norm_prod = norm_l (L_temp); + pvad->e = sub (pvad->e, norm_prod); move16 (); + pvad->m = extract_h (L_shl (L_temp, norm_prod)); + move16 (); + + return; +} + +/**************************************************************************** + * + * FUNCTION: acf_averaging + * + * PURPOSE: Computes the arrays L_av0[0..8] and L_av1[0..8]. + * + * INPUTS: r_h[0..8] autocorrelation of input signal frame (msb) + * r_l[0..8] autocorrelation of input signal frame (lsb) + * scal_acf scaling factor for the autocorrelations + * + * OUTPUTS: L_av0[0..8] ACF averaged over last four frames + * L_av1[0..8] ACF averaged over previous four frames + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void acf_averaging ( + Word16 r_h[], + Word16 r_l[], + Word16 scal_acf, + Word32 L_av0[], + Word32 L_av1[] +) +{ + Word32 L_temp; + Word16 scale; + Word16 i; + + scale = add (9, scal_acf); + + for (i = 0; i <= 8; i++) + { + L_temp = L_shr (L_Comp (r_h[i], r_l[i]), scale); + L_av0[i] = L_add (L_sacf[i], L_temp); move32 (); + L_av0[i] = L_add (L_sacf[i + 9], L_av0[i]); move32 (); + L_av0[i] = L_add (L_sacf[i + 18], L_av0[i]); move32 (); + L_sacf[pt_sacf + i] = L_temp; move32 (); + L_av1[i] = L_sav0[pt_sav0 + i]; move32 (); + L_sav0[pt_sav0 + i] = L_av0[i]; move32 (); + } + + /* Update the array pointers */ + + test (); + if (sub (pt_sacf, 18) == 0) + { + pt_sacf = 0; move16 (); + } + else + { + pt_sacf = add (pt_sacf, 9); + } + + test (); + if (sub (pt_sav0, 27) == 0) + { + pt_sav0 = 0; move16 (); + } + else + { + pt_sav0 = add (pt_sav0, 9); + } + + return; +} + +/**************************************************************************** + * + * FUNCTION: predictor_values + * + * PURPOSE: Computes the array rav[0..8] needed for the spectral + * comparison and the threshold adaptation. + * + * INPUTS: L_av1[0..8] ACF averaged over previous four frames + * + * OUTPUTS: rav1[0..8] ACF obtained from L_av1 + * *scal_rav1 rav1[] scaling factor + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void predictor_values ( + Word32 L_av1[], + Word16 rav1[], + Word16 *scal_rav1 +) +{ + Word16 vpar[8], aav1[9]; + + schur_recursion (L_av1, vpar); + step_up (8, vpar, aav1); + compute_rav1 (aav1, rav1, scal_rav1); + + return; +} + +/**************************************************************************** + * + * FUNCTION: schur_recursion + * + * PURPOSE: Uses the Schur recursion to compute adaptive filter + * reflection coefficients from an autorrelation function. + * + * INPUTS: L_av1[0..8] autocorrelation function + * + * OUTPUTS: vpar[0..7] reflection coefficients + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void schur_recursion ( + Word32 L_av1[], + Word16 vpar[] +) +{ + Word16 acf[9], pp[9], kk[9], temp; + Word16 i, k, m, n; + + /*** Schur recursion with 16-bit arithmetic ***/ + + test (); move32 (); + if (L_av1[0] == 0) + { + for (i = 0; i < 8; i++) + { + vpar[i] = 0; move16 (); + } + return; + } + temp = norm_l (L_av1[0]); + + for (k = 0; k <= 8; k++) + { + acf[k] = extract_h (L_shl (L_av1[k], temp)); move16 (); + } + + /*** Initialize arrays pp[..] and kk[..] for the recursion: ***/ + + for (i = 1; i <= 7; i++) + { + kk[9 - i] = acf[i]; move16 (); + } + + for (i = 0; i <= 8; i++) + { + pp[i] = acf[i]; move16 (); + } + + /*** Compute Parcor coefficients: ***/ + + for (n = 0; n < 8; n++) + { + test (); + if ((pp[0] == 0) || + (sub (pp[0], abs_s (pp[1])) < 0)) + { + for (i = n; i < 8; i++) + { + vpar[i] = 0; move16 (); + } + return; + } + vpar[n] = div_s (abs_s (pp[1]), pp[0]); move16 (); + + test (); move16 (); + if (pp[1] > 0) + { + vpar[n] = negate (vpar[n]); move16 (); + } + test (); + if (sub (n, 7) == 0) + { + return; + } + /*** Schur recursion: ***/ + + pp[0] = add (pp[0], mult_r (pp[1], vpar[n])); move16 (); + + for (m = 1; m <= 7 - n; m++) + { + pp[m] = add (pp[1 + m], mult_r (kk[9 - m], vpar[n])); + move16 (); + kk[9 - m] = add (kk[9 - m], mult_r (pp[1 + m], vpar[n])); + move16 (); + } + } + + return; +} + +/**************************************************************************** + * + * FUNCTION: step_up + * + * PURPOSE: Computes the transversal filter coefficients from the + * reflection coefficients. + * + * INPUTS: np filter order (2..8) + * vpar[0..np-1] reflection coefficients + * + * OUTPUTS: aav1[0..np] transversal filter coefficients + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void step_up ( + Word16 np, + Word16 vpar[], + Word16 aav1[] +) +{ + Word32 L_coef[9], L_work[9]; + Word16 temp; + Word16 i, m; + + /*** Initialization of the step-up recursion ***/ + + L_coef[0] = 0x20000000L; move32 (); + L_coef[1] = L_shl (L_deposit_l (vpar[0]), 14); move32 (); + + /*** Loop on the LPC analysis order: ***/ + + for (m = 2; m <= np; m++) + { + for (i = 1; i < m; i++) + { + temp = extract_h (L_coef[m - i]); + L_work[i] = L_mac (L_coef[i], vpar[m - 1], temp); move32 (); + } + + for (i = 1; i < m; i++) + { + L_coef[i] = L_work[i]; move32 (); + } + + L_coef[m] = L_shl (L_deposit_l (vpar[m - 1]), 14); move32 (); + } + + /*** Keep the aav1[0..np] in 15 bits ***/ + + for (i = 0; i <= np; i++) + { + aav1[i] = extract_h (L_shr (L_coef[i], 3)); move32 (); + } + + return; +} + +/**************************************************************************** + * + * FUNCTION: compute_rav1 + * + * PURPOSE: Computes the autocorrelation function of the adaptive + * filter coefficients. + * + * INPUTS: aav1[0..8] adaptive filter coefficients + * + * OUTPUTS: rav1[0..8] ACF of aav1 + * *scal_rav1 rav1[] scaling factor + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void compute_rav1 ( + Word16 aav1[], + Word16 rav1[], + Word16 *scal_rav1 +) +{ + Word32 L_work[9]; + Word16 i, k; + + /*** Computation of the rav1[0..8] ***/ + + for (i = 0; i <= 8; i++) + { + L_work[i] = 0L; move32 (); + + for (k = 0; k <= 8 - i; k++) + { + L_work[i] = L_mac (L_work[i], aav1[k], aav1[k + i]); move32 (); + } + } + + test (); move32 (); + if (L_work[0] == 0L) + { + *scal_rav1 = 0; move16 (); + } + else + { + *scal_rav1 = norm_l (L_work[0]); + } + + for (i = 0; i <= 8; i++) + { + rav1[i] = extract_h (L_shl (L_work[i], *scal_rav1)); move16 (); + } + + return; +} + +/**************************************************************************** + * + * FUNCTION: spectral_comparison + * + * PURPOSE: Computes the stat flag needed for the threshold + * adaptation decision. + * + * INPUTS: rav1[0..8] ACF obtained from L_av1 + * *scal_rav1 rav1[] scaling factor + * L_av0[0..8] ACF averaged over last four frames + * + * OUTPUTS: none + * + * RETURN VALUE: flag to indicate spectral stationarity + * + ***************************************************************************/ + +Word16 spectral_comparison ( + Word16 rav1[], + Word16 scal_rav1, + Word32 L_av0[] +) +{ + Word32 L_dm, L_sump, L_temp; + Word16 stat, sav0[9], shift, divshift, temp; + Word16 i; + + /*** Re-normalize L_av0[0..8] ***/ + + test (); move32 (); + if (L_av0[0] == 0L) + { + for (i = 0; i <= 8; i++) + { + sav0[i] = 0x0fff; /* 4095 */ move16 (); + } + } + else + { + shift = sub (norm_l (L_av0[0]), 3); + for (i = 0; i <= 8; i++) + { + sav0[i] = extract_h (L_shl (L_av0[i], shift)); move16 (); + } + } + + /*** Compute partial sum of dm ***/ + + L_sump = 0L; move32 (); + for (i = 1; i <= 8; i++) + { + L_sump = L_mac (L_sump, rav1[i], sav0[i]); + } + + /*** Compute the division of the partial sum by sav0[0] ***/ + + test (); + if (L_sump < 0L) + { + L_temp = L_negate (L_sump); + } + else + { + L_temp = L_sump; move32 (); + } + + test (); + if (L_temp == 0L) + { + L_dm = 0L; move32 (); + shift = 0; move16 (); + } + else + { + sav0[0] = shl (sav0[0], 3); move16 (); + shift = norm_l (L_temp); + temp = extract_h (L_shl (L_temp, shift)); + + test (); + if (sub (sav0[0], temp) >= 0) + { + divshift = 0; move16 (); + temp = div_s (temp, sav0[0]); + } + else + { + divshift = 1; move16 (); + temp = sub (temp, sav0[0]); + temp = div_s (temp, sav0[0]); + } + + test (); + if (sub (divshift, 1) == 0) + { + L_dm = 0x8000L; move32 (); + } + else + { + L_dm = 0L; move32 (); + } + + L_dm = L_shl (L_add (L_dm, L_deposit_l (temp)), 1); + + test (); + if (L_sump < 0L) + { + L_dm = L_negate (L_dm); + } + } + + /*** Re-normalization and final computation of L_dm ***/ + + L_dm = L_shl (L_dm, 14); + L_dm = L_shr (L_dm, shift); + L_dm = L_add (L_dm, L_shl (L_deposit_l (rav1[0]), 11)); + L_dm = L_shr (L_dm, scal_rav1); + + /*** Compute the difference and save L_dm ***/ + + L_temp = L_sub (L_dm, L_lastdm); + L_lastdm = L_dm; move32 (); + + test (); + if (L_temp < 0L) + { + L_temp = L_negate (L_temp); + } + /*** Evaluation of the stat flag ***/ + + L_temp = L_sub (L_temp, STAT_THRESH); + + test (); + if (L_temp < 0L) + { + stat = 1; move16 (); + } + else + { + stat = 0; move16 (); + } + + return stat; +} + +/**************************************************************************** + * + * FUNCTION: threshold_adaptation + * + * PURPOSE: Evaluates the secondary VAD decision. If speech is not + * present then the noise model rvad and adaptive threshold + * thvad are updated. + * + * INPUTS: stat flag to indicate spectral stationarity + * ptch flag to indicate a periodic signal component + * tone flag to indicate a tone signal component + * rav1[0..8] ACF obtained from L_av1 + * scal_rav1 rav1[] scaling factor + * pvad filtered signal energy (mantissa+exponent) + * acf0 signal frame energy (mantissa+exponent) + * + * OUTPUTS: rvad[0..8] autocorrelated adaptive filter coefficients + * *scal_rvad rvad[] scaling factor + * *thvad decision threshold (mantissa+exponent) + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void threshold_adaptation ( + Word16 stat, + Word16 ptch, + Word16 tone, + Word16 rav1[], + Word16 scal_rav1, + Pfloat pvad, + Pfloat acf0, + Word16 rvad[], + Word16 *scal_rvad, + Pfloat * thvad +) +{ + Word16 comp, comp2; + Word32 L_temp; + Word16 temp; + Pfloat p_temp; + Word16 i; + + comp = 0; move16 (); + + /*** Test if acf0 < pth; if yes set thvad to plev ***/ + + test (); + if (sub (acf0.e, E_PTH) < 0) + { + comp = 1; move16 (); + } + test (); test (); + if ((sub (acf0.e, E_PTH) == 0) && (sub (acf0.m, M_PTH) < 0)) + { + comp = 1; move16 (); + } + test (); + if (sub (comp, 1) == 0) + { + thvad->e = E_PLEV; move16 (); + thvad->m = M_PLEV; move16 (); + + return; + } + /*** Test if an adaption is required ***/ + + test (); + if (sub (ptch, 1) == 0) + { + comp = 1; move16 (); + } + test (); + if (stat == 0) + { + comp = 1; move16 (); + } + test (); + if (sub (tone, 1) == 0) + { + comp = 1; move16 (); + } + test (); + if (sub (comp, 1) == 0) + { + adaptcount = 0; move16 (); + return; + } + /*** Increment adaptcount ***/ + + adaptcount = add (adaptcount, 1); + test (); + if (sub (adaptcount, 8) <= 0) + { + return; + } + /*** computation of thvad-(thvad/dec) ***/ + + thvad->m = sub (thvad->m, shr (thvad->m, 5)); move16 (); + + test (); + if (sub (thvad->m, 0x4000) < 0) + { + thvad->m = shl (thvad->m, 1); move16 (); + thvad->e = sub (thvad->e, 1); move16 (); + } + /*** computation of pvad*fac ***/ + + L_temp = L_mult (pvad.m, FAC); + L_temp = L_shr (L_temp, 15); + p_temp.e = add (pvad.e, 1); move16 (); + + test (); + if (L_temp > 0x7fffL) + { + L_temp = L_shr (L_temp, 1); + p_temp.e = add (p_temp.e, 1); move16 (); + } + p_temp.m = extract_l (L_temp); move16 (); + + /*** test if thvad < pvad*fac ***/ + + test (); + if (sub (thvad->e, p_temp.e) < 0) + { + comp = 1; move16 (); + } + test (); test (); + if ((sub (thvad->e, p_temp.e) == 0) && + (sub (thvad->m, p_temp.m) < 0)) + { + comp = 1; move16 (); + } + /*** compute minimum(thvad+(thvad/inc), pvad*fac) when comp = 1 ***/ + + test (); + if (sub (comp, 1) == 0) + { + /*** compute thvad + (thvad/inc) ***/ + + L_temp = L_add (L_deposit_l (thvad->m), + L_deposit_l (shr (thvad->m, 4))); + + test (); + if (L_sub (L_temp, 0x7fffL) > 0) + { + thvad->m = extract_l (L_shr (L_temp, 1)); move16 (); + thvad->e = add (thvad->e, 1); move16 (); + } + else + { + thvad->m = extract_l (L_temp); move16 (); + } + + comp2 = 0; move16 (); + + test (); + if (sub (p_temp.e, thvad->e) < 0) + { + comp2 = 1; move16 (); + } + test (); test (); + if ((sub (p_temp.e, thvad->e) == 0) && + (sub (p_temp.m, thvad->m) < 0)) + { + comp2 = 1; move16 (); + } + test (); + if (sub (comp2, 1) == 0) + { + thvad->e = p_temp.e;move16 (); + thvad->m = p_temp.m;move16 (); + } + } + /*** compute pvad + margin ***/ + + test (); + if (sub (pvad.e, E_MARGIN) == 0) + { + L_temp = L_add (L_deposit_l (pvad.m), L_deposit_l (M_MARGIN)); + p_temp.m = extract_l (L_shr (L_temp, 1)); move16 (); + p_temp.e = add (pvad.e, 1); move16 (); + } + else + { + test (); + if (sub (pvad.e, E_MARGIN) > 0) + { + temp = sub (pvad.e, E_MARGIN); + temp = shr (M_MARGIN, temp); + L_temp = L_add (L_deposit_l (pvad.m), L_deposit_l (temp)); + + test (); + if (L_sub (L_temp, 0x7fffL) > 0) + { + p_temp.e = add (pvad.e, 1); move16 (); + p_temp.m = extract_l (L_shr (L_temp, 1)); + move16 (); + } + else + { + p_temp.e = pvad.e; move16 (); + p_temp.m = extract_l (L_temp); move16 (); + } + } + else + { + temp = sub (E_MARGIN, pvad.e); + temp = shr (pvad.m, temp); + L_temp = L_add (L_deposit_l (M_MARGIN), L_deposit_l (temp)); + + test (); + if (L_sub (L_temp, 0x7fffL) > 0) + { + p_temp.e = add (E_MARGIN, 1); move16 (); + p_temp.m = extract_l (L_shr (L_temp, 1)); + move16 (); + } + else + { + p_temp.e = E_MARGIN; move16 (); + p_temp.m = extract_l (L_temp); move16 (); + } + } + } + + /*** Test if thvad > pvad + margin ***/ + + comp = 0; move16 (); + + test (); + if (sub (thvad->e, p_temp.e) > 0) + { + comp = 1; move16 (); + } + test (); test (); + if ((sub (thvad->e, p_temp.e) == 0) && + (sub (thvad->m, p_temp.m) > 0)) + { + comp = 1; move16 (); + } + test (); + if (sub (comp, 1) == 0) + { + thvad->e = p_temp.e; move16 (); + thvad->m = p_temp.m; move16 (); + } + /*** Normalise and retain rvad[0..8] in memory ***/ + + *scal_rvad = scal_rav1; move16 (); + + for (i = 0; i <= 8; i++) + { + rvad[i] = rav1[i]; move16 (); + } + + /*** Set adaptcount to adp + 1 ***/ + + adaptcount = 9; move16 (); + + return; +} + +/**************************************************************************** + * + * FUNCTION: tone_detection + * + * PURPOSE: Computes the tone flag needed for the threshold + * adaptation decision. + * + * INPUTS: rc[0..3] reflection coefficients calculated in the + * speech encoder short term predictor + * + * OUTPUTS: *tone flag to indicate a periodic signal component + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void tone_detection ( + Word16 rc[], + Word16 *tone +) +{ + Word32 L_num, L_den, L_temp; + Word16 temp, prederr, a[3]; + Word16 i; + + *tone = 0; move16 (); + + /*** Calculate filter coefficients ***/ + + step_up (2, rc, a); + + /*** Calculate ( a[1] * a[1] ) ***/ + + temp = shl (a[1], 3); + L_den = L_mult (temp, temp); + + /*** Calculate ( 4*a[2] - a[1]*a[1] ) ***/ + + L_temp = L_shl (L_deposit_h (a[2]), 3); + L_num = L_sub (L_temp, L_den); + + /*** Check if pole frequency is less than 385 Hz ***/ + + test (); + if (L_num <= 0) + { + return; + } + test (); move16 (); + if (a[1] < 0) + { + temp = extract_h (L_den); + L_den = L_mult (temp, FREQTH); + + L_temp = L_sub (L_num, L_den); + + test (); + if (L_temp < 0) + { + return; + } + } + /*** Calculate normalised prediction error ***/ + + prederr = 0x7fff; move16 (); + + for (i = 0; i < 4; i++) + { + temp = mult (rc[i], rc[i]); + temp = sub (0x7fff, temp); + prederr = mult (prederr, temp); + } + + /*** Test if prediction error is smaller than threshold ***/ + + temp = sub (prederr, PREDTH); + + test (); + if (temp < 0) + { + *tone = 1; move16 (); + } + return; +} + +/**************************************************************************** + * + * FUNCTION: vad_decision + * + * PURPOSE: Computes the VAD decision based on the comparison of the + * floating point representations of pvad and thvad. + * + * INPUTS: pvad filtered signal energy (mantissa+exponent) + * thvad decision threshold (mantissa+exponent) + * + * OUTPUTS: none + * + * RETURN VALUE: vad decision before hangover is added + * + ***************************************************************************/ + +Word16 vad_decision ( + Pfloat pvad, + Pfloat thvad +) +{ + Word16 vvad; + + test (); test (); test (); + if (sub (pvad.e, thvad.e) > 0) + { + vvad = 1; move16 (); + } + else if ((sub (pvad.e, thvad.e) == 0) && + (sub (pvad.m, thvad.m) > 0)) + { + vvad = 1; move16 (); + } + else + { + vvad = 0; move16 (); + } + + return vvad; +} + +/**************************************************************************** + * + * FUNCTION: vad_hangover + * + * PURPOSE: Computes the final VAD decision for the current frame + * being processed. + * + * INPUTS: vvad vad decision before hangover is added + * + * OUTPUTS: none + * + * RETURN VALUE: vad decision after hangover is added + * + ***************************************************************************/ + +Word16 vad_hangover ( + Word16 vvad +) +{ + test (); + if (sub (vvad, 1) == 0) + { + burstcount = add (burstcount, 1); + } + else + { + burstcount = 0; move16 (); + } + + test (); + if (sub (burstcount, BURSTCONST) >= 0) + { + hangcount = HANGCONST; move16 (); + burstcount = BURSTCONST;move16 (); + } + test (); + if (hangcount >= 0) + { + hangcount = sub (hangcount, 1); + return 1; /* vad = 1 */ + } + return vvad; /* vad = vvad */ +} + +/**************************************************************************** + * + * FUNCTION: periodicity_update + * + * PURPOSE: Computes the ptch flag needed for the threshold + * adaptation decision for the next frame. + * + * INPUTS: lags[0..1] speech encoder long term predictor lags + * + * OUTPUTS: *ptch Boolean voiced / unvoiced decision + * + * RETURN VALUE: none + * + ***************************************************************************/ + +void periodicity_update ( + Word16 lags[], + Word16 *ptch +) +{ + Word16 minlag, maxlag, lagcount, temp; + Word16 i; + + /*** Run loop for the two halves in the frame ***/ + + lagcount = 0; move16 (); + + for (i = 0; i <= 1; i++) + { + /*** Search the maximum and minimum of consecutive lags ***/ + + test (); + if (sub (oldlag, lags[i]) > 0) + { + minlag = lags[i]; move16 (); + maxlag = oldlag; move16 (); + } + else + { + minlag = oldlag; move16 (); + maxlag = lags[i]; move16 (); + } + + temp = sub (maxlag, minlag); + + test (); + if (sub (temp, LTHRESH) < 0) + { + lagcount = add (lagcount, 1); + } + /*** Save the current LTP lag ***/ + + oldlag = lags[i]; move16 (); + } + + /*** Update the veryoldlagcount and oldlagcount ***/ + + veryoldlagcount = oldlagcount; + move16 (); + oldlagcount = lagcount; move16 (); + + /*** Make ptch decision ready for next frame ***/ + + temp = add (oldlagcount, veryoldlagcount); + + test (); + if (sub (temp, NTHRESH) >= 0) + { + *ptch = 1; move16 (); + } + else + { + *ptch = 0; move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/vad.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vad.h Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,106 @@ +/*************************************************************************** + * + * File Name: vad.h + * + * Purpose: Contains the prototypes for all functions of voice activity + * detection. Also contains the type definition for the pseudo + * floating point data type. + * + **************************************************************************/ + +/* Struct for storing pseudo floating point exponent and mantissa */ +struct _fp +{ + Word16 e; /* exponent */ + Word16 m; /* mantissa */ +}; + +typedef struct _fp Pfloat; + +void vad_reset (void); + +Word16 vad_computation ( + Word16 r_h[], + Word16 r_l[], + Word16 scal_acf, + Word16 rc[], + Word16 ptch +); + +void energy_computation ( + Word16 r_h[], + Word16 scal_acf, + Word16 rvad[], + Word16 scal_rvad, + Pfloat * acf0, + Pfloat * pvad +); + +void acf_averaging ( + Word16 r_h[], + Word16 r_l[], + Word16 scal_acf, + Word32 L_av0[], + Word32 L_av1[] +); + +void predictor_values ( + Word32 L_av1[], + Word16 rav1[], + Word16 *scal_rav1 +); + +void schur_recursion ( + Word32 L_av1[], + Word16 vpar[] +); + +void step_up ( + Word16 np, + Word16 vpar[], + Word16 aav1[] +); + +void compute_rav1 ( + Word16 aav1[], + Word16 rav1[], + Word16 *scal_rav1 +); + +Word16 spectral_comparison ( + Word16 rav1[], + Word16 scal_rav1, + Word32 L_av0[] +); + +void threshold_adaptation ( + Word16 stat, + Word16 ptch, + Word16 tone, + Word16 rav1[], + Word16 scal_rav1, + Pfloat pvad, + Pfloat acf0, + Word16 rvad[], + Word16 *scal_rvad, + Pfloat * thvad +); + +void tone_detection ( + Word16 rc[], + Word16 *tone +); + +Word16 vad_decision ( + Pfloat pvad, + Pfloat thvad +); + +Word16 vad_hangover ( + Word16 vvad +); + +void periodicity_update ( + Word16 lags[], + Word16 *ptch +); diff -r 000000000000 -r 56410792419a src/weight_a.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/weight_a.c Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,34 @@ +/************************************************************************* + * + * FUNCTION: Weight_Ai + * + * PURPOSE: Spectral expansion of LP coefficients. (order==10) + * + * DESCRIPTION: + * a_exp[i] = a[i] * fac[i-1] ,i=1,10 + * + *************************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "count.h" + +/* m = LPC order == 10 */ +#define m 10 + +void Weight_Ai ( + Word16 a[], /* (i) : a[m+1] LPC coefficients (m=10) */ + Word16 fac[], /* (i) : Spectral expansion factors. */ + Word16 a_exp[] /* (o) : Spectral expanded LPC coefficients */ +) +{ + Word16 i; + + a_exp[0] = a[0]; move16 (); + for (i = 1; i <= m; i++) + { + a_exp[i] = round (L_mult (a[i], fac[i - 1])); move16 (); + } + + return; +} diff -r 000000000000 -r 56410792419a src/window2.tab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/window2.tab Wed Apr 03 05:31:37 2024 +0000 @@ -0,0 +1,59 @@ +/* Hamming_cos window for LPC analysis. */ + +static const Word16 window_232_8[L_WINDOW] = +{ + 2621, 2623, 2627, 2634, 2644, 2656, 2671, 2689, 2710, 2734, + 2760, 2789, 2821, 2855, 2893, 2933, 2975, 3021, 3069, 3120, + 3173, 3229, 3288, 3350, 3414, 3481, 3550, 3622, 3697, 3774, + 3853, 3936, 4021, 4108, 4198, 4290, 4385, 4482, 4582, 4684, + 4788, 4895, 5004, 5116, 5230, 5346, 5464, 5585, 5708, 5833, + 5960, 6090, 6221, 6355, 6491, 6629, 6769, 6910, 7054, 7200, + 7348, 7498, 7649, 7803, 7958, 8115, 8274, 8434, 8597, 8761, + 8926, 9093, 9262, 9432, 9604, 9778, 9952, 10129, 10306, 10485, + 10665, 10847, 11030, 11214, 11399, 11586, 11773, 11962, 12152, 12342, + 12534, 12727, 12920, 13115, 13310, 13506, 13703, 13901, 14099, 14298, + 14497, 14698, 14898, 15100, 15301, 15504, 15706, 15909, 16112, 16316, + 16520, 16724, 16928, 17132, 17337, 17541, 17746, 17950, 18155, 18359, + 18564, 18768, 18972, 19175, 19379, 19582, 19785, 19987, 20189, 20390, + 20591, 20792, 20992, 21191, 21390, 21588, 21785, 21981, 22177, 22372, + 22566, 22759, 22951, 23143, 23333, 23522, 23710, 23897, 24083, 24268, + 24451, 24633, 24814, 24994, 25172, 25349, 25525, 25699, 25871, 26042, + 26212, 26380, 26546, 26711, 26874, 27035, 27195, 27353, 27509, 27664, + 27816, 27967, 28115, 28262, 28407, 28550, 28691, 28830, 28967, 29102, + 29234, 29365, 29493, 29619, 29743, 29865, 29985, 30102, 30217, 30330, + 30440, 30548, 30654, 30757, 30858, 30956, 31052, 31146, 31237, 31326, + 31412, 31495, 31576, 31655, 31730, 31804, 31874, 31942, 32008, 32071, + 32131, 32188, 32243, 32295, 32345, 32392, 32436, 32477, 32516, 32552, + 32585, 32615, 32643, 32668, 32690, 32709, 32726, 32740, 32751, 32759, + 32765, 32767, 32767, 32097, 30112, 26895, 22576, 17333, 11380, 4962 +}; + +/* Hamming-cosine window for LPC analysis. */ + +static const Word16 window_160_80[L_WINDOW] = +{ + 2621, 2624, 2633, 2648, 2668, 2695, 2727, 2765, 2809, 2859, + 2915, 2976, 3043, 3116, 3194, 3279, 3368, 3464, 3565, 3671, + 3783, 3900, 4023, 4151, 4285, 4423, 4567, 4716, 4870, 5029, + 5193, 5362, 5535, 5714, 5897, 6084, 6277, 6473, 6674, 6880, + 7089, 7303, 7521, 7742, 7968, 8197, 8430, 8667, 8907, 9151, + 9398, 9648, 9902, 10158, 10417, 10680, 10945, 11212, 11482, 11755, + 12030, 12307, 12586, 12867, 13150, 13435, 13722, 14010, 14299, 14590, + 14882, 15175, 15469, 15764, 16060, 16356, 16653, 16950, 17248, 17546, + 17844, 18141, 18439, 18736, 19033, 19330, 19625, 19920, 20214, 20507, + 20799, 21090, 21380, 21668, 21954, 22239, 22522, 22803, 23083, 23360, + 23635, 23907, 24177, 24445, 24710, 24972, 25231, 25488, 25741, 25991, + 26238, 26482, 26722, 26959, 27192, 27422, 27647, 27869, 28087, 28300, + 28510, 28715, 28916, 29113, 29305, 29493, 29676, 29854, 30028, 30197, + 30361, 30519, 30673, 30822, 30966, 31105, 31238, 31366, 31489, 31606, + 31718, 31825, 31926, 32021, 32111, 32195, 32273, 32346, 32413, 32475, + 32530, 32580, 32624, 32662, 32695, 32721, 32742, 32756, 32765, 32767, + 32767, 32756, 32720, 32661, 32578, 32471, 32341, 32188, 32012, 31813, + 31592, 31349, 31084, 30798, 30492, 30165, 29818, 29453, 29068, 28666, + 28247, 27810, 27358, 26891, 26408, 25913, 25404, 24883, 24350, 23807, + 23255, 22693, 22124, 21548, 20965, 20378, 19786, 19191, 18593, 17994, + 17395, 16796, 16199, 15604, 15012, 14424, 13842, 13265, 12696, 12135, + 11582, 11039, 10507, 9986, 9477, 8981, 8499, 8031, 7579, 7143, + 6723, 6321, 5937, 5571, 5225, 4898, 4591, 4305, 4041, 3798, + 3577, 3378, 3202, 3048, 2918, 2812, 2729, 2669, 2633, 2621 +};