# HG changeset patch # User Mychaela Falconia # Date 1669393101 0 # Node ID 49dd1ac8e75b18f4fbce7affb66025b4c6d625a6 # Parent 988fd7ff514f194ecfead5d2d4889115ab14d1d6 libgsmefr: import most *.c files from ETSI source diff -r 988fd7ff514f -r 49dd1ac8e75b libgsmefr/agc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/agc.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/autocorr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/autocorr.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/az_lsp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/az_lsp.c Fri Nov 25 16:18:21 2022 +0000 @@ -0,0 +1,261 @@ +/*********************************************************************** + * + * FUNCTION: Az_lsp + * + * PURPOSE: Compute the LSPs from the LP coefficients (order=10) + * + * DESCRIPTION: + * - The sum and difference filters are computed and divided by + * 1+z^{-1} and 1-z^{-1}, respectively. + * + * f1[i] = a[i] + a[11-i] - f1[i-1] ; i=1,...,5 + * f2[i] = a[i] - a[11-i] + f2[i-1] ; i=1,...,5 + * + * - The roots of F1(z) and F2(z) are found using Chebyshev polynomial + * evaluation. The polynomials are evaluated at 60 points regularly + * spaced in the frequency domain. The sign change interval is + * subdivided 4 times to better track the root. + * The LSPs are found in the cosine domain [1,-1]. + * + * - If less than 10 roots are found, the LSPs from the past frame are + * used. + * + ***********************************************************************/ + +#include "typedef.h" +#include "basic_op.h" +#include "oper_32b.h" +#include "count.h" +#include "cnst.h" + +#include "grid.tab" + +/* M = LPC order, NC = M/2 */ + +#define NC M/2 + +/* local function */ + +static Word16 Chebps (Word16 x, Word16 f[], Word16 n); + +void Az_lsp ( + Word16 a[], /* (i) : predictor coefficients */ + Word16 lsp[], /* (o) : line spectral pairs */ + Word16 old_lsp[] /* (i) : old lsp[] (in case not found 10 roots) */ +) +{ + Word16 i, j, nf, ip; + Word16 xlow, ylow, xhigh, yhigh, xmid, ymid, xint; + Word16 x, y, sign, exp; + Word16 *coef; + Word16 f1[M / 2 + 1], f2[M / 2 + 1]; + Word32 t0; + + /*-------------------------------------------------------------* + * find the sum and diff. pol. F1(z) and F2(z) * + * F1(z) <--- F1(z)/(1+z**-1) & F2(z) <--- F2(z)/(1-z**-1) * + * * + * f1[0] = 1.0; * + * f2[0] = 1.0; * + * * + * for (i = 0; i< NC; i++) * + * { * + * f1[i+1] = a[i+1] + a[M-i] - f1[i] ; * + * f2[i+1] = a[i+1] - a[M-i] + f2[i] ; * + * } * + *-------------------------------------------------------------*/ + + f1[0] = 1024; move16 (); /* f1[0] = 1.0 */ + f2[0] = 1024; move16 (); /* f2[0] = 1.0 */ + + for (i = 0; i < NC; i++) + { + t0 = L_mult (a[i + 1], 8192); /* x = (a[i+1] + a[M-i]) >> 2 */ + t0 = L_mac (t0, a[M - i], 8192); + x = extract_h (t0); + /* f1[i+1] = a[i+1] + a[M-i] - f1[i] */ + f1[i + 1] = sub (x, f1[i]);move16 (); + + t0 = L_mult (a[i + 1], 8192); /* x = (a[i+1] - a[M-i]) >> 2 */ + t0 = L_msu (t0, a[M - i], 8192); + x = extract_h (t0); + /* f2[i+1] = a[i+1] - a[M-i] + f2[i] */ + f2[i + 1] = add (x, f2[i]);move16 (); + } + + /*-------------------------------------------------------------* + * find the LSPs using the Chebychev pol. evaluation * + *-------------------------------------------------------------*/ + + nf = 0; move16 (); /* number of found frequencies */ + ip = 0; move16 (); /* indicator for f1 or f2 */ + + coef = f1; move16 (); + + xlow = grid[0]; move16 (); + ylow = Chebps (xlow, coef, NC);move16 (); + + j = 0; + test (); test (); + /* while ( (nf < M) && (j < grid_points) ) */ + while ((sub (nf, M) < 0) && (sub (j, grid_points) < 0)) + { + j++; + xhigh = xlow; move16 (); + yhigh = ylow; move16 (); + xlow = grid[j]; move16 (); + ylow = Chebps (xlow, coef, NC); + move16 (); + + test (); + if (L_mult (ylow, yhigh) <= (Word32) 0L) + { + + /* divide 4 times the interval */ + + for (i = 0; i < 4; i++) + { + /* xmid = (xlow + xhigh)/2 */ + xmid = add (shr (xlow, 1), shr (xhigh, 1)); + ymid = Chebps (xmid, coef, NC); + move16 (); + + test (); + if (L_mult (ylow, ymid) <= (Word32) 0L) + { + yhigh = ymid; move16 (); + xhigh = xmid; move16 (); + } + else + { + ylow = ymid; move16 (); + xlow = xmid; move16 (); + } + } + + /*-------------------------------------------------------------* + * Linear interpolation * + * xint = xlow - ylow*(xhigh-xlow)/(yhigh-ylow); * + *-------------------------------------------------------------*/ + + x = sub (xhigh, xlow); + y = sub (yhigh, ylow); + + test (); + if (y == 0) + { + xint = xlow; move16 (); + } + else + { + sign = y; move16 (); + y = abs_s (y); + exp = norm_s (y); + y = shl (y, exp); + y = div_s ((Word16) 16383, y); + t0 = L_mult (x, y); + t0 = L_shr (t0, sub (20, exp)); + y = extract_l (t0); /* y= (xhigh-xlow)/(yhigh-ylow) */ + + test (); + if (sign < 0) + y = negate (y); + + t0 = L_mult (ylow, y); + t0 = L_shr (t0, 11); + xint = sub (xlow, extract_l (t0)); /* xint = xlow - ylow*y */ + } + + lsp[nf] = xint; move16 (); + xlow = xint; move16 (); + nf++; + + test (); + if (ip == 0) + { + ip = 1; move16 (); + coef = f2; move16 (); + } + else + { + ip = 0; move16 (); + coef = f1; move16 (); + } + ylow = Chebps (xlow, coef, NC); + move16 (); + + } + test (); test (); + } + + /* Check if M roots found */ + + test (); + if (sub (nf, M) < 0) + { + for (i = 0; i < M; i++) + { + lsp[i] = old_lsp[i]; move16 (); + } + + } + return; +} + +/************************************************************************ + * + * FUNCTION: Chebps + * + * PURPOSE: Evaluates the Chebyshev polynomial series + * + * DESCRIPTION: + * - The polynomial order is n = m/2 = 5 + * - The polynomial F(z) (F1(z) or F2(z)) is given by + * F(w) = 2 exp(-j5w) C(x) + * where + * C(x) = T_n(x) + f(1)T_n-1(x) + ... +f(n-1)T_1(x) + f(n)/2 + * and T_m(x) = cos(mw) is the mth order Chebyshev polynomial ( x=cos(w) ) + * - The function returns the value of C(x) for the input x. + * + ***********************************************************************/ + +static Word16 Chebps (Word16 x, Word16 f[], Word16 n) +{ + Word16 i, cheb; + Word16 b0_h, b0_l, b1_h, b1_l, b2_h, b2_l; + Word32 t0; + + b2_h = 256; move16 (); /* b2 = 1.0 */ + b2_l = 0; move16 (); + + t0 = L_mult (x, 512); /* 2*x */ + t0 = L_mac (t0, f[1], 8192); /* + f[1] */ + L_Extract (t0, &b1_h, &b1_l); /* b1 = 2*x + f[1] */ + + for (i = 2; i < n; i++) + { + t0 = Mpy_32_16 (b1_h, b1_l, x); /* t0 = 2.0*x*b1 */ + t0 = L_shl (t0, 1); + t0 = L_mac (t0, b2_h, (Word16) 0x8000); /* t0 = 2.0*x*b1 - b2 */ + t0 = L_msu (t0, b2_l, 1); + t0 = L_mac (t0, f[i], 8192); /* t0 = 2.0*x*b1 - b2 + f[i] */ + + L_Extract (t0, &b0_h, &b0_l); /* b0 = 2.0*x*b1 - b2 + f[i]*/ + + b2_l = b1_l; move16 (); /* b2 = b1; */ + b2_h = b1_h; move16 (); + b1_l = b0_l; move16 (); /* b1 = b0; */ + b1_h = b0_h; move16 (); + } + + t0 = Mpy_32_16 (b1_h, b1_l, x); /* t0 = x*b1; */ + t0 = L_mac (t0, b2_h, (Word16) 0x8000); /* t0 = x*b1 - b2 */ + t0 = L_msu (t0, b2_l, 1); + t0 = L_mac (t0, f[i], 4096); /* t0 = x*b1 - b2 + f[i]/2 */ + + t0 = L_shl (t0, 6); + + cheb = extract_h (t0); + + return (cheb); +} diff -r 988fd7ff514f -r 49dd1ac8e75b libgsmefr/c1035pf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/c1035pf.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/cod_12k2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/cod_12k2.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/convolve.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/convolve.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/d1035pf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/d1035pf.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/d_gains.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/d_gains.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/d_homing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/d_homing.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/d_plsf_5.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/d_plsf_5.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/dec_12k2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/dec_12k2.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/dec_lag6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/dec_lag6.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/e_homing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/e_homing.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/enc_lag6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/enc_lag6.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/g_code.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/g_code.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/g_pitch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/g_pitch.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/int_lpc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/int_lpc.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/inter_6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/inter_6.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/inv_sqrt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/inv_sqrt.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/lag_wind.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/lag_wind.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/levinson.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/levinson.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/log2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/log2.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/lsp_az.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/lsp_az.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/lsp_lsf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/lsp_lsf.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/oper_32b.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/oper_32b.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/pitch_f6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/pitch_f6.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/pitch_ol.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/pitch_ol.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/pow2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/pow2.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/pre_proc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/pre_proc.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/pred_lt6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/pred_lt6.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/preemph.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/preemph.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/pstfilt2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/pstfilt2.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/q_gains.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/q_gains.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/q_plsf_5.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/q_plsf_5.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/reorder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/reorder.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/residu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/residu.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/syn_filt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/syn_filt.c Fri Nov 25 16:18:21 2022 +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 988fd7ff514f -r 49dd1ac8e75b libgsmefr/weight_a.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgsmefr/weight_a.c Fri Nov 25 16:18:21 2022 +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; +}