Files
rtphone/src/libs/gsmhr/gsmhr_sp_dec.c
2018-06-05 11:05:37 +03:00

5472 lines
169 KiB
C

/***************************************************************************
*
* File Name: sp_dec.c
*
* Purpose:
* Contains all functions for decoding speech. It does not
* include those routines needed to decode channel information.
*
* Since the GSM half-rate speech coder is an analysis-by-synthesis
* coder, many of the routines in this file are also called by the
* encoder. Functions are included for coded-parameter lookup,
* LPC filter coefficient interpolation, excitation vector lookup
* and construction, vector quantized gain lookup, and LPC synthesis
* filtering. In addition, some post-processing functions are
* included.
*
* Below is a listing of all the functions appearing in the file.
* The functions are arranged according to their purpose. Under
* each heading, the ordering is hierarchical.
*
* The entire speech decoder, under which all these routines fall,
* except were noted:
* speechDecoder()
*
* Spectral Smoothing of LPC:
* a_sst()
* aFlatRcDp()
* rcToCorrDpL()
* aToRc()
* rcToADp()
* VSELP codevector construction:
* b_con()
* v_con()
* LTP vector contruction:
* fp_ex()
* get_ipjj()
* lagDecode()
* LPC contruction
* getSfrmLpc()
* interpolateCheck()
* res_eng()
* lookupVq()
* Excitation scaling:
* rs_rr()
* g_corr1() (no scaling)
* rs_rrNs()
* g_corr1s() (g_corr1 with scaling)
* scaleExcite()
* Post filtering:
* pitchPreFilt()
* agcGain()
* lpcIir()
* r0BasedEnergyShft()
* spectralPostFilter()
* lpcFir()
*
*
* Routines not referenced by speechDecoder()
* Filtering routines:
* lpcIrZsIir()
* lpcZiIir()
* lpcZsFir()
* lpcZsIir()
* lpcZsIirP()
* Square root:
* sqroot()
*
**************************************************************************/
/*_________________________________________________________________________
| |
| Include Files |
|_________________________________________________________________________|
*/
#include "typedefs.h"
#include "mathhalf.h"
#include "sp_rom.h"
#include "sp_dec.h"
#include "err_conc.h"
#include "dtx.h"
/*_________________________________________________________________________
| |
| Local Functions (scope is limited to this file) |
|_________________________________________________________________________|
*/
static void a_sst(int16_t swAshift, int16_t swAscale,
int16_t pswDirectFormCoefIn[],
int16_t pswDirectFormCoefOut[]);
static short aToRc(int16_t swAshift, int16_t pswAin[],
int16_t pswRc[]);
static int16_t agcGain(int16_t pswStateCurr[],
struct NormSw snsInSigEnergy,
int16_t swEngyRShft);
static int16_t lagDecode(int16_t swDeltaLag);
static void lookupVq(int16_t pswVqCodeWds[], int16_t pswRCOut[]);
static void pitchPreFilt(int16_t pswExcite[],
int16_t swRxGsp0,
int16_t swRxLag,
int16_t swUvCode,
int16_t swSemiBeta,
struct NormSw snsSqrtRs,
int16_t pswExciteOut[],
int16_t pswPPreState[]);
static void spectralPostFilter(int16_t pswSPFIn[],
int16_t pswNumCoef[], int16_t pswDenomCoef[],
int16_t pswSPFOut[]);
/*_________________________________________________________________________
| |
| Local Defines |
|_________________________________________________________________________|
*/
#define P_INT_MACS 10
#define ASCALE 0x0800
#define ASHIFT 4
#define DELTA_LEVELS 16
#define GSP0_SCALE 1
#define C_BITS_V 9 /* number of bits in any voiced VSELP
* codeword */
#define C_BITS_UV 7 /* number of bits in a unvoiced VSELP
* codeword */
#define MAXBITS C_BITS_V /* max number of bits in any VSELP
* codeword */
#define LTP_LEN 147 /* 147==0x93 length of LTP history */
#define SQRT_ONEHALF 0x5a82 /* the 0.5 ** 0.5 */
#define LPC_ROUND 0x00000800L /* 0x8000 >> ASHIFT */
#define AFSHIFT 2 /* number of right shifts to be
* applied to the autocorrelation
* sequence in aFlatRcDp */
/*_________________________________________________________________________
| |
| State variables (globals) |
|_________________________________________________________________________|
*/
int16_t gswPostFiltAgcGain,
gpswPostFiltStateNum[NP],
gpswPostFiltStateDenom[NP],
swPostEmphasisState,
pswSynthFiltState[NP],
pswOldFrmKsDec[NP],
pswOldFrmAsDec[NP],
pswOldFrmPFNum[NP],
pswOldFrmPFDenom[NP],
swOldR0Dec,
pswLtpStateBaseDec[LTP_LEN + S_LEN],
pswPPreState[LTP_LEN + S_LEN];
int16_t swMuteFlagOld; /* error concealment */
/* DTX state variables */
/* ------------------- */
int16_t swRxDTXState = CNINTPER - 1; /* DTX State at the rx.
* Modulo */
/* counter [0,11]. */
int16_t swDecoMode = SPEECH;
int16_t swDtxMuting = 0;
int16_t swDtxBfiCnt = 0;
int16_t swOldR0IndexDec = 0;
int16_t swRxGsHistPtr = 0;
int32_t pL_RxGsHist[(OVERHANG - 1) * N_SUB];
/*_________________________________________________________________________
| |
| Global Data |
| (scope is global to this file) |
|_________________________________________________________________________|
*/
int16_t swR0Dec;
int16_t swVoicingMode, /* MODE */
pswVq[3], /* LPC1, LPC2, LPC3 */
swSi, /* INT_LPC */
swEngyRShift; /* for use by spectral postfilter */
int16_t swR0NewCN; /* DTX mode */
extern int32_tRom ppLr_gsTable[4][32]; /* DTX mode */
/***************************************************************************
*
* FUNCTION NAME: aFlatRcDp
*
* PURPOSE:
*
* Given a int32_t autocorrelation sequence, representing LPC
* information, aFlatRcDp converts the vector to one of NP
* int16_t reflection coefficients.
*
* INPUT:
*
*
* pL_R[0:NP] - An input int32_t autocorrelation sequence, (pL_R[0] =
* not necessarily 0x7fffffffL). pL_R is altered in the
* call, by being right shifted by global constant
* AFSHIFT bits.
*
* The input array pL_R[] should be shifted left as much
* as possible to improve precision.
*
* AFSHIFT - The number of right shifts to be applied to the
* normalized autocorrelation sequence pL_R.
*
* OUTPUT:
*
* pswRc[0:NP-1] - A int16_t output vector of NP reflection
* coefficients.
*
* RETURN VALUE:
*
* None
*
* DESCRIPTION:
*
* This routine transforms LPC information from one set of
* parameters to another. It is better suited for fixed point
* implementations than the Levinson-Dubin recursion.
*
* The function is called by a_sst(), and getNWCoefs(). In a_sst()
* direct form coefficients are converted to autocorrelations,
* and smoothed in that domain. Conversion back to direct form
* coefficients is done by calling aFlatRc(), followed by rcToADp().
*
* In getNwCoefs() again the conversion back to direct form
* coefficients is done by calling aFlatRc(), followed by rcToADp().
* In getNwCoefs() an autocorrelation sequence is generated from the
* impulse response of the weighting filters.
*
* The fundamental recursion is derived from AFLAT, which is
* described in section 4.1.4.1.
*
* Unlike in AFLAT where the reflection coefficients are known, here
* they are the unknowns. PBar and VBar for j==0 are initially
* known, as is rSub1. From this information the next set of P's
* and V's are generated. At the end of the recursion the next,
* reflection coefficient rSubj (pswRc[j]) can be calcluated by
* dividing Vsubj by Psubj.
*
* Precision is crucial in this routine. At each stage, a
* normalization is performed prior to the reflection coefficient
* calculation. In addition, to prevent overflow, the
* autocorrelation sequence is scaled down by ASHIFT (4) right
* shifts.
*
*
* REFERENCES: Sub_Clause 4.1.9 and 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: reflection coefficients, AFLAT, aflat, recursion, LPC
* KEYWORDS: autocorrelation
*
*************************************************************************/
void aFlatRcDp(int32_t *pL_R, int16_t *pswRc)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t pL_pjNewSpace[NP];
int32_t pL_pjOldSpace[NP];
int32_t pL_vjNewSpace[2 * NP - 1];
int32_t pL_vjOldSpace[2 * NP - 1];
int32_t *pL_pjOld;
int32_t *pL_pjNew;
int32_t *pL_vjOld;
int32_t *pL_vjNew;
int32_t *pL_swap;
int32_t L_temp;
int32_t L_sum;
int16_t swRc,
swRcSq,
swTemp,
swTemp1,
swAbsTemp1,
swTemp2;
int i,
j;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
pL_pjOld = pL_pjOldSpace;
pL_pjNew = pL_pjNewSpace;
pL_vjOld = pL_vjOldSpace + NP - 1;
pL_vjNew = pL_vjNewSpace + NP - 1;
/* Extract the 0-th reflection coefficient */
/*-----------------------------------------*/
swTemp1 = round(pL_R[1]);
swTemp2 = round(pL_R[0]);
swAbsTemp1 = abs_s(swTemp1);
if (swTemp2 <= 0 || sub(swAbsTemp1, swTemp2) >= 0)
{
j = 0;
for (i = j; i < NP; i++)
{
pswRc[i] = 0;
}
return;
}
swRc = divide_s(swAbsTemp1, swTemp2);/* return division result */
if (sub(swTemp1, swAbsTemp1) == 0)
swRc = negate(swRc); /* negate reflection Rc[j] */
pswRc[0] = swRc; /* copy into the output Rc array */
for (i = 0; i <= NP; i++)
{
pL_R[i] = L_shr(pL_R[i], AFSHIFT);
}
/* Initialize the pjOld and vjOld recursion arrays */
/*-------------------------------------------------*/
for (i = 0; i < NP; i++)
{
pL_pjOld[i] = pL_R[i];
pL_vjOld[i] = pL_R[i + 1];
}
for (i = -1; i > -NP; i--)
pL_vjOld[i] = pL_R[-(i + 1)];
/* Compute the square of the j=0 reflection coefficient */
/*------------------------------------------------------*/
swRcSq = mult_r(swRc, swRc);
/* Update pjNew and vjNew arrays for lattice stage j=1 */
/*-----------------------------------------------------*/
/* Updating pjNew: */
/*-------------------*/
for (i = 0; i <= NP - 2; i++)
{
L_temp = L_mpy_ls(pL_vjOld[i], swRc);
L_sum = L_add(L_temp, pL_pjOld[i]);
L_temp = L_mpy_ls(pL_pjOld[i], swRcSq);
L_sum = L_add(L_temp, L_sum);
L_temp = L_mpy_ls(pL_vjOld[-i], swRc);
pL_pjNew[i] = L_add(L_sum, L_temp);
}
/* Updating vjNew: */
/*-------------------*/
for (i = -NP + 2; i <= NP - 2; i++)
{
L_temp = L_mpy_ls(pL_vjOld[-i - 1], swRcSq);
L_sum = L_add(L_temp, pL_vjOld[i + 1]);
L_temp = L_mpy_ls(pL_pjOld[(((i + 1) >= 0) ? i + 1 : -(i + 1))], swRc);
L_temp = L_shl(L_temp, 1);
pL_vjNew[i] = L_add(L_temp, L_sum);
}
j = 0;
/* Compute reflection coefficients Rc[1],...,Rc[9] */
/*-------------------------------------------------*/
for (j = 1; j < NP; j++)
{
/* Swap pjNew and pjOld buffers */
/*------------------------------*/
pL_swap = pL_pjNew;
pL_pjNew = pL_pjOld;
pL_pjOld = pL_swap;
/* Swap vjNew and vjOld buffers */
/*------------------------------*/
pL_swap = pL_vjNew;
pL_vjNew = pL_vjOld;
pL_vjOld = pL_swap;
/* Compute the j-th reflection coefficient */
/*-----------------------------------------*/
swTemp = norm_l(pL_pjOld[0]); /* get shift count */
swTemp1 = round(L_shl(pL_vjOld[0], swTemp)); /* normalize num. */
swTemp2 = round(L_shl(pL_pjOld[0], swTemp)); /* normalize den. */
/* Test for invalid divide conditions: a) devisor < 0 b) abs(divident) >
* abs(devisor) If either of these conditions is true, zero out
* reflection coefficients for i=j,...,NP-1 and return. */
swAbsTemp1 = abs_s(swTemp1);
if (swTemp2 <= 0 || sub(swAbsTemp1, swTemp2) >= 0)
{
i = j;
for (i = j; i < NP; i++)
{
pswRc[i] = 0;
}
return;
}
swRc = divide_s(swAbsTemp1, swTemp2); /* return division result */
if (sub(swTemp1, swAbsTemp1) == 0)
swRc = negate(swRc); /* negate reflection Rc[j] */
swRcSq = mult_r(swRc, swRc); /* compute Rc^2 */
pswRc[j] = swRc; /* copy Rc[j] to output array */
/* Update pjNew and vjNew arrays for the next lattice stage if j < NP-1 */
/*---------------------------------------------------------------------*/
/* Updating pjNew: */
/*-----------------*/
for (i = 0; i <= NP - j - 2; i++)
{
L_temp = L_mpy_ls(pL_vjOld[i], swRc);
L_sum = L_add(L_temp, pL_pjOld[i]);
L_temp = L_mpy_ls(pL_pjOld[i], swRcSq);
L_sum = L_add(L_temp, L_sum);
L_temp = L_mpy_ls(pL_vjOld[-i], swRc);
pL_pjNew[i] = L_add(L_sum, L_temp);
}
/* Updating vjNew: */
/*-----------------*/
for (i = -NP + j + 2; i <= NP - j - 2; i++)
{
L_temp = L_mpy_ls(pL_vjOld[-i - 1], swRcSq);
L_sum = L_add(L_temp, pL_vjOld[i + 1]);
L_temp = L_mpy_ls(pL_pjOld[(((i + 1) >= 0) ? i + 1 : -(i + 1))], swRc);
L_temp = L_shl(L_temp, 1);
pL_vjNew[i] = L_add(L_temp, L_sum);
}
}
return;
}
/***************************************************************************
*
* FUNCTION NAME: aToRc
*
* PURPOSE:
*
* This subroutine computes a vector of reflection coefficients, given
* an input vector of direct form LPC filter coefficients.
*
* INPUTS:
*
* NP
* order of the LPC filter (global constant)
*
* swAshift
* The number of right shifts applied externally
* to the direct form filter coefficients.
*
* pswAin[0:NP-1]
* The input vector of direct form LPC filter
* coefficients.
*
* OUTPUTS:
*
* pswRc[0:NP-1]
* Array containing the reflection coefficients.
*
* RETURN VALUE:
*
* siUnstableFlt
* If stable reflection coefficients 0, 1 if unstable.
*
*
* DESCRIPTION:
*
* This function performs the conversion from direct form
* coefficients to reflection coefficients. It is used in a_sst()
* and interpolateCheck(). In a_sst() reflection coefficients used
* as a transitional data format. aToRc() is used for this
* conversion.
*
* When performing interpolation, a stability check must be
* performed. interpolateCheck() does this by calling aToRc().
*
* First coefficients are shifted down by iAshift. NP, the filter
* order is 10. The a's and rc's each have NP elements in them. An
* elaborate algorithm description can be found on page 443, of
* "Digital Processing of Speech Signals" by L.R. Rabiner and R.W.
* Schafer; Prentice-Hall; Englewood Cliffs, NJ (USA). 1978.
*
* REFERENCES: Sub_Clause 4.1.6, and 4.2.3 of GSM Recomendation 06.20
*
* KEYWORDS: reflectioncoefficients, parcors, conversion, atorc, ks, as
* KEYWORDS: parcorcoefficients, lpc, flat, vectorquantization
*
*************************************************************************/
static short aToRc(int16_t swAshift, int16_t pswAin[],
int16_t pswRc[])
{
/*_________________________________________________________________________
| |
| Constants |
|_________________________________________________________________________|
*/
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int16_t pswTmpSpace[NP],
pswASpace[NP],
swNormShift,
swActShift,
swNormProd,
swRcOverE,
swDiv,
*pswSwap,
*pswTmp,
*pswA;
int32_t L_temp;
short int siUnstableFlt,
i,
j; /* Loop control variables */
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Initialize starting addresses for temporary buffers */
/*-----------------------------------------------------*/
pswA = pswASpace;
pswTmp = pswTmpSpace;
/* Copy the direct form filter coefficients to a temporary array */
/*---------------------------------------------------------------*/
for (i = 0; i < NP; i++)
{
pswA[i] = pswAin[i];
}
/* Initialize the flag for filter stability check */
/*------------------------------------------------*/
siUnstableFlt = 0;
/* Start computation of the reflection coefficients, Rc[9],...,Rc[1] */
/*-------------------------------------------------------------------*/
for (i = NP - 1; i >= 1; i--)
{
pswRc[i] = shl(pswA[i], swAshift); /* write Rc[i] to output array */
/* Check the stability of i-th reflection coefficient */
/*----------------------------------------------------*/
siUnstableFlt = siUnstableFlt | isSwLimit(pswRc[i]);
/* Precompute intermediate variables for needed for the computation */
/* of direct form filter of order i-1 */
/*------------------------------------------------------------------*/
if (sub(pswRc[i], SW_MIN) == 0)
{
siUnstableFlt = 1;
swRcOverE = 0;
swDiv = 0;
swActShift = 2;
}
else
{
L_temp = LW_MAX; /* Load ~1.0 into accum */
L_temp = L_msu(L_temp, pswRc[i], pswRc[i]); /* 1.-Rc[i]*Rc[i] */
swNormShift = norm_l(L_temp);
L_temp = L_shl(L_temp, swNormShift);
swNormProd = extract_h(L_temp);
swActShift = add(2, swNormShift);
swDiv = divide_s(0x2000, swNormProd);
swRcOverE = mult_r(pswRc[i], swDiv);
}
/* Check stability */
/*---------------------*/
siUnstableFlt = siUnstableFlt | isSwLimit(swRcOverE);
/* Compute direct form filter coefficients corresponding to */
/* a direct form filter of order i-1 */
/*----------------------------------------------------------*/
for (j = 0; j <= i - 1; j++)
{
L_temp = L_mult(pswA[j], swDiv);
L_temp = L_msu(L_temp, pswA[i - j - 1], swRcOverE);
L_temp = L_shl(L_temp, swActShift);
pswTmp[j] = round(L_temp);
siUnstableFlt = siUnstableFlt | isSwLimit(pswTmp[j]);
}
/* Swap swA and swTmp buffers */
/*----------------------------*/
pswSwap = pswA;
pswA = pswTmp;
pswTmp = pswSwap;
}
/* Compute reflection coefficient Rc[0] */
/*--------------------------------------*/
pswRc[0] = shl(pswA[0], swAshift); /* write Rc[0] to output array */
/* Check the stability of 0-th reflection coefficient */
/*----------------------------------------------------*/
siUnstableFlt = siUnstableFlt | isSwLimit(pswRc[0]);
return (siUnstableFlt);
}
/***************************************************************************
*
* FUNCTION NAME: a_sst
*
* PURPOSE:
*
* The purpose of this function is to perform spectral smoothing of the
* direct form filter coefficients
*
* INPUTS:
*
* swAshift
* number of shift for coefficients
*
* swAscale
* scaling factor for coefficients
*
* pswDirectFormCoefIn[0:NP-1]
*
* array of input direct form coefficients
*
* OUTPUTS:
*
* pswDirectFormCoefOut[0:NP-1]
*
* array of output direct form coefficients
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* In a_sst() direct form coefficients are converted to
* autocorrelations, and smoothed in that domain. The function is
* used in the spectral postfilter. A description can be found in
* section 3.2.4 as well as in the reference by Y. Tohkura et al.
* "Spectral Smoothing Technique in PARCOR Speech
* Analysis-Synthesis", IEEE Trans. ASSP, vol. ASSP-26, pp. 591-596,
* Dec. 1978.
*
* After smoothing is performed conversion back to direct form
* coefficients is done by calling aFlatRc(), followed by rcToADp().
*
* The spectral smoothing filter coefficients with bandwidth set to 300
* and a sampling rate of 8000 be :
* static int16_tRom psrSST[NP+1] = { 0x7FFF,
* 0x7F5C, 0x7D76, 0x7A5B, 0x7622, 0x70EC,
* 0x6ADD, 0x641F, 0x5CDD, 0x5546, 0x4D86
* }
*
* REFERENCES: Sub_Clause 4.2.4 of GSM Recomendation 06.20
*
* KEYWORDS: spectral smoothing, direct form coef, sst, atorc, atocor
* KEYWORDS: levinson
*
*************************************************************************/
static void a_sst(int16_t swAshift, int16_t swAscale,
int16_t pswDirectFormCoefIn[],
int16_t pswDirectFormCoefOut[])
{
/*_________________________________________________________________________
| |
| Local Static Variables |
|_________________________________________________________________________|
*/
static int16_tRom psrSST[NP + 1] = {0x7FFF,
0x7F5C, 0x7D76, 0x7A5B, 0x7622, 0x70EC,
0x6ADD, 0x641F, 0x5CDD, 0x5546, 0x4D86,
};
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t pL_CorrTemp[NP + 1];
int16_t pswRCNum[NP],
pswRCDenom[NP];
short int siLoopCnt;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* convert direct form coefs to reflection coefs */
/* --------------------------------------------- */
aToRc(swAshift, pswDirectFormCoefIn, pswRCDenom);
/* convert to autocorrelation coefficients */
/* --------------------------------------- */
rcToCorrDpL(swAshift, swAscale, pswRCDenom, pL_CorrTemp);
/* do spectral smoothing technique */
/* ------------------------------- */
for (siLoopCnt = 1; siLoopCnt <= NP; siLoopCnt++)
{
pL_CorrTemp[siLoopCnt] = L_mpy_ls(pL_CorrTemp[siLoopCnt],
psrSST[siLoopCnt]);
}
/* Compute the reflection coefficients via AFLAT */
/*-----------------------------------------------*/
aFlatRcDp(pL_CorrTemp, pswRCNum);
/* Convert reflection coefficients to direct form filter coefficients */
/*-------------------------------------------------------------------*/
rcToADp(swAscale, pswRCNum, pswDirectFormCoefOut);
}
/**************************************************************************
*
* FUNCTION NAME: agcGain
*
* PURPOSE:
*
* Figure out what the agc gain should be to make the energy in the
* output signal match that of the input signal. Used in the post
* filters.
*
* INPUT:
*
* pswStateCurr[0:39]
* Input signal into agc block whose energy is
* to be modified using the gain returned. Signal is not
* modified in this routine.
*
* snsInSigEnergy
* Normalized number with shift count - the energy in
* the input signal.
*
* swEngyRShft
* Number of right shifts to apply to the vectors energy
* to ensure that it remains less than 1.0
* (swEngyRShft is always positive or zero)
*
* OUTPUT:
*
* none
*
* RETURN:
*
* the agc's gain/2 note DIVIDED by 2
*
*
* REFERENCES: Sub_Clause 4.2.2 and 4.2.4 of GSM Recomendation 06.20
*
* KEYWORDS: postfilter, agc, automaticgaincontrol, leveladjust
*
*************************************************************************/
static int16_t agcGain(int16_t pswStateCurr[],
struct NormSw snsInSigEnergy, int16_t swEngyRShft)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_OutEnergy,
L_AgcGain;
struct NormSw snsOutEnergy,
snsAgc;
int16_t swAgcOut,
swAgcShftCnt;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Calculate the energy in the output vector divided by 2 */
/*--------------------------------------------------------*/
snsOutEnergy.sh = g_corr1s(pswStateCurr, swEngyRShft, &L_OutEnergy);
/* reduce energy by a factor of 2 */
snsOutEnergy.sh = add(snsOutEnergy.sh, 1);
/* if waveform has nonzero energy, find AGC gain */
/*-----------------------------------------------*/
if (L_OutEnergy == 0)
{
swAgcOut = 0;
}
else
{
snsOutEnergy.man = round(L_OutEnergy);
/* divide input energy by 2 */
snsInSigEnergy.man = shr(snsInSigEnergy.man, 1);
/* Calculate AGC gain squared */
/*----------------------------*/
snsAgc.man = divide_s(snsInSigEnergy.man, snsOutEnergy.man);
swAgcShftCnt = norm_s(snsAgc.man);
snsAgc.man = shl(snsAgc.man, swAgcShftCnt);
/* find shift count for G^2 */
/*--------------------------*/
snsAgc.sh = add(sub(snsInSigEnergy.sh, snsOutEnergy.sh),
swAgcShftCnt);
L_AgcGain = L_deposit_h(snsAgc.man);
/* Calculate AGC gain */
/*--------------------*/
snsAgc.man = sqroot(L_AgcGain);
/* check if 1/2 sqrt(G^2) >= 1.0 */
/* This is equivalent to checking if shiftCnt/2+1 < 0 */
/*----------------------------------------------------*/
if (add(snsAgc.sh, 2) < 0)
{
swAgcOut = SW_MAX;
}
else
{
if (0x1 & snsAgc.sh)
{
snsAgc.man = mult(snsAgc.man, SQRT_ONEHALF);
}
snsAgc.sh = shr(snsAgc.sh, 1); /* shiftCnt/2 */
snsAgc.sh = add(snsAgc.sh, 1); /* shiftCnt/2 + 1 */
if (snsAgc.sh > 0)
{
snsAgc.man = shr(snsAgc.man, snsAgc.sh);
}
swAgcOut = snsAgc.man;
}
}
return (swAgcOut);
}
/***************************************************************************
*
* FUNCTION NAME: b_con
*
* PURPOSE:
* Expands codeword into an one dimensional array. The 0/1 input is
* changed to an element with magnitude +/- 0.5.
*
* input output
*
* 0 -0.5
* 1 +0.5
*
* INPUT:
*
* swCodeWord
* Input codeword, information in the LSB's
*
* siNumBits
* number of bits in the input codeword and number
* of elements in output vector
*
* pswVectOut[0:siNumBits]
*
* pointer to bit array
*
* OUTPUT:
*
* pswVectOut[0:siNumBits]
*
* signed bit array
*
* RETURN:
*
* none
*
* REFERENCES: Sub_Clause 4.1.10 and 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: b_con, codeword, expansion
*
*************************************************************************/
void b_con(int16_t swCodeWord, short siNumBits,
int16_t pswVectOut[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
short int siLoopCnt;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
for (siLoopCnt = 0; siLoopCnt < siNumBits; siLoopCnt++)
{
if (swCodeWord & 1) /* temp accumulator get 0.5 */
pswVectOut[siLoopCnt] = (int16_t) 0x4000;
else /* temp accumulator gets -0.5 */
pswVectOut[siLoopCnt] = (int16_t) 0xc000;
swCodeWord = shr(swCodeWord, 1);
}
}
/***************************************************************************
*
* FUNCTION NAME: fp_ex
*
* PURPOSE:
*
* Looks up a vector in the adaptive excitation codebook (long-term
* predictor).
*
* INPUTS:
*
* swOrigLagIn
*
* Extended resolution lag (lag * oversampling factor)
*
* pswLTPState[-147:39]
*
* Adaptive codebook (with space at end for looked up
* vector). Indicies [-147:-1] are the history, [0:39]
* are for the looked up vector.
*
* psrPitchIntrpFirBase[0:59]
* ppsrPVecIntFilt[0:9][0:5] ([tap][phase])
*
* Interpolating FIR filter coefficients.
*
* OUTPUTS:
*
* pswLTPState[0:39]
*
* Array containing the contructed output vector
*
* RETURN VALUE:
* none
*
* DESCRIPTION:
*
* The adaptive codebook consists of the history of the excitation.
* The vector is looked up by going back into this history
* by the amount of the input lag. If the input lag is fractional,
* then the samples to be looked up are interpolated from the existing
* samples in the history.
*
* If the lag is less than the length of the vector to be generated
* (i.e. less than the subframe length), then the lag is doubled
* after the first n samples have been looked up (n = input lag).
* In this way, the samples being generated are not part of the
* codebook. This is described in section 4.1.8.
*
* REFERENCES: Sub_Clause 4.1.8.5 and 4.2.1 of GSM Recomendation 06.20
*
* Keywords: pitch, excitation vector, long term filter, history,
* Keywords: fractional lag, get_ipjj
*
*************************************************************************/
void fp_ex(int16_t swOrigLagIn,
int16_t pswLTPState[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Temp;
int16_t swIntLag,
swRemain,
swRunningLag;
short int siSampsSoFar,
siSampsThisPass,
i,
j;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Loop: execute until all samples in the vector have been looked up */
/*-------------------------------------------------------------------*/
swRunningLag = swOrigLagIn;
siSampsSoFar = 0;
while (siSampsSoFar < S_LEN)
{
/* Get integer lag and remainder. These are used in addressing */
/* the LTP state and the interpolating filter, respectively */
/*--------------------------------------------------------------*/
get_ipjj(swRunningLag, &swIntLag, &swRemain);
/* Get the number of samples to look up in this pass */
/*---------------------------------------------------*/
if (sub(swIntLag, S_LEN) < 0)
siSampsThisPass = swIntLag - siSampsSoFar;
else
siSampsThisPass = S_LEN - siSampsSoFar;
/* Look up samples by interpolating (fractional lag), or copying */
/* (integer lag). */
/*---------------------------------------------------------------*/
if (swRemain == 0)
{
/* Integer lag: copy samples from history */
/*----------------------------------------*/
for (i = siSampsSoFar; i < siSampsSoFar + siSampsThisPass; i++)
pswLTPState[i] = pswLTPState[i - swIntLag];
}
else
{
/* Fractional lag: interpolate to get samples */
/*--------------------------------------------*/
for (i = siSampsSoFar; i < siSampsSoFar + siSampsThisPass; i++)
{
/* first tap with rounding offset */
/*--------------------------------*/
L_Temp = L_mac((long) 32768,
pswLTPState[i - swIntLag - P_INT_MACS / 2],
ppsrPVecIntFilt[0][swRemain]);
for (j = 1; j < P_INT_MACS - 1; j++)
{
L_Temp = L_mac(L_Temp,
pswLTPState[i - swIntLag - P_INT_MACS / 2 + j],
ppsrPVecIntFilt[j][swRemain]);
}
pswLTPState[i] = extract_h(L_mac(L_Temp,
pswLTPState[i - swIntLag + P_INT_MACS / 2 - 1],
ppsrPVecIntFilt[P_INT_MACS - 1][swRemain]));
}
}
/* Done with this pass: update loop controls */
/*-------------------------------------------*/
siSampsSoFar += siSampsThisPass;
swRunningLag = add(swRunningLag, swOrigLagIn);
}
}
/***************************************************************************
*
* FUNCTION NAME: g_corr1 (no scaling)
*
* PURPOSE:
*
* Calculates energy in subframe vector. Differs from g_corr1s,
* in that there the estimate of the maximum possible
* energy is < 1.0
*
*
* INPUT:
*
* pswIn[0:39]
* A subframe vector.
*
*
* OUTPUT:
*
* *pL_out
* A int32_t containing the normalized energy
* in the input vector.
*
* RETURN:
*
* swOut
* Number of right shifts which the accumulator was
* shifted to normalize it. Negative number implies
* a left shift, and therefore an energy larger than
* 1.0.
*
* REFERENCES: Sub_Clause 4.1.10.2 and 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: energy, autocorrelation, correlation, g_corr1
*
*
*************************************************************************/
int16_t g_corr1(int16_t *pswIn, int32_t *pL_out)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_sum;
int16_t swEngyLShft;
int i;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Calculate energy in subframe vector (40 samples) */
/*--------------------------------------------------*/
L_sum = L_mult(pswIn[0], pswIn[0]);
for (i = 1; i < S_LEN; i++)
{
L_sum = L_mac(L_sum, pswIn[i], pswIn[i]);
}
if (L_sum != 0)
{
/* Normalize the energy in the output int32_t */
/*---------------------------------------------*/
swEngyLShft = norm_l(L_sum);
*pL_out = L_shl(L_sum, swEngyLShft); /* normalize output
* int32_t */
}
else
{
/* Special case: energy is zero */
/*------------------------------*/
*pL_out = L_sum;
swEngyLShft = 0;
}
return (swEngyLShft);
}
/***************************************************************************
*
* FUNCTION NAME: g_corr1s (g_corr1 with scaling)
*
* PURPOSE:
*
* Calculates energy in subframe vector. Differs from g_corr1,
* in that there is an estimate of the maximum possible energy in the
* vector.
*
* INPUT:
*
* pswIn[0:39]
* A subframe vector.
*
* swEngyRShft
*
* Number of right shifts to apply to the vectors energy
* to ensure that it remains less than 1.0
* (swEngyRShft is always positive or zero)
*
* OUTPUT:
*
* *pL_out
* A int32_t containing the normalized energy
* in the input vector.
*
* RETURN:
*
* swOut
* Number of right shifts which the accumulator was
* shifted to normalize it. Negative number implies
* a left shift, and therefore an energy larger than
* 1.0.
*
* REFERENCES: Sub-Clause 4.1.8, 4.2.1, 4.2.2, and 4.2.4
* of GSM Recomendation 06.20
*
* keywords: energy, autocorrelation, correlation, g_corr1
*
*
*************************************************************************/
int16_t g_corr1s(int16_t pswIn[], int16_t swEngyRShft,
int32_t *pL_out)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_sum;
int16_t swTemp,
swEngyLShft;
int16_t swInputRShft;
int i;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Calculate energy in subframe vector (40 samples) */
/*--------------------------------------------------*/
if (sub(swEngyRShft, 1) <= 0)
{
/* use the energy shift factor, although it is an odd shift count */
/*----------------------------------------------------------------*/
swTemp = shr(pswIn[0], swEngyRShft);
L_sum = L_mult(pswIn[0], swTemp);
for (i = 1; i < S_LEN; i++)
{
swTemp = shr(pswIn[i], swEngyRShft);
L_sum = L_mac(L_sum, pswIn[i], swTemp);
}
}
else
{
/* convert energy shift factor to an input shift factor */
/*------------------------------------------------------*/
swInputRShft = shift_r(swEngyRShft, -1);
swEngyRShft = shl(swInputRShft, 1);
swTemp = shr(pswIn[0], swInputRShft);
L_sum = L_mult(swTemp, swTemp);
for (i = 1; i < S_LEN; i++)
{
swTemp = shr(pswIn[i], swInputRShft);
L_sum = L_mac(L_sum, swTemp, swTemp);
}
}
if (L_sum != 0)
{
/* Normalize the energy in the output int32_t */
/*---------------------------------------------*/
swTemp = norm_l(L_sum);
*pL_out = L_shl(L_sum, swTemp); /* normalize output int32_t */
swEngyLShft = sub(swTemp, swEngyRShft);
}
else
{
/* Special case: energy is zero */
/*------------------------------*/
*pL_out = L_sum;
swEngyLShft = 0;
}
return (swEngyLShft);
}
/***************************************************************************
*
* FUNCTION NAME: getSfrmLpc
*
* PURPOSE:
*
* Given frame information from past and present frame, interpolate
* (or copy) the frame based LPC coefficients into subframe
* lpc coeffs, i.e. the ones which will be used by the subframe
* as opposed to those coded and transmitted.
*
* INPUTS:
*
* siSoftInterpolation
*
* interpolate 1/0, a coded parameter.
*
* swPrevR0,swNewR0
*
* Rq0 for the last frame and for this frame.
* These are the decoded values, not the codewords.
*
* Previous lpc coefficients from the previous frame:
* in all filters below array[0] is the t=-1 element array[9]
* t=-10 element.
*
* pswPrevFrmKs[0:9]
*
* decoded version of the rc's tx'd last frame
*
* pswPrevFrmAs[0:9]
*
* the above K's converted to A's. i.e. direct
* form coefficients.
*
* pswPrevFrmPFNum[0:9], pswPrevFrmPFDenom[0:9]
*
* numerator and denominator coefficients used in the
* postfilter
*
* Current lpc coefficients from the current frame:
*
* pswNewFrmKs[0:9], pswNewFrmAs[0:9],
* pswNewFrmPFNum[0:9], pswNewFrmPFDenom[0:9] same as above.
*
* OUTPUTS:
*
* psnsSqrtRs[0:3]
*
* a normalized number (struct NormSw)
* containing an estimate of RS for each subframe.
* (number and a shift)
*
* ppswSynthAs[0:3][0:9]
*
* filter coefficients used by the synthesis filter.
*
* ppswPFNumAs[0:3][0:9]
*
* filter coefficients used by the postfilters
* numerator.
*
* ppswPFDenomAs[0:3][0:9]
*
* filter coefficients used by postfilters denominator.
*
* RETURN VALUE:
*
* None
*
* DESCRIPTION:
*
* For interpolated subframes, the direct form coefficients
* are converted to reflection coeffiecients to check for
* filter stability. If unstable, the uninterpolated coef.
* are used for that subframe.
*
* Interpolation is described in section 4.1.6, "Soft Interpolation
* of the Spectral Parameters"
*
* REFERENCES: Sub_clause 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: soft interpolation, int_lpc, interpolate, atorc,res_eng,i_mov
*
*************************************************************************/
void getSfrmLpc(short int siSoftInterpolation,
int16_t swPrevR0, int16_t swNewR0,
/* last frm */ int16_t pswPrevFrmKs[], int16_t pswPrevFrmAs[],
int16_t pswPrevFrmPFNum[],
int16_t pswPrevFrmPFDenom[],
/* this frm */ int16_t pswNewFrmKs[], int16_t pswNewFrmAs[],
int16_t pswNewFrmPFNum[],
int16_t pswNewFrmPFDenom[],
/* output */ struct NormSw *psnsSqrtRs,
int16_t *ppswSynthAs[], int16_t *ppswPFNumAs[],
int16_t *ppswPFDenomAs[])
{
/*_________________________________________________________________________
| |
| Local Static Variables |
|_________________________________________________________________________|
*/
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
short int siSfrm,
siStable,
i;
int32_t L_Temp1,
L_Temp2;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
if (siSoftInterpolation)
{
/* yes, interpolating */
/* ------------------ */
siSfrm = 0;
siStable = interpolateCheck(pswPrevFrmKs, pswPrevFrmAs,
pswPrevFrmAs, pswNewFrmAs,
psrOldCont[siSfrm], psrNewCont[siSfrm],
swPrevR0,
&psnsSqrtRs[siSfrm],
ppswSynthAs[siSfrm]);
if (siStable)
{
/* interpolate between direct form coefficient sets */
/* for both numerator and denominator coefficients */
/* assume output will be stable */
/* ------------------------------------------------ */
for (i = 0; i < NP; i++)
{
L_Temp1 = L_mult(pswNewFrmPFNum[i], psrNewCont[siSfrm]);
ppswPFNumAs[siSfrm][i] = mac_r(L_Temp1, pswPrevFrmPFNum[i],
psrOldCont[siSfrm]);
L_Temp2 = L_mult(pswNewFrmPFDenom[i], psrNewCont[siSfrm]);
ppswPFDenomAs[siSfrm][i] = mac_r(L_Temp2, pswPrevFrmPFDenom[i],
psrOldCont[siSfrm]);
}
}
else
{
/* this subframe is unstable */
/* ------------------------- */
for (i = 0; i < NP; i++)
{
ppswPFNumAs[siSfrm][i] = pswPrevFrmPFNum[i];
ppswPFDenomAs[siSfrm][i] = pswPrevFrmPFDenom[i];
}
}
for (siSfrm = 1; siSfrm < N_SUB - 1; siSfrm++)
{
siStable = interpolateCheck(pswNewFrmKs, pswNewFrmAs,
pswPrevFrmAs, pswNewFrmAs,
psrOldCont[siSfrm], psrNewCont[siSfrm],
swNewR0,
&psnsSqrtRs[siSfrm],
ppswSynthAs[siSfrm]);
if (siStable)
{
/* interpolate between direct form coefficient sets */
/* for both numerator and denominator coefficients */
/* assume output will be stable */
/* ------------------------------------------------ */
for (i = 0; i < NP; i++)
{
L_Temp1 = L_mult(pswNewFrmPFNum[i], psrNewCont[siSfrm]);
ppswPFNumAs[siSfrm][i] = mac_r(L_Temp1, pswPrevFrmPFNum[i],
psrOldCont[siSfrm]);
L_Temp2 = L_mult(pswNewFrmPFDenom[i], psrNewCont[siSfrm]);
ppswPFDenomAs[siSfrm][i] = mac_r(L_Temp2, pswPrevFrmPFDenom[i],
psrOldCont[siSfrm]);
}
}
else
{
/* this subframe has unstable filter coeffs, would like to
* interpolate but can not */
/* -------------------------------------- */
for (i = 0; i < NP; i++)
{
ppswPFNumAs[siSfrm][i] = pswNewFrmPFNum[i];
ppswPFDenomAs[siSfrm][i] = pswNewFrmPFDenom[i];
}
}
}
/* the last subframe never interpolate */
/* ----------------------------------- */
siSfrm = 3;
for (i = 0; i < NP; i++)
{
ppswPFNumAs[siSfrm][i] = pswNewFrmPFNum[i];
ppswPFDenomAs[siSfrm][i] = pswNewFrmPFDenom[i];
ppswSynthAs[siSfrm][i] = pswNewFrmAs[i];
}
res_eng(pswNewFrmKs, swNewR0, &psnsSqrtRs[siSfrm]);
}
/* SoftInterpolation == 0 - no interpolation */
/* ------------------------------------------ */
else
{
siSfrm = 0;
for (i = 0; i < NP; i++)
{
ppswPFNumAs[siSfrm][i] = pswPrevFrmPFNum[i];
ppswPFDenomAs[siSfrm][i] = pswPrevFrmPFDenom[i];
ppswSynthAs[siSfrm][i] = pswPrevFrmAs[i];
}
res_eng(pswPrevFrmKs, swPrevR0, &psnsSqrtRs[siSfrm]);
/* for subframe 1 and all subsequent sfrms, use result from new frm */
/* ---------------------------------------------------------------- */
res_eng(pswNewFrmKs, swNewR0, &psnsSqrtRs[1]);
for (siSfrm = 1; siSfrm < N_SUB; siSfrm++)
{
psnsSqrtRs[siSfrm].man = psnsSqrtRs[1].man;
psnsSqrtRs[siSfrm].sh = psnsSqrtRs[1].sh;
for (i = 0; i < NP; i++)
{
ppswPFNumAs[siSfrm][i] = pswNewFrmPFNum[i];
ppswPFDenomAs[siSfrm][i] = pswNewFrmPFDenom[i];
ppswSynthAs[siSfrm][i] = pswNewFrmAs[i];
}
}
}
}
/***************************************************************************
*
* FUNCTION NAME: get_ipjj
*
* PURPOSE:
*
* This subroutine calculates IP, the single-resolution lag rounded
* down to the nearest integer, and JJ, the remainder when the
* extended resolution lag is divided by the oversampling factor
*
* INPUTS:
*
* swLagIn
* extended resolution lag as an integer, i.e.
* fractional lag x oversampling factor
*
* OUTPUTS:
*
* *pswIp
* fractional lag rounded down to nearest integer, IP
*
* *pswJj
* the remainder JJ
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* ip = integer[lag/OS_FCTR]
* jj = integer_round[((lag/OS_FCTR)-ip)*(OS_FCTR)]
* if the rounding caused an 'overflow'
* set remainder jj to 0 and add 'carry' to ip
*
* This routine is involved in the mechanics of fractional and
* integer LTP searchs. The LTP is described in section 5.
*
* REFERENCES: Sub-clause 4.1.8 and 4.2.2 of GSM Recomendation 06.20
*
* KEYWORDS: lag, fractional, remainder, ip, jj, get_ipjj
*
*************************************************************************/
void get_ipjj(int16_t swLagIn,
int16_t *pswIp, int16_t *pswJj)
{
/*_________________________________________________________________________
| |
| Local Constants |
|_________________________________________________________________________|
*/
#define OS_FCTR_INV (int16_t)0x1555/* SW_MAX/OS_FCTR */
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Temp;
int16_t swTemp,
swTempIp,
swTempJj;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* calculate ip */
/* ------------ */
L_Temp = L_mult(OS_FCTR_INV, swLagIn); /* lag/OS_FCTR */
swTempIp = extract_h(L_Temp);
/* calculate jj */
/* ------------ */
swTemp = extract_l(L_Temp); /* loose ip */
swTemp = shr(swTemp, 1); /* isolate jj fraction */
swTemp = swTemp & SW_MAX;
L_Temp = L_mult(swTemp, OS_FCTR); /* ((lag/OS_FCTR)-ip))*(OS_FCTR) */
swTemp = round(L_Temp); /* round and pick-off jj */
if (sub(swTemp, OS_FCTR) == 0)
{ /* if 'overflow ' */
swTempJj = 0; /* set remainder,jj to 0 */
swTempIp = add(swTempIp, 1); /* 'carry' overflow into ip */
}
else
{
swTempJj = swTemp; /* read-off remainder,jj */
}
/* return ip and jj */
/* ---------------- */
*pswIp = swTempIp;
*pswJj = swTempJj;
}
/***************************************************************************
*
* FUNCTION NAME: interpolateCheck
*
* PURPOSE:
*
* Interpolates between direct form coefficient sets.
* Before releasing the interpolated coefficients, they are checked.
* If unstable, the "old" parameters are used.
*
* INPUTS:
*
* pswRefKs[0:9]
* decoded version of the rc's tx'd last frame
*
* pswRefCoefsA[0:9]
* above K's converted to direct form coefficients
*
* pswOldCoefsA[0:9]
* array of old Coefseters
*
* pswNewCoefsA[0:9]
* array of new Coefseters
*
* swOldPer
* amount old coefs supply to the output
*
* swNewPer
* amount new coefs supply to the output
*
* ASHIFT
* shift for reflection coef. conversion
*
* swRq
* quantized energy to use for subframe
* *
* OUTPUTS:
*
* psnsSqrtRsOut
* output pointer to sqrt(RS) normalized
*
* pswCoefOutA[0:9]
* output coefficients
*
* RETURN VALUE:
*
* siInterp_flg
* temporary subframe interpolation flag
* 0 - coef. interpolated, 1 -coef. not interpolated
*
* DESCRIPTION:
*
* For interpolated subframes, the direct form coefficients
* are converted to reflection coefficients to check for
* filter stability. If unstable, the uninterpolated coef.
* are used for that subframe. Section 4.1.6 describes
* interpolation.
*
* REFERENCES: Sub-clause 4.1.6 and 4.2.3 of GSM Recomendation 06.20
*
* KEYWORDS: soft interpolation, int_lpc, interpolate, atorc,res_eng,i_mov
*
*************************************************************************/
short int interpolateCheck(int16_t pswRefKs[],
int16_t pswRefCoefsA[],
int16_t pswOldCoefsA[], int16_t pswNewCoefsA[],
int16_t swOldPer, int16_t swNewPer,
int16_t swRq,
struct NormSw *psnsSqrtRsOut,
int16_t pswCoefOutA[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int16_t pswRcTemp[NP];
int32_t L_Temp;
short int siInterp_flg,
i;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Interpolation loop, NP is order of LPC filter */
/* --------------------------------------------- */
for (i = 0; i < NP; i++)
{
L_Temp = L_mult(pswNewCoefsA[i], swNewPer);
pswCoefOutA[i] = mac_r(L_Temp, pswOldCoefsA[i], swOldPer);
}
/* Convert to reflection coefficients and check stability */
/* ------------------------------------------------------ */
if (aToRc(ASHIFT, pswCoefOutA, pswRcTemp) != 0)
{
/* Unstable, use uninterpolated parameters and compute RS update the
* state with the frame data closest to this subfrm */
/* --------------------------------------------------------- */
res_eng(pswRefKs, swRq, psnsSqrtRsOut);
for (i = 0; i < NP; i++)
{
pswCoefOutA[i] = pswRefCoefsA[i];
}
siInterp_flg = 0;
}
else
{
/* Stable, compute RS */
/* ------------------ */
res_eng(pswRcTemp, swRq, psnsSqrtRsOut);
/* Set temporary subframe interpolation flag */
/* ----------------------------------------- */
siInterp_flg = 1;
}
/* Return subframe interpolation flag */
/* ---------------------------------- */
return (siInterp_flg);
}
/***************************************************************************
*
* FUNCTION NAME: lagDecode
*
* PURPOSE:
*
* The purpose of this function is to decode the lag received from the
* speech encoder into a full resolution lag for the speech decoder
*
* INPUTS:
*
* swDeltaLag
*
* lag received from channel decoder
*
* giSfrmCnt
*
* current sub-frame count
*
* swLastLag
*
* previous lag to un-delta this sub-frame's lag
*
* psrLagTbl[0:255]
*
* table used to look up full resolution lag
*
* OUTPUTS:
*
* swLastLag
*
* new previous lag for next sub-frame
*
* RETURN VALUE:
*
* swLag
*
* decoded full resolution lag
*
* DESCRIPTION:
*
* If first subframe, use lag as index to look up table directly.
*
* If it is one of the other subframes, the codeword represents a
* delta offset. The previously decoded lag is used as a starting
* point for decoding the current lag.
*
* REFERENCES: Sub-clause 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: deltalags, lookup lag
*
*************************************************************************/
static int16_t lagDecode(int16_t swDeltaLag)
{
/*_________________________________________________________________________
| |
| Local Constants |
|_________________________________________________________________________|
*/
#define DELTA_LEVELS_D2 DELTA_LEVELS/2
#define MAX_LAG 0x00ff
#define MIN_LAG 0x0000
/*_________________________________________________________________________
| |
| Local Static Variables |
|_________________________________________________________________________|
*/
static int16_t swLastLag;
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int16_t swLag;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* first sub-frame */
/* --------------- */
if (giSfrmCnt == 0)
{
swLastLag = swDeltaLag;
}
/* remaining sub-frames */
/* -------------------- */
else
{
/* get lag biased around 0 */
/* ----------------------- */
swLag = sub(swDeltaLag, DELTA_LEVELS_D2);
/* get real lag relative to last */
/* ----------------------------- */
swLag = add(swLag, swLastLag);
/* clip to max or min */
/* ------------------ */
if (sub(swLag, MAX_LAG) > 0)
{
swLastLag = MAX_LAG;
}
else if (sub(swLag, MIN_LAG) < 0)
{
swLastLag = MIN_LAG;
}
else
{
swLastLag = swLag;
}
}
/* return lag after look up */
/* ------------------------ */
swLag = psrLagTbl[swLastLag];
return (swLag);
}
/***************************************************************************
*
* FUNCTION NAME: lookupVq
*
* PURPOSE:
*
* The purpose of this function is to recover the reflection coeffs from
* the received LPC codewords.
*
* INPUTS:
*
* pswVqCodeWds[0:2]
*
* the codewords for each of the segments
*
* OUTPUTS:
*
* pswRCOut[0:NP-1]
*
* the decoded reflection coefficients
*
* RETURN VALUE:
*
* none.
*
* DESCRIPTION:
*
* For each segment do the following:
* setup the retrieval pointers to the correct vector
* get that vector
*
* REFERENCES: Sub-clause 4.2.3 of GSM Recomendation 06.20
*
* KEYWORDS: vq, vectorquantizer, lpc
*
*************************************************************************/
static void lookupVq(int16_t pswVqCodeWds[], int16_t pswRCOut[])
{
/*_________________________________________________________________________
| |
| Local Constants |
|_________________________________________________________________________|
*/
#define LSP_MASK 0x00ff
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
short int siSeg,
siIndex,
siVector,
siVector1,
siVector2,
siWordPtr;
int16_tRom *psrQTable;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* for each segment */
/* ---------------- */
for (siSeg = 0; siSeg < QUANT_NUM_OF_TABLES; siSeg++)
{
siVector = pswVqCodeWds[siSeg];
siIndex = psvqIndex[siSeg].l;
if (sub(siSeg, 2) == 0)
{ /* segment 3 */
/* set table */
/* --------- */
psrQTable = psrQuant3;
/* set offset into table */
/* ---------------------- */
siWordPtr = add(siVector, siVector);
/* look up coeffs */
/* -------------- */
siVector1 = psrQTable[siWordPtr];
siVector2 = psrQTable[siWordPtr + 1];
pswRCOut[siIndex - 1] = psrSQuant[shr(siVector1, 8) & LSP_MASK];
pswRCOut[siIndex] = psrSQuant[siVector1 & LSP_MASK];
pswRCOut[siIndex + 1] = psrSQuant[shr(siVector2, 8) & LSP_MASK];
pswRCOut[siIndex + 2] = psrSQuant[siVector2 & LSP_MASK];
}
else
{ /* segments 1 and 2 */
/* set tables */
/* ---------- */
if (siSeg == 0)
{
psrQTable = psrQuant1;
}
else
{
psrQTable = psrQuant2;
}
/* set offset into table */
/* --------------------- */
siWordPtr = add(siVector, siVector);
siWordPtr = add(siWordPtr, siVector);
siWordPtr = shr(siWordPtr, 1);
/* look up coeffs */
/* -------------- */
siVector1 = psrQTable[siWordPtr];
siVector2 = psrQTable[siWordPtr + 1];
if ((siVector & 0x0001) == 0)
{
pswRCOut[siIndex - 1] = psrSQuant[shr(siVector1, 8) & LSP_MASK];
pswRCOut[siIndex] = psrSQuant[siVector1 & LSP_MASK];
pswRCOut[siIndex + 1] = psrSQuant[shr(siVector2, 8) & LSP_MASK];
}
else
{
pswRCOut[siIndex - 1] = psrSQuant[siVector1 & LSP_MASK];
pswRCOut[siIndex] = psrSQuant[shr(siVector2, 8) & LSP_MASK];
pswRCOut[siIndex + 1] = psrSQuant[siVector2 & LSP_MASK];
}
}
}
}
/***************************************************************************
*
* FUNCTION NAME: lpcFir
*
* PURPOSE:
*
* The purpose of this function is to perform direct form fir filtering
* assuming a NP order filter and given state, coefficients, and input.
*
* INPUTS:
*
* NP
* order of the lpc filter
*
* S_LEN
* number of samples to filter
*
* pswInput[0:S_LEN-1]
*
* input array of points to be filtered.
* pswInput[0] is the oldest point (first to be filtered)
* pswInput[siLen-1] is the last point filtered (newest)
*
* pswCoef[0:NP-1]
*
* array of direct form coefficients
* pswCoef[0] = coeff for delay n = -1
* pswCoef[NP-1] = coeff for delay n = -NP
*
* ASHIFT
* number of shifts input A's have been shifted down by
*
* LPC_ROUND
* rounding constant
*
* pswState[0:NP-1]
*
* array of the filter state following form of pswCoef
* pswState[0] = state of filter for delay n = -1
* pswState[NP-1] = state of filter for delay n = -NP
*
* OUTPUTS:
*
* pswState[0:NP-1]
*
* updated filter state, ready to filter
* pswInput[siLen], i.e. the next point
*
* pswFiltOut[0:S_LEN-1]
*
* the filtered output
* same format as pswInput, pswFiltOut[0] is oldest point
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* because of the default sign of the coefficients the
* formula for the filter is :
* i=0, i < S_LEN
* out[i] = rounded(state[i]*coef[0])
* j=1, j < NP
* out[i] += state[j]*coef[j] (state is taken from either input
* state[] or input in[] arrays)
* rescale(out[i])
* out[i] += in[i]
* update final state array using in[]
*
* REFERENCES: Sub-clause 4.1.7 and 4.2.4 of GSM Recomendation 06.20
*
* KEYWORDS: lpc, directform, fir, lpcFir, inversefilter, lpcFilt
* KEYWORDS: dirForm, dir_mod, dir_clr, dir_neg, dir_set, i_dir_mod
*
*************************************************************************/
void lpcFir(int16_t pswInput[], int16_t pswCoef[],
int16_t pswState[], int16_t pswFiltOut[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Sum;
short int siStage,
siSmp;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* filter 1st sample */
/* ----------------- */
/* sum past state outputs */
/* ---------------------- */
/* 0th coef, with rounding */
L_Sum = L_mac(LPC_ROUND, pswState[0], pswCoef[0]);
for (siStage = 1; siStage < NP; siStage++)
{ /* remaining coefs */
L_Sum = L_mac(L_Sum, pswState[siStage], pswCoef[siStage]);
}
/* add input to partial output */
/* --------------------------- */
L_Sum = L_shl(L_Sum, ASHIFT);
L_Sum = L_msu(L_Sum, pswInput[0], 0x8000);
/* save 1st output sample */
/* ---------------------- */
pswFiltOut[0] = extract_h(L_Sum);
/* filter remaining samples */
/* ------------------------ */
for (siSmp = 1; siSmp < S_LEN; siSmp++)
{
/* sum past outputs */
/* ---------------- */
/* 0th coef, with rounding */
L_Sum = L_mac(LPC_ROUND, pswInput[siSmp - 1], pswCoef[0]);
/* remaining coefs */
for (siStage = 1; ((0 < (siSmp - siStage)) && siStage < NP); siStage++)
{
L_Sum = L_mac(L_Sum, pswInput[siSmp - siStage - 1], pswCoef[siStage]);
}
/* sum past states, if any */
/* ----------------------- */
for (siStage = siSmp; siStage < NP; siStage++)
{
L_Sum = L_mac(L_Sum, pswState[siStage - siSmp], pswCoef[siStage]);
}
/* add input to partial output */
/* --------------------------- */
L_Sum = L_shl(L_Sum, ASHIFT);
L_Sum = L_msu(L_Sum, pswInput[siSmp], 0x8000);
/* save current output sample */
/* -------------------------- */
pswFiltOut[siSmp] = extract_h(L_Sum);
}
/* save final state */
/* ---------------- */
for (siStage = 0; siStage < NP; siStage++)
{
pswState[siStage] = pswInput[S_LEN - siStage - 1];
}
}
/***************************************************************************
*
* FUNCTION NAME: lpcIir
*
* PURPOSE:
*
* The purpose of this function is to perform direct form IIR filtering
* assuming a NP order filter and given state, coefficients, and input
*
* INPUTS:
*
* NP
* order of the lpc filter
*
* S_LEN
* number of samples to filter
*
* pswInput[0:S_LEN-1]
*
* input array of points to be filtered
* pswInput[0] is the oldest point (first to be filtered)
* pswInput[siLen-1] is the last point filtered (newest)
*
* pswCoef[0:NP-1]
* array of direct form coefficients
* pswCoef[0] = coeff for delay n = -1
* pswCoef[NP-1] = coeff for delay n = -NP
*
* ASHIFT
* number of shifts input A's have been shifted down by
*
* LPC_ROUND
* rounding constant
*
* pswState[0:NP-1]
*
* array of the filter state following form of pswCoef
* pswState[0] = state of filter for delay n = -1
* pswState[NP-1] = state of filter for delay n = -NP
*
* OUTPUTS:
*
* pswState[0:NP-1]
*
* updated filter state, ready to filter
* pswInput[siLen], i.e. the next point
*
* pswFiltOut[0:S_LEN-1]
*
* the filtered output
* same format as pswInput, pswFiltOut[0] is oldest point
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* because of the default sign of the coefficients the
* formula for the filter is :
* i=0, i < S_LEN
* out[i] = rounded(state[i]*coef[0])
* j=1, j < NP
* out[i] -= state[j]*coef[j] (state is taken from either input
* state[] or prior out[] arrays)
* rescale(out[i])
* out[i] += in[i]
* update final state array using out[]
*
* REFERENCES: Sub-clause 4.1.7 and 4.2.4 of GSM Recomendation 06.20
*
* KEYWORDS: lpc, directform, iir, synthesisfilter, lpcFilt
* KEYWORDS: dirForm, dir_mod, dir_clr, dir_neg, dir_set
*
*************************************************************************/
void lpcIir(int16_t pswInput[], int16_t pswCoef[],
int16_t pswState[], int16_t pswFiltOut[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Sum;
short int siStage,
siSmp;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* filter 1st sample */
/* ----------------- */
/* sum past state outputs */
/* ---------------------- */
/* 0th coef, with rounding */
L_Sum = L_msu(LPC_ROUND, pswState[0], pswCoef[0]);
for (siStage = 1; siStage < NP; siStage++)
{ /* remaining coefs */
L_Sum = L_msu(L_Sum, pswState[siStage], pswCoef[siStage]);
}
/* add input to partial output */
/* --------------------------- */
L_Sum = L_shl(L_Sum, ASHIFT);
L_Sum = L_msu(L_Sum, pswInput[0], 0x8000);
/* save 1st output sample */
/* ---------------------- */
pswFiltOut[0] = extract_h(L_Sum);
/* filter remaining samples */
/* ------------------------ */
for (siSmp = 1; siSmp < S_LEN; siSmp++)
{
/* sum past outputs */
/* ---------------- */
/* 0th coef, with rounding */
L_Sum = L_msu(LPC_ROUND, pswFiltOut[siSmp - 1], pswCoef[0]);
/* remaining coefs */
for (siStage = 1; ((0 < (siSmp - siStage)) && siStage < NP); siStage++)
{
L_Sum = L_msu(L_Sum, pswFiltOut[siSmp - siStage - 1],
pswCoef[siStage]);
}
/* sum past states, if any */
/* ----------------------- */
for (siStage = siSmp; siStage < NP; siStage++)
{
L_Sum = L_msu(L_Sum, pswState[siStage - siSmp], pswCoef[siStage]);
}
/* add input to partial output */
/* --------------------------- */
L_Sum = L_shl(L_Sum, ASHIFT);
L_Sum = L_msu(L_Sum, pswInput[siSmp], 0x8000);
/* save current output sample */
/* -------------------------- */
pswFiltOut[siSmp] = extract_h(L_Sum);
}
/* save final state */
/* ---------------- */
for (siStage = 0; siStage < NP; siStage++)
{
pswState[siStage] = pswFiltOut[S_LEN - siStage - 1];
}
}
/***************************************************************************
*
* FUNCTION NAME: lpcIrZsIir
*
* PURPOSE:
*
* The purpose of this function is to calculate the impulse response
* via direct form IIR filtering with zero state assuming a NP order
* filter and given coefficients
*
* INPUTS:
*
* NP
* order of the lpc filter
*
* S_LEN
* number of samples to filter
*
* pswCoef[0:NP-1]
* array of direct form coefficients
* pswCoef[0] = coeff for delay n = -1
* pswCoef[NP-1] = coeff for delay n = -NP
*
* ASHIFT
* number of shifts input A's have been shifted down by
*
* LPC_ROUND
* rounding constant
*
* OUTPUTS:
*
* pswFiltOut[0:S_LEN-1]
*
* the filtered output
* same format as pswInput, pswFiltOut[0] is oldest point
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* This routine is called by getNWCoefs().
*
* Because of the default sign of the coefficients the
* formula for the filter is :
* i=0, i < S_LEN
* out[i] = rounded(state[i]*coef[0])
* j=1, j < NP
* out[i] -= state[j]*coef[j] (state taken from prior output[])
* rescale(out[i])
*
* REFERENCES: Sub-clause 4.1.8 of GSM Recomendation 06.20
*
* KEYWORDS: lpc, directform, iir, synthesisfilter, lpcFilt
* KEYWORDS: dirForm, dir_mod, dir_clr, dir_neg, dir_set
*
*************************************************************************/
void lpcIrZsIir(int16_t pswCoef[], int16_t pswFiltOut[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Sum;
short int siStage,
siSmp;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* output 1st sample */
/* ----------------- */
pswFiltOut[0] = 0x0400;
/* filter remaining samples */
/* ------------------------ */
for (siSmp = 1; siSmp < S_LEN; siSmp++)
{
/* sum past outputs */
/* ---------------- */
/* 0th coef, with rounding */
L_Sum = L_msu(LPC_ROUND, pswFiltOut[siSmp - 1], pswCoef[0]);
/* remaining coefs */
for (siStage = 1; ((0 < (siSmp - siStage)) && siStage < NP); siStage++)
{
L_Sum = L_msu(L_Sum, pswFiltOut[siSmp - siStage - 1],
pswCoef[siStage]);
}
/* scale output */
/* ------------ */
L_Sum = L_shl(L_Sum, ASHIFT);
/* save current output sample */
/* -------------------------- */
pswFiltOut[siSmp] = extract_h(L_Sum);
}
}
/***************************************************************************
*
* FUNCTION NAME: lpcZiIir
*
* PURPOSE:
* The purpose of this function is to perform direct form iir filtering
* with zero input assuming a NP order filter, and given state and
* coefficients
*
* INPUTS:
*
* NP
* order of the lpc filter
*
* S_LEN
* number of samples to filter MUST be <= MAX_ZIS
*
* pswCoef[0:NP-1]
*
* array of direct form coefficients.
* pswCoef[0] = coeff for delay n = -1
* pswCoef[NP-1] = coeff for delay n = -NP
*
* ASHIFT
* number of shifts input A's have been shifted down by
*
* LPC_ROUND
* rounding constant
*
* pswState[0:NP-1]
*
* array of the filter state following form of pswCoef
* pswState[0] = state of filter for delay n = -1
* pswState[NP-1] = state of filter for delay n = -NP
*
* OUTPUTS:
*
* pswFiltOut[0:S_LEN-1]
*
* the filtered output
* same format as pswIn, pswFiltOut[0] is oldest point
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* The routine is called from sfrmAnalysis, and is used to let the
* LPC filters ring out.
*
* because of the default sign of the coefficients the
* formula for the filter is :
* i=0, i < S_LEN
* out[i] = rounded(state[i]*coef[0])
* j=1, j < NP
* out[i] -= state[j]*coef[j] (state is taken from either input
* state[] or prior output[] arrays)
* rescale(out[i])
*
* REFERENCES: Sub-clause 4.1.7 of GSM Recomendation 06.20
*
* KEYWORDS: lpc, directform, iir, synthesisfilter, lpcFilt
* KEYWORDS: dirForm, dir_mod, dir_clr, dir_neg, dir_set
*
*************************************************************************/
void lpcZiIir(int16_t pswCoef[], int16_t pswState[],
int16_t pswFiltOut[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Sum;
short int siStage,
siSmp;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* filter 1st sample */
/* ----------------- */
/* sum past state outputs */
/* ---------------------- */
/* 0th coef, with rounding */
L_Sum = L_msu(LPC_ROUND, pswState[0], pswCoef[0]);
for (siStage = 1; siStage < NP; siStage++)
{ /* remaining coefs */
L_Sum = L_msu(L_Sum, pswState[siStage], pswCoef[siStage]);
}
/* scale output */
/* ------------ */
L_Sum = L_shl(L_Sum, ASHIFT);
/* save 1st output sample */
/* ---------------------- */
pswFiltOut[0] = extract_h(L_Sum);
/* filter remaining samples */
/* ------------------------ */
for (siSmp = 1; siSmp < S_LEN; siSmp++)
{
/* sum past outputs */
/* ---------------- */
/* 0th coef, with rounding */
L_Sum = L_msu(LPC_ROUND, pswFiltOut[siSmp - 1], pswCoef[0]);
/* remaining coefs */
for (siStage = 1; ((0 < (siSmp - siStage)) && siStage < NP); siStage++)
{
L_Sum = L_msu(L_Sum, pswFiltOut[siSmp - siStage - 1],
pswCoef[siStage]);
}
/* sum past states, if any */
/* ----------------------- */
for (siStage = siSmp; siStage < NP; siStage++)
{
L_Sum = L_msu(L_Sum, pswState[siStage - siSmp], pswCoef[siStage]);
}
/* scale output */
/* ------------ */
L_Sum = L_shl(L_Sum, ASHIFT);
/* save current output sample */
/* -------------------------- */
pswFiltOut[siSmp] = extract_h(L_Sum);
}
}
/***************************************************************************
*
* FUNCTION NAME: lpcZsFir
*
* PURPOSE:
* The purpose of this function is to perform direct form fir filtering
* with zero state, assuming a NP order filter and given coefficients
* and non-zero input.
*
* INPUTS:
*
* NP
* order of the lpc filter
*
* S_LEN
* number of samples to filter
*
* pswInput[0:S_LEN-1]
*
* input array of points to be filtered.
* pswInput[0] is the oldest point (first to be filtered)
* pswInput[siLen-1] is the last point filtered (newest)
*
* pswCoef[0:NP-1]
*
* array of direct form coefficients
* pswCoef[0] = coeff for delay n = -1
* pswCoef[NP-1] = coeff for delay n = -NP
*
* ASHIFT
* number of shifts input A's have been shifted down by
*
* LPC_ROUND
* rounding constant
*
* OUTPUTS:
*
* pswFiltOut[0:S_LEN-1]
*
* the filtered output
* same format as pswInput, pswFiltOut[0] is oldest point
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* This routine is used in getNWCoefs(). See section 4.1.7.
*
* because of the default sign of the coefficients the
* formula for the filter is :
* i=0, i < S_LEN
* out[i] = rounded(state[i]*coef[0])
* j=1, j < NP
* out[i] += state[j]*coef[j] (state taken from in[])
* rescale(out[i])
* out[i] += in[i]
*
* REFERENCES: Sub-clause 4.1.7 of GSM Recomendation 06.20
*
* KEYWORDS: lpc, directform, fir, lpcFir, inversefilter, lpcFilt
* KEYWORDS: dirForm, dir_mod, dir_clr, dir_neg, dir_set, i_dir_mod
*
*************************************************************************/
void lpcZsFir(int16_t pswInput[], int16_t pswCoef[],
int16_t pswFiltOut[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Sum;
short int siStage,
siSmp;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* output 1st sample */
/* ----------------- */
pswFiltOut[0] = pswInput[0];
/* filter remaining samples */
/* ------------------------ */
for (siSmp = 1; siSmp < S_LEN; siSmp++)
{
/* sum past outputs */
/* ---------------- */
/* 0th coef, with rounding */
L_Sum = L_mac(LPC_ROUND, pswInput[siSmp - 1], pswCoef[0]);
/* remaining coefs */
for (siStage = 1; ((0 < (siSmp - siStage)) && siStage < NP); siStage++)
{
L_Sum = L_mac(L_Sum, pswInput[siSmp - siStage - 1],
pswCoef[siStage]);
}
/* add input to partial output */
/* --------------------------- */
L_Sum = L_shl(L_Sum, ASHIFT);
L_Sum = L_msu(L_Sum, pswInput[siSmp], 0x8000);
/* save current output sample */
/* -------------------------- */
pswFiltOut[siSmp] = extract_h(L_Sum);
}
}
/***************************************************************************
*
* FUNCTION NAME: lpcZsIir
*
* PURPOSE:
*
* The purpose of this function is to perform direct form IIR filtering
* with zero state, assuming a NP order filter and given coefficients
* and non-zero input.
*
* INPUTS:
*
* NP
* order of the lpc filter
*
* S_LEN
* number of samples to filter
*
* pswInput[0:S_LEN-1]
*
* input array of points to be filtered
* pswInput[0] is the oldest point (first to be filtered)
* pswInput[siLen-1] is the last point filtered (newest)
*
* pswCoef[0:NP-1]
* array of direct form coefficients
* pswCoef[0] = coeff for delay n = -1
* pswCoef[NP-1] = coeff for delay n = -NP
*
* ASHIFT
* number of shifts input A's have been shifted down by
*
* LPC_ROUND
* rounding constant
*
* OUTPUTS:
*
* pswFiltOut[0:S_LEN-1]
*
* the filtered output
* same format as pswInput, pswFiltOut[0] is oldest point
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* This routine is used in the subframe analysis process. It is
* called by sfrmAnalysis() and fnClosedLoop(). It is this function
* which performs the weighting of the excitation vectors.
*
* because of the default sign of the coefficients the
* formula for the filter is :
* i=0, i < S_LEN
* out[i] = rounded(state[i]*coef[0])
* j=1, j < NP
* out[i] -= state[j]*coef[j] (state taken from prior out[])
* rescale(out[i])
* out[i] += in[i]
*
* REFERENCES: Sub-clause 4.1.8.5 of GSM Recomendation 06.20
*
* KEYWORDS: lpc, directform, iir, synthesisfilter, lpcFilt
* KEYWORDS: dirForm, dir_mod, dir_clr, dir_neg, dir_set
*
*************************************************************************/
void lpcZsIir(int16_t pswInput[], int16_t pswCoef[],
int16_t pswFiltOut[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Sum;
short int siStage,
siSmp;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* output 1st sample */
/* ----------------- */
pswFiltOut[0] = pswInput[0];
/* filter remaining samples */
/* ------------------------ */
for (siSmp = 1; siSmp < S_LEN; siSmp++)
{
/* sum past outputs */
/* ---------------- */
/* 0th coef, with rounding */
L_Sum = L_msu(LPC_ROUND, pswFiltOut[siSmp - 1], pswCoef[0]);
/* remaining coefs */
for (siStage = 1; ((0 < (siSmp - siStage)) && siStage < NP); siStage++)
{
L_Sum = L_msu(L_Sum, pswFiltOut[siSmp - siStage - 1],
pswCoef[siStage]);
}
/* add input to partial output */
/* --------------------------- */
L_Sum = L_shl(L_Sum, ASHIFT);
L_Sum = L_msu(L_Sum, pswInput[siSmp], 0x8000);
/* save current output sample */
/* -------------------------- */
pswFiltOut[siSmp] = extract_h(L_Sum);
}
}
/***************************************************************************
*
* FUNCTION NAME: lpcZsIirP
*
* PURPOSE:
*
* The purpose of this function is to perform direct form iir filtering
* with zero state, assuming a NP order filter and given coefficients
* and input
*
* INPUTS:
*
* NP
* order of the lpc filter
*
* S_LEN
* number of samples to filter
*
* pswCommonIO[0:S_LEN-1]
*
* input array of points to be filtered
* pswCommonIO[0] is oldest point (first to be filtered)
* pswCommonIO[siLen-1] is last point filtered (newest)
*
* pswCoef[0:NP-1]
* array of direct form coefficients
* pswCoef[0] = coeff for delay n = -1
* pswCoef[NP-1] = coeff for delay n = -NP
*
* ASHIFT
* number of shifts input A's have been shifted down by
*
* LPC_ROUND
* rounding constant
*
* OUTPUTS:
*
* pswCommonIO[0:S_LEN-1]
*
* the filtered output
* pswCommonIO[0] is oldest point
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* This function is called by geNWCoefs(). See section 4.1.7.
*
* because of the default sign of the coefficients the
* formula for the filter is :
* i=0, i < S_LEN
* out[i] = rounded(state[i]*coef[0])
* j=1, j < NP
* out[i] += state[j]*coef[j] (state taken from prior out[])
* rescale(out[i])
* out[i] += in[i]
*
* REFERENCES: Sub-clause 4.1.7 of GSM Recomendation 06.20
*
* KEYWORDS: lpc, directform, iir, synthesisfilter, lpcFilt
* KEYWORDS: dirForm, dir_mod, dir_clr, dir_neg, dir_set
*
*************************************************************************/
void lpcZsIirP(int16_t pswCommonIO[], int16_t pswCoef[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Sum;
short int siStage,
siSmp;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* filter remaining samples */
/* ------------------------ */
for (siSmp = 1; siSmp < S_LEN; siSmp++)
{
/* sum past outputs */
/* ---------------- */
/* 0th coef, with rounding */
L_Sum = L_mac(LPC_ROUND, pswCommonIO[siSmp - 1], pswCoef[0]);
/* remaining coefs */
for (siStage = 1; ((0 < (siSmp - siStage)) && siStage < NP); siStage++)
{
L_Sum = L_mac(L_Sum, pswCommonIO[siSmp - siStage - 1],
pswCoef[siStage]);
}
/* add input to partial output */
/* --------------------------- */
L_Sum = L_shl(L_Sum, ASHIFT);
L_Sum = L_msu(L_Sum, pswCommonIO[siSmp], 0x8000);
/* save current output sample */
/* -------------------------- */
pswCommonIO[siSmp] = extract_h(L_Sum);
}
}
/**************************************************************************
*
* FUNCTION NAME: pitchPreFilt
*
* PURPOSE:
*
* Performs pitch pre-filter on excitation in speech decoder.
*
* INPUTS:
*
* pswExcite[0:39]
*
* Synthetic residual signal to be filtered, a subframe-
* length vector.
*
* ppsrPVecIntFilt[0:9][0:5] ([tap][phase])
*
* Interpolation filter coefficients.
*
* ppsrSqtrP0[0:2][0:31] ([voicing level-1][gain code])
*
* Sqrt(P0) look-up table, used to determine pitch
* pre-filtering coefficient.
*
* swRxGsp0
*
* Coded value from gain quantizer, used to look up
* sqrt(P0).
*
* swRxLag
*
* Full-resolution lag value (fractional lag *
* oversampling factor), used to index pitch pre-filter
* state.
*
* swUvCode
*
* Coded voicing level, used to distinguish between
* voiced and unvoiced conditions, and to look up
* sqrt(P0).
*
* swSemiBeta
*
* The gain applied to the adaptive codebook excitation
* (long-term predictor excitation) limited to a maximum
* of 1.0, used to determine the pitch pre-filter
* coefficient.
*
* snsSqrtRs
*
* The estimate of the energy in the residual, used only
* for scaling.
*
* OUTPUTS:
*
* pswExciteOut[0:39]
*
* The output pitch pre-filtered excitation.
*
* pswPPreState[0:44]
*
* Contains the state of the pitch pre-filter
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* If the voicing mode for the frame is unvoiced, then the pitch pre-
* filter state is updated with the input excitation, and the input
* excitation is copied to the output.
*
* If voiced: first the energy in the input excitation is calculated.
* Then, the coefficient of the pitch pre-filter is obtained:
*
* PpfCoef = POST_EPSILON * min(beta, sqrt(P0)).
*
* Then, the pitch pre-filter is performed:
*
* ex_p(n) = ex(n) + PpfCoef * ex_p(n-L)
*
* The ex_p(n-L) sample is interpolated from the surrounding samples,
* even for integer values of L.
*
* Note: The coefficients of the interpolating filter are multiplied
* by PpfCoef, rather multiplying ex_p(n_L) after interpolation.
*
* Finally, the energy in the output excitation is calculated, and
* automatic gain control is applied to the output signal so that
* its energy matches the original.
*
* The pitch pre-filter is described in section 4.2.2.
*
* REFERENCES: Sub-clause 4.2.2 of GSM Recomendation 06.20
*
* KEYWORDS: prefilter, pitch, pitchprefilter, excitation, residual
*
*************************************************************************/
static void pitchPreFilt(int16_t pswExcite[],
int16_t swRxGsp0,
int16_t swRxLag, int16_t swUvCode,
int16_t swSemiBeta, struct NormSw snsSqrtRs,
int16_t pswExciteOut[],
int16_t pswPPreState[])
{
/*_________________________________________________________________________
| |
| Local Constants |
|_________________________________________________________________________|
*/
#define POST_EPSILON 0x2666
/*_________________________________________________________________________
| |
| Local Static Variables |
|_________________________________________________________________________|
*/
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_1,
L_OrigEnergy;
int16_t swScale,
swSqrtP0,
swIntLag,
swRemain,
swEnergy,
pswInterpCoefs[P_INT_MACS];
short int i,
j;
struct NormSw snsOrigEnergy;
int16_t *pswPPreCurr = &pswPPreState[LTP_LEN];
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Initialization */
/*----------------*/
swEnergy = 0;
/* Check voicing level */
/*---------------------*/
if (swUvCode == 0)
{
/* Unvoiced: perform one subframe of delay on state, copy input to */
/* state, copy input to output (if not same) */
/*-----------------------------------------------------------------*/
for (i = 0; i < LTP_LEN - S_LEN; i++)
pswPPreState[i] = pswPPreState[i + S_LEN];
for (i = 0; i < S_LEN; i++)
pswPPreState[i + LTP_LEN - S_LEN] = pswExcite[i];
if (pswExciteOut != pswExcite)
{
for (i = 0; i < S_LEN; i++)
pswExciteOut[i] = pswExcite[i];
}
}
else
{
/* Voiced: calculate energy in input, filter, calculate energy in */
/* output, scale */
/*----------------------------------------------------------------*/
/* Get energy in input excitation vector */
/*---------------------------------------*/
swEnergy = add(negate(shl(snsSqrtRs.sh, 1)), 3);
if (swEnergy > 0)
{
/* High-energy residual: scale input vector during energy */
/* calculation. The shift count + 1 of the energy of the */
/* residual estimate is used as an estimate of the shift */
/* count needed for the excitation energy */
/*--------------------------------------------------------*/
snsOrigEnergy.sh = g_corr1s(pswExcite, swEnergy, &L_OrigEnergy);
snsOrigEnergy.man = round(L_OrigEnergy);
}
else
{
/* set shift count to zero for AGC later */
/*---------------------------------------*/
swEnergy = 0;
/* Lower-energy residual: no overflow protection needed */
/*------------------------------------------------------*/
L_OrigEnergy = 0;
for (i = 0; i < S_LEN; i++)
{
L_OrigEnergy = L_mac(L_OrigEnergy, pswExcite[i], pswExcite[i]);
}
snsOrigEnergy.sh = norm_l(L_OrigEnergy);
snsOrigEnergy.man = round(L_shl(L_OrigEnergy, snsOrigEnergy.sh));
}
/* Determine pitch pre-filter coefficient, and scale the appropriate */
/* phase of the interpolating filter by it */
/*-------------------------------------------------------------------*/
swSqrtP0 = ppsrSqrtP0[swUvCode - 1][swRxGsp0];
if (sub(swSqrtP0, swSemiBeta) > 0)
swScale = swSemiBeta;
else
swScale = swSqrtP0;
swScale = mult_r(POST_EPSILON, swScale);
get_ipjj(swRxLag, &swIntLag, &swRemain);
for (i = 0; i < P_INT_MACS; i++)
pswInterpCoefs[i] = mult_r(ppsrPVecIntFilt[i][swRemain], swScale);
/* Perform filter */
/*----------------*/
for (i = 0; i < S_LEN; i++)
{
L_1 = L_deposit_h(pswExcite[i]);
for (j = 0; j < P_INT_MACS - 1; j++)
{
L_1 = L_mac(L_1, pswPPreCurr[i - swIntLag - P_INT_MACS / 2 + j],
pswInterpCoefs[j]);
}
pswPPreCurr[i] = mac_r(L_1,
pswPPreCurr[i - swIntLag + P_INT_MACS / 2 - 1],
pswInterpCoefs[P_INT_MACS - 1]);
}
/* Get energy in filtered vector, determine automatic-gain-control */
/* scale factor */
/*-----------------------------------------------------------------*/
swScale = agcGain(pswPPreCurr, snsOrigEnergy, swEnergy);
/* Scale filtered vector by AGC, put out. NOTE: AGC scale returned */
/* by routine above is divided by two, hence the shift below */
/*------------------------------------------------------------------*/
for (i = 0; i < S_LEN; i++)
{
L_1 = L_mult(pswPPreCurr[i], swScale);
L_1 = L_shl(L_1, 1);
pswExciteOut[i] = round(L_1);
}
/* Update pitch pre-filter state */
/*-------------------------------*/
for (i = 0; i < LTP_LEN; i++)
pswPPreState[i] = pswPPreState[i + S_LEN];
}
}
/***************************************************************************
*
* FUNCTION NAME: r0BasedEnergyShft
*
* PURPOSE:
*
* Given an R0 voicing level, find the number of shifts to be
* performed on the energy to ensure that the subframe energy does
* not overflow. example if energy can maximally take the value
* 4.0, then 2 shifts are required.
*
* INPUTS:
*
* swR0Index
* R0 codeword (0-0x1f)
*
* OUTPUTS:
*
* none
*
* RETURN VALUE:
*
* swShiftDownSignal
*
* number of right shifts to apply to energy (0..6)
*
* DESCRIPTION:
*
* Based on the R0, the average frame energy, we can get an
* upper bound on the energy any one subframe can take on.
* Using this upper bound we can calculate what right shift is
* needed to ensure an unsaturated output out of a subframe
* energy calculation (g_corr).
*
* REFERENCES: Sub-clause 4.1.9 and 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: spectral postfilter
*
*************************************************************************/
int16_t r0BasedEnergyShft(int16_t swR0Index)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int16_t swShiftDownSignal;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
if (sub(swR0Index, 26) <= 0)
{
if (sub(swR0Index, 23) <= 0)
{
if (sub(swR0Index, 21) <= 0)
swShiftDownSignal = 0; /* r0 [0, 21] */
else
swShiftDownSignal = 1; /* r0 [22, 23] */
}
else
{
if (sub(swR0Index, 24) <= 0)
swShiftDownSignal = 2; /* r0 [23, 24] */
else
swShiftDownSignal = 3; /* r0 [24, 26] */
}
}
else
{ /* r0 index > 26 */
if (sub(swR0Index, 28) <= 0)
{
swShiftDownSignal = 4; /* r0 [26, 28] */
}
else
{
if (sub(swR0Index, 29) <= 0)
swShiftDownSignal = 5; /* r0 [28, 29] */
else
swShiftDownSignal = 6; /* r0 [29, 31] */
}
}
if (sub(swR0Index, 18) > 0)
swShiftDownSignal = add(swShiftDownSignal, 2);
return (swShiftDownSignal);
}
/***************************************************************************
*
* FUNCTION NAME: rcToADp
*
* PURPOSE:
*
* This subroutine computes a vector of direct form LPC filter
* coefficients, given an input vector of reflection coefficients.
* Double precision is used internally, but 16 bit direct form
* filter coefficients are returned.
*
* INPUTS:
*
* NP
* order of the LPC filter (global constant)
*
* swAscale
* The multiplier which scales down the direct form
* filter coefficients.
*
* pswRc[0:NP-1]
* The input vector of reflection coefficients.
*
* OUTPUTS:
*
* pswA[0:NP-1]
* Array containing the scaled down direct form LPC
* filter coefficients.
*
* RETURN VALUE:
*
* siLimit
* 1 if limiting occured in computation, 0 otherwise.
*
* DESCRIPTION:
*
* This function performs the conversion from reflection coefficients
* to direct form LPC filter coefficients. The direct form coefficients
* are scaled by multiplication by swAscale. NP, the filter order is 10.
* The a's and rc's each have NP elements in them. Double precision
* calculations are used internally.
*
* The equations are:
* for i = 0 to NP-1{
*
* a(i)(i) = rc(i) (scaling by swAscale occurs here)
*
* for j = 0 to i-1
* a(i)(j) = a(i-1)(j) + rc(i)*a(i-1)(i-j-1)
* }
*
* See page 443, of
* "Digital Processing of Speech Signals" by L.R. Rabiner and R.W.
* Schafer; Prentice-Hall; Englewood Cliffs, NJ (USA). 1978.
*
* REFERENCES: Sub-clause 4.1.7 and 4.2.3 of GSM Recomendation 06.20
*
* KEYWORDS: reflectioncoefficients, parcors, conversion, rctoadp, ks, as
* KEYWORDS: parcorcoefficients, lpc, flat, vectorquantization
*
*************************************************************************/
short rcToADp(int16_t swAscale, int16_t pswRc[],
int16_t pswA[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t pL_ASpace[NP],
pL_tmpSpace[NP],
L_temp,
*pL_A,
*pL_tmp,
*pL_swap;
short int i,
j, /* loop counters */
siLimit;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Initialize starting addresses for temporary buffers */
/*-----------------------------------------------------*/
pL_A = pL_ASpace;
pL_tmp = pL_tmpSpace;
/* Initialize the flag for checking if limiting has occured */
/*----------------------------------------------------------*/
siLimit = 0;
/* Compute direct form filter coefficients, pswA[0],...,pswA[9] */
/*-------------------------------------------------------------------*/
for (i = 0; i < NP; i++)
{
pL_tmp[i] = L_mult(swAscale, pswRc[i]);
for (j = 0; j <= i - 1; j++)
{
L_temp = L_mpy_ls(pL_A[i - j - 1], pswRc[i]);
pL_tmp[j] = L_add(L_temp, pL_A[j]);
siLimit |= isLwLimit(pL_tmp[j]);
}
if (i != NP - 1)
{
/* Swap swA and swTmp buffers */
pL_swap = pL_tmp;
pL_tmp = pL_A;
pL_A = pL_swap;
}
}
for (i = 0; i < NP; i++)
{
pswA[i] = round(pL_tmp[i]);
siLimit |= isSwLimit(pswA[i]);
}
return (siLimit);
}
/***************************************************************************
*
* FUNCTION NAME: rcToCorrDpL
*
* PURPOSE:
*
* This subroutine computes an autocorrelation vector, given a vector
* of reflection coefficients as an input. Double precision calculations
* are used internally, and a double precision (int32_t)
* autocorrelation sequence is returned.
*
* INPUTS:
*
* NP
* LPC filter order passed in as a global constant.
*
* swAshift
* Number of right shifts to be applied to the
* direct form filter coefficients being computed
* as an intermediate step to generating the
* autocorrelation sequence.
*
* swAscale
* A multiplicative scale factor corresponding to
* swAshift; i.e. swAscale = 2 ^(-swAshift).
*
* pswRc[0:NP-1]
* An input vector of reflection coefficients.
*
* OUTPUTS:
*
* pL_R[0:NP]
* An output int32_t array containing the
* autocorrelation vector where
* pL_R[0] = 0x7fffffff; (i.e., ~1.0).
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* The algorithm used for computing the correlation sequence is
* described on page 232 of the book "Linear Prediction of Speech",
* by J.D. Markel and A.H. Gray, Jr.; Springer-Verlag, Berlin,
* Heidelberg, New York, 1976.
*
* REFERENCES: Sub_Clause 4.1.4 and 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: normalized autocorrelation, reflection coefficients
* KEYWORDS: conversion
*
**************************************************************************/
void rcToCorrDpL(int16_t swAshift, int16_t swAscale,
int16_t pswRc[], int32_t pL_R[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t pL_ASpace[NP],
pL_tmpSpace[NP],
L_temp,
L_sum,
*pL_A,
*pL_tmp,
*pL_swap;
short int i,
j; /* loop control variables */
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Set R[0] = 0x7fffffff, (i.e., R[0] = 1.0) */
/*-------------------------------------------*/
pL_R[0] = LW_MAX;
/* Assign an address onto each of the two temporary buffers */
/*----------------------------------------------------------*/
pL_A = pL_ASpace;
pL_tmp = pL_tmpSpace;
/* Compute correlations R[1],...,R[10] */
/*------------------------------------*/
for (i = 0; i < NP; i++)
{
/* Compute, as an intermediate step, the filter coefficients for */
/* for an i-th order direct form filter (pL_tmp[j],j=0,i) */
/*---------------------------------------------------------------*/
pL_tmp[i] = L_mult(swAscale, pswRc[i]);
for (j = 0; j <= i - 1; j++)
{
L_temp = L_mpy_ls(pL_A[i - j - 1], pswRc[i]);
pL_tmp[j] = L_add(L_temp, pL_A[j]);
}
/* Swap pL_A and pL_tmp buffers */
/*------------------------------*/
pL_swap = pL_A;
pL_A = pL_tmp;
pL_tmp = pL_swap;
/* Given the direct form filter coefficients for an i-th order filter */
/* and the autocorrelation vector computed up to and including stage i */
/* compute the autocorrelation coefficient R[i+1] */
/*---------------------------------------------------------------------*/
L_temp = L_mpy_ll(pL_A[0], pL_R[i]);
L_sum = L_negate(L_temp);
for (j = 1; j <= i; j++)
{
L_temp = L_mpy_ll(pL_A[j], pL_R[i - j]);
L_sum = L_sub(L_sum, L_temp);
}
pL_R[i + 1] = L_shl(L_sum, swAshift);
}
}
/***************************************************************************
*
* FUNCTION NAME: res_eng
*
* PURPOSE:
*
* Calculates square root of subframe residual energy estimate:
*
* sqrt( R(0)(1-k1**2)...(1-k10**2) )
*
* INPUTS:
*
* pswReflecCoefIn[0:9]
*
* Array of reflection coeffcients.
*
* swRq
*
* Subframe energy = sqrt(frame_energy * S_LEN/2**S_SH)
* (quantized).
*
* OUTPUTS:
*
* psnsSqrtRsOut
*
* (Pointer to) the output residual energy estimate.
*
* RETURN VALUE:
*
* The shift count of the normalized residual energy estimate, as int.
*
* DESCRIPTION:
*
* First, the canonic product of the (1-ki**2) terms is calculated
* (normalizations are done to maintain precision). Also, a factor of
* 2**S_SH is applied to the product to offset this same factor in the
* quantized square root of the subframe energy.
*
* Then the product is square-rooted, and multiplied by the quantized
* square root of the subframe energy. This combined product is put
* out as a normalized fraction and shift count (mantissa and exponent).
*
* REFERENCES: Sub-clause 4.1.7 and 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: residualenergy, res_eng, rs
*
*************************************************************************/
void res_eng(int16_t pswReflecCoefIn[], int16_t swRq,
struct NormSw *psnsSqrtRsOut)
{
/*_________________________________________________________________________
| |
| Local Constants |
|_________________________________________________________________________|
*/
#define S_SH 6 /* ceiling(log2(S_LEN)) */
#define MINUS_S_SH -S_SH
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Product,
L_Shift,
L_SqrtResEng;
int16_t swPartialProduct,
swPartialProductShift,
swTerm,
swShift,
swSqrtPP,
swSqrtPPShift,
swSqrtResEng,
swSqrtResEngShift;
short int i;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Form canonic product, maintain precision and shift count */
/*----------------------------------------------------------*/
/* (Start off with unity product (actually -1), and shift offset) */
/*----------------------------------------------------------------*/
swPartialProduct = SW_MIN;
swPartialProductShift = MINUS_S_SH;
for (i = 0; i < NP; i++)
{
/* Get next (-1 + k**2) term, form partial canonic product */
/*---------------------------------------------------------*/
swTerm = mac_r(LW_MIN, pswReflecCoefIn[i], pswReflecCoefIn[i]);
L_Product = L_mult(swTerm, swPartialProduct);
/* Normalize partial product, round */
/*----------------------------------*/
swShift = norm_s(extract_h(L_Product));
swPartialProduct = round(L_shl(L_Product, swShift));
swPartialProductShift = add(swPartialProductShift, swShift);
}
/* Correct sign of product, take square root */
/*-------------------------------------------*/
swPartialProduct = abs_s(swPartialProduct);
swSqrtPP = sqroot(L_deposit_h(swPartialProduct));
L_Shift = L_shr(L_deposit_h(swPartialProductShift), 1);
swSqrtPPShift = extract_h(L_Shift);
if (extract_l(L_Shift) != 0)
{
/* Odd exponent: shr above needs to be compensated by multiplying */
/* mantissa by sqrt(0.5) */
/*----------------------------------------------------------------*/
swSqrtPP = mult_r(swSqrtPP, SQRT_ONEHALF);
}
/* Form final product, the residual energy estimate, and do final */
/* normalization */
/*----------------------------------------------------------------*/
L_SqrtResEng = L_mult(swRq, swSqrtPP);
swShift = norm_l(L_SqrtResEng);
swSqrtResEng = round(L_shl(L_SqrtResEng, swShift));
swSqrtResEngShift = add(swSqrtPPShift, swShift);
/* Return */
/*--------*/
psnsSqrtRsOut->man = swSqrtResEng;
psnsSqrtRsOut->sh = swSqrtResEngShift;
return;
}
/***************************************************************************
*
* FUNCTION NAME: rs_rr
*
* PURPOSE:
*
* Calculates sqrt(RS/R(x,x)) using floating point format,
* where RS is the approximate residual energy in a given
* subframe and R(x,x) is the power in each long term
* predictor vector or in each codevector.
* Used in the joint optimization of the gain and the long
* term predictor coefficient.
*
* INPUTS:
*
* pswExcitation[0:39] - excitation signal array
* snsSqrtRs - structure sqrt(RS) normalized with mantissa and shift
*
* OUTPUTS:
*
* snsSqrtRsRr - structure sqrt(RS/R(x,x)) with mantissa and shift
*
* RETURN VALUE:
*
* None
*
* DESCRIPTION:
*
* Implemented as sqrt(RS)/sqrt(R(x,x)) where both sqrts
* are stored normalized (0.5<=x<1.0) and the associated
* shift. See section 4.1.11.1 for details
*
* REFERENCES: Sub-clause 4.1.11.1 and 4.2.1 of GSM
* Recomendation 06.20
*
* KEYWORDS: rs_rr, sqroot
*
*************************************************************************/
void rs_rr(int16_t pswExcitation[], struct NormSw snsSqrtRs,
struct NormSw *snsSqrtRsRr)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Temp;
int16_t swTemp,
swTemp2,
swEnergy,
swNormShift,
swShift;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
swEnergy = sub(shl(snsSqrtRs.sh, 1), 3); /* shift*2 + margin ==
* energy. */
if (swEnergy < 0)
{
/* High-energy residual: scale input vector during energy */
/* calculation. The shift count of the energy of the */
/* residual estimate is used as an estimate of the shift */
/* count needed for the excitation energy */
/*--------------------------------------------------------*/
swNormShift = g_corr1s(pswExcitation, negate(swEnergy), &L_Temp);
}
else
{
/* Lower-energy residual: no overflow protection needed */
/*------------------------------------------------------*/
swNormShift = g_corr1(pswExcitation, &L_Temp);
}
/* Compute single precision square root of energy sqrt(R(x,x)) */
/* ----------------------------------------------------------- */
swTemp = sqroot(L_Temp);
/* If odd no. of shifts compensate by sqrt(0.5) */
/* -------------------------------------------- */
if (swNormShift & 1)
{
/* Decrement no. of shifts in accordance with sqrt(0.5) */
/* ---------------------------------------------------- */
swNormShift = sub(swNormShift, 1);
/* sqrt(R(x,x) = sqrt(R(x,x)) * sqrt(0.5) */
/* -------------------------------------- */
L_Temp = L_mult(0x5a82, swTemp);
}
else
{
L_Temp = L_deposit_h(swTemp);
}
/* Normalize again and update shifts */
/* --------------------------------- */
swShift = norm_l(L_Temp);
swNormShift = add(shr(swNormShift, 1), swShift);
L_Temp = L_shl(L_Temp, swShift);
/* Shift sqrt(RS) to make sure less than divisor */
/* --------------------------------------------- */
swTemp = shr(snsSqrtRs.man, 1);
/* Divide sqrt(RS)/sqrt(R(x,x)) */
/* ---------------------------- */
swTemp2 = divide_s(swTemp, round(L_Temp));
/* Calculate shift for division, compensate for shift before division */
/* ------------------------------------------------------------------ */
swNormShift = sub(snsSqrtRs.sh, swNormShift);
swNormShift = sub(swNormShift, 1);
/* Normalize and get no. of shifts */
/* ------------------------------- */
swShift = norm_s(swTemp2);
snsSqrtRsRr->sh = add(swNormShift, swShift);
snsSqrtRsRr->man = shl(swTemp2, swShift);
}
/***************************************************************************
*
* FUNCTION NAME: rs_rrNs
*
* PURPOSE:
*
* Calculates sqrt(RS/R(x,x)) using floating point format,
* where RS is the approximate residual energy in a given
* subframe and R(x,x) is the power in each long term
* predictor vector or in each codevector.
*
* Used in the joint optimization of the gain and the long
* term predictor coefficient.
*
* INPUTS:
*
* pswExcitation[0:39] - excitation signal array
* snsSqrtRs - structure sqrt(RS) normalized with mantissa and shift
*
* OUTPUTS:
*
* snsSqrtRsRr - structure sqrt(RS/R(x,x)) with mantissa and shift
*
* RETURN VALUE:
*
* None
*
* DESCRIPTION:
*
* Implemented as sqrt(RS)/sqrt(R(x,x)) where both sqrts
* are stored normalized (0.5<=x<1.0) and the associated
* shift.
*
* REFERENCES: Sub-clause 4.1.11.1 and 4.2.1 of GSM
* Recomendation 06.20
*
* KEYWORDS: rs_rr, sqroot
*
*************************************************************************/
void rs_rrNs(int16_t pswExcitation[], struct NormSw snsSqrtRs,
struct NormSw *snsSqrtRsRr)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Temp;
int16_t swTemp,
swTemp2,
swNormShift,
swShift;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Lower-energy residual: no overflow protection needed */
/*------------------------------------------------------*/
swNormShift = g_corr1(pswExcitation, &L_Temp);
/* Compute single precision square root of energy sqrt(R(x,x)) */
/* ----------------------------------------------------------- */
swTemp = sqroot(L_Temp);
/* If odd no. of shifts compensate by sqrt(0.5) */
/* -------------------------------------------- */
if (swNormShift & 1)
{
/* Decrement no. of shifts in accordance with sqrt(0.5) */
/* ---------------------------------------------------- */
swNormShift = sub(swNormShift, 1);
/* sqrt(R(x,x) = sqrt(R(x,x)) * sqrt(0.5) */
/* -------------------------------------- */
L_Temp = L_mult(0x5a82, swTemp);
}
else
{
L_Temp = L_deposit_h(swTemp);
}
/* Normalize again and update shifts */
/* --------------------------------- */
swShift = norm_l(L_Temp);
swNormShift = add(shr(swNormShift, 1), swShift);
L_Temp = L_shl(L_Temp, swShift);
/* Shift sqrt(RS) to make sure less than divisor */
/* --------------------------------------------- */
swTemp = shr(snsSqrtRs.man, 1);
/* Divide sqrt(RS)/sqrt(R(x,x)) */
/* ---------------------------- */
swTemp2 = divide_s(swTemp, round(L_Temp));
/* Calculate shift for division, compensate for shift before division */
/* ------------------------------------------------------------------ */
swNormShift = sub(snsSqrtRs.sh, swNormShift);
swNormShift = sub(swNormShift, 1);
/* Normalize and get no. of shifts */
/* ------------------------------- */
swShift = norm_s(swTemp2);
snsSqrtRsRr->sh = add(swNormShift, swShift);
snsSqrtRsRr->man = shl(swTemp2, swShift);
}
/***************************************************************************
*
* FUNCTION NAME: scaleExcite
*
* PURPOSE:
*
* Scale an arbitrary excitation vector (codevector or
* pitch vector)
*
* INPUTS:
*
* pswVect[0:39] - the unscaled vector.
* iGsp0Scale - an positive offset to compensate for the fact
* that GSP0 table is scaled down.
* swErrTerm - rather than a gain being passed in, (beta, gamma)
* it is calculated from this error term - either
* Gsp0[][][0] error term A or Gsp0[][][1] error
* term B. Beta is calculated from error term A,
* gamma from error term B.
* snsRS - the RS_xx appropriate to pswVect.
*
* OUTPUTS:
*
* pswScldVect[0:39] - the output, scaled excitation vector.
*
* RETURN VALUE:
*
* swGain - One of two things. Either a clamped value of 0x7fff if the
* gain's shift was > 0 or the rounded vector gain otherwise.
*
* DESCRIPTION:
*
* If gain > 1.0 then
* (do not shift gain up yet)
* partially scale vector element THEN shift and round save
* else
* shift gain correctly
* scale vector element and round save
* update state array
*
* REFERENCES: Sub-clause 4.1.10.2 and 4.2.1 of GSM
* Recomendation 06.20
*
* KEYWORDS: excite_vl, sc_ex, excitevl, scaleexcite, codevector, p_vec,
* KEYWORDS: x_vec, pitchvector, gain, gsp0
*
*************************************************************************/
int16_t scaleExcite(int16_t pswVect[],
int16_t swErrTerm, struct NormSw snsRS,
int16_t pswScldVect[])
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_GainUs,
L_scaled,
L_Round_off;
int16_t swGain,
swGainUs,
swGainShift,
i,
swGainUsShft;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
L_GainUs = L_mult(swErrTerm, snsRS.man);
swGainUsShft = norm_s(extract_h(L_GainUs));
L_GainUs = L_shl(L_GainUs, swGainUsShft);
swGainShift = add(swGainUsShft, snsRS.sh);
swGainShift = sub(swGainShift, GSP0_SCALE);
/* gain > 1.0 */
/* ---------- */
if (swGainShift < 0)
{
swGainUs = round(L_GainUs);
L_Round_off = L_shl((long) 32768, swGainShift);
for (i = 0; i < S_LEN; i++)
{
L_scaled = L_mac(L_Round_off, swGainUs, pswVect[i]);
L_scaled = L_shr(L_scaled, swGainShift);
pswScldVect[i] = extract_h(L_scaled);
}
if (swGainShift == 0)
swGain = swGainUs;
else
swGain = 0x7fff;
}
/* gain < 1.0 */
/* ---------- */
else
{
/* shift down or not at all */
/* ------------------------ */
if (swGainShift > 0)
L_GainUs = L_shr(L_GainUs, swGainShift);
/* the rounded actual vector gain */
/* ------------------------------ */
swGain = round(L_GainUs);
/* now scale the vector (with rounding) */
/* ------------------------------------ */
for (i = 0; i < S_LEN; i++)
{
L_scaled = L_mac((long) 32768, swGain, pswVect[i]);
pswScldVect[i] = extract_h(L_scaled);
}
}
return (swGain);
}
/***************************************************************************
*
* FUNCTION NAME: spectralPostFilter
*
* PURPOSE:
*
* Perform spectral post filter on the output of the
* synthesis filter.
*
*
* INPUT:
*
* S_LEN a global constant
*
* pswSPFIn[0:S_LEN-1]
*
* input to the routine. Unmodified
* pswSPFIn[0] is the oldest point (first to be filtered),
* pswSPFIn[iLen-1] is the last pointer filtered,
* the newest.
*
* pswNumCoef[0:NP-1],pswDenomCoef[0:NP-1]
*
* numerator and denominator
* direct form coeffs used by postfilter.
* Exactly like lpc coefficients in format. Shifted down
* by iAShift to ensure that they are < 1.0.
*
* gpswPostFiltStateNum[0:NP-1], gpswPostFiltStateDenom[0:NP-1]
*
* array of the filter state.
* Same format as coefficients: *praState = state of
* filter for delay n = -1 praState[NP] = state of
* filter for delay n = -NP These numbers are not
* shifted at all. These states are static to this
* file.
*
* OUTPUT:
*
* gpswPostFiltStateNum[0:NP-1], gpswPostFiltStateDenom[0:NP-1]
*
* See above for description. These are updated.
*
* pswSPFOut[0:S_LEN-1]
*
* same format as pswSPFIn,
* *pswSPFOut is oldest point. The filtered output.
* Note this routine can handle pswSPFOut = pswSPFIn.
* output can be the same as input. i.e. in place
* calculation.
*
* RETURN:
*
* none
*
* DESCRIPTION:
*
* find energy in input,
* perform the numerator fir
* perform the denominator iir
* perform the post emphasis
* find energy in signal,
* perform the agc using energy in and energy in signam after
* post emphasis signal
*
* The spectral postfilter is described in section 4.2.4.
*
* REFERENCES: Sub-clause 4.2.4 of GSM Recomendation 06.20
*
* KEYWORDS: postfilter, emphasis, postemphasis, brightness,
* KEYWORDS: numerator, deminator, filtering, lpc,
*
*************************************************************************/
static void spectralPostFilter(int16_t pswSPFIn[],
int16_t pswNumCoef[],
int16_t pswDenomCoef[], int16_t pswSPFOut[])
{
/*_________________________________________________________________________
| |
| Local Constants |
|_________________________________________________________________________|
*/
#define AGC_COEF (int16_t)0x19a /* (1.0 - POST_AGC_COEF)
* 1.0-.9875 */
#define POST_EMPHASIS (int16_t)0x199a /* 0.2 */
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
short int i;
int32_t L_OrigEnergy,
L_runningGain,
L_Output;
int16_t swAgcGain,
swRunningGain,
swTemp;
struct NormSw snsOrigEnergy;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* calculate the energy in the input and save it */
/*-----------------------------------------------*/
snsOrigEnergy.sh = g_corr1s(pswSPFIn, swEngyRShift, &L_OrigEnergy);
snsOrigEnergy.man = round(L_OrigEnergy);
/* numerator of the postfilter */
/*-----------------------------*/
lpcFir(pswSPFIn, pswNumCoef, gpswPostFiltStateNum, pswSPFOut);
/* denominator of the postfilter */
/*-------------------------------*/
lpcIir(pswSPFOut, pswDenomCoef, gpswPostFiltStateDenom, pswSPFOut);
/* postemphasis section of postfilter */
/*------------------------------------*/
for (i = 0; i < S_LEN; i++)
{
swTemp = msu_r(L_deposit_h(pswSPFOut[i]), swPostEmphasisState,
POST_EMPHASIS);
swPostEmphasisState = pswSPFOut[i];
pswSPFOut[i] = swTemp;
}
swAgcGain = agcGain(pswSPFOut, snsOrigEnergy, swEngyRShift);
/* scale the speech vector */
/*-----------------------------*/
swRunningGain = gswPostFiltAgcGain;
L_runningGain = L_deposit_h(gswPostFiltAgcGain);
for (i = 0; i < S_LEN; i++)
{
L_runningGain = L_msu(L_runningGain, swRunningGain, AGC_COEF);
L_runningGain = L_mac(L_runningGain, swAgcGain, AGC_COEF);
swRunningGain = extract_h(L_runningGain);
/* now scale input with gain */
L_Output = L_mult(swRunningGain, pswSPFOut[i]);
pswSPFOut[i] = extract_h(L_shl(L_Output, 2));
}
gswPostFiltAgcGain = swRunningGain;
}
/***************************************************************************
*
* FUNCTION NAME: speechDecoder
*
* PURPOSE:
* The purpose of this function is to call all speech decoder
* subroutines. This is the top level routine for the speech
* decoder.
*
* INPUTS:
*
* pswParameters[0:21]
*
* pointer to this frame's parameters. See below for input
* data format.
*
* OUTPUTS:
*
* pswDecodedSpeechFrame[0:159]
*
* this frame's decoded 16 bit linear pcm frame
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* The sequence of events in the decoder, and therefore this routine
* follow a simple plan. First, the frame based parameters are
* decoded. Second, on a subframe basis, the subframe based
* parameters are decoded and the excitation is generated. Third,
* on a subframe basis, the combined and scaled excitation is
* passed through the synthesis filter, and then the pitch and
* spectral postfilters.
*
* The in-line comments for the routine speechDecoder, are very
* detailed. Here in a more consolidated form, are the main
* points.
*
* The R0 parameter is decoded using the lookup table
* psrR0DecTbl[]. The LPC codewords are looked up using lookupVQ().
* The decoded parameters are reflection coefficients
* (pswFrmKs[]).
*
* The decoder does not use reflection coefficients directly.
* Instead it converts them to direct form coeficients. This is
* done using rcToADp(). If this conversion results in invalid
* results, the previous frames parameters are used.
*
* The direct form coeficients are used to derive the spectal
* postfilter's numerator and denominator coeficients. The
* denominators coefficients are widened, and the numerators
* coefficients are a spectrally smoothed version of the
* denominator. The smoothing is done with a_sst().
*
* The frame based LPC coefficients are either used directly as the
* subframe coefficients, or are derived through interpolation.
* The subframe based coeffiecients are calculated in getSfrmLpc().
*
* Based on voicing mode, the decoder will construct and scale the
* excitation in one of two ways. For the voiced mode the lag is
* decoded using lagDecode(). The fractional pitch LTP lookup is
* done by the function fp_ex(). In both voiced and unvoiced
* mode, the VSELP codewords are decoded into excitation vectors
* using b_con() and v_con().
*
* rs_rr(), rs_rrNs(), and scaleExcite() are used to calculate
* the gamma's, codevector gains, as well as beta, the LTP vector
* gain. Description of this can be found in section 4.1.11. Once
* the vectors have been scaled and combined, the excitation is
* stored in the LTP history.
*
* The excitation, pswExcite[], passes through the pitch pre-filter
* (pitchPreFilt()). Then the harmonically enhanced excitation
* passes through the synthesis filter, lpcIir(), and finally the
* reconstructed speech passes through the spectral post-filter
* (spectalPostFilter()). The final output speech is passed back in
* the array pswDecodedSpeechFrame[].
*
* INPUT DATA FORMAT:
*
* The format/content of the input parameters is the so called
* bit alloc format.
*
* voiced mode bit alloc format:
* -----------------------------
* index number of bits parameter name
* 0 5 R0
* 1 11 k1Tok3
* 2 9 k4Tok6
* 3 8 k7Tok10
* 4 1 softInterpolation
* 5 2 voicingDecision
* 6 8 frameLag
* 7 9 code_1
* 8 5 gsp0_1
* 9 4 deltaLag_2
* 10 9 code_2
* 11 5 gsp0_2
* 12 4 deltaLag_3
* 13 9 code_3
* 14 5 gsp0_3
* 15 4 deltaLag_4
* 16 9 code_4
* 17 5 gsp0_4
*
* 18 1 BFI
* 19 1 UFI
* 20 2 SID
* 21 1 TAF
*
*
* unvoiced mode bit alloc format:
* -------------------------------
*
* index number of bits parameter name
* 0 5 R0
* 1 11 k1Tok3
* 2 9 k4Tok6
* 3 8 k7Tok10
* 4 1 softInterpolation
* 5 2 voicingDecision
* 6 7 code1_1
* 7 7 code2_1
* 8 5 gsp0_1
* 9 7 code1_2
* 10 7 code2_2
* 11 5 gsp0_2
* 12 7 code1_3
* 13 7 code2_3
* 14 5 gsp0_3
* 15 7 code1_4
* 16 7 code2_4
* 17 5 gsp0_4
*
* 18 1 BFI
* 19 1 UFI
* 20 2 SID
* 21 1 TAF
*
*
* REFERENCES: Sub_Clause 4.2 of GSM Recomendation 06.20
*
* KEYWORDS: synthesis, speechdecoder, decoding
* KEYWORDS: codewords, lag, codevectors, gsp0
*
*************************************************************************/
void speechDecoder(int16_t pswParameters[],
int16_t pswDecodedSpeechFrame[])
{
/*_________________________________________________________________________
| |
| Local Static Variables |
|_________________________________________________________________________|
*/
static int16_t
*pswLtpStateOut = &pswLtpStateBaseDec[LTP_LEN],
pswSythAsSpace[NP * N_SUB],
pswPFNumAsSpace[NP * N_SUB],
pswPFDenomAsSpace[NP * N_SUB],
*ppswSynthAs[N_SUB] = {
&pswSythAsSpace[0],
&pswSythAsSpace[10],
&pswSythAsSpace[20],
&pswSythAsSpace[30],
},
*ppswPFNumAs[N_SUB] = {
&pswPFNumAsSpace[0],
&pswPFNumAsSpace[10],
&pswPFNumAsSpace[20],
&pswPFNumAsSpace[30],
},
*ppswPFDenomAs[N_SUB] = {
&pswPFDenomAsSpace[0],
&pswPFDenomAsSpace[10],
&pswPFDenomAsSpace[20],
&pswPFDenomAsSpace[30],
};
static int16_tRom
psrSPFDenomWidenCf[NP] = {
0x6000, 0x4800, 0x3600, 0x2880, 0x1E60,
0x16C8, 0x1116, 0x0CD0, 0x099C, 0x0735,
};
static int32_t L_RxPNSeed; /* DTX mode */
static int16_t swRxDtxGsIndex; /* DTX mode */
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
short int i,
j,
siLagCode,
siGsp0Code,
psiVselpCw[2],
siVselpCw,
siNumBits,
siCodeBook;
int16_t pswFrmKs[NP],
pswFrmAs[NP],
pswFrmPFNum[NP],
pswFrmPFDenom[NP],
pswPVec[S_LEN],
ppswVselpEx[2][S_LEN],
pswExcite[S_LEN],
pswPPFExcit[S_LEN],
pswSynthFiltOut[S_LEN],
swR0Index,
swLag,
swSemiBeta,
pswBitArray[MAXBITS];
struct NormSw psnsSqrtRs[N_SUB],
snsRs00,
snsRs11,
snsRs22;
int16_t swMutePermit,
swLevelMean,
swLevelMax, /* error concealment */
swMuteFlag; /* error concealment */
int16_t swTAF,
swSID,
swBfiDtx; /* DTX mode */
int16_t swFrameType; /* DTX mode */
int32_t L_RxDTXGs; /* DTX mode */
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* -------------------------------------------------------------------- */
/* do bad frame handling (error concealment) and comfort noise */
/* insertion */
/* -------------------------------------------------------------------- */
/* This flag indicates whether muting is performed in the actual frame */
/* ------------------------------------------------------------------- */
swMuteFlag = 0;
/* This flag indicates whether muting is allowed in the actual frame */
/* ----------------------------------------------------------------- */
swMutePermit = 0;
/* frame classification */
/* -------------------- */
swSID = pswParameters[20];
swTAF = pswParameters[21];
swBfiDtx = pswParameters[18] | pswParameters[19]; /* BFI | UFI */
if ((swSID == 2) && (swBfiDtx == 0))
swFrameType = VALIDSID;
else if ((swSID == 0) && (swBfiDtx == 0))
swFrameType = GOODSPEECH;
else if ((swSID == 0) && (swBfiDtx != 0))
swFrameType = UNUSABLE;
else
swFrameType = INVALIDSID;
/* update of decoder state */
/* ----------------------- */
if (swDecoMode == SPEECH)
{
/* speech decoding mode */
/* -------------------- */
if (swFrameType == VALIDSID)
swDecoMode = CNIFIRSTSID;
else if (swFrameType == INVALIDSID)
swDecoMode = CNIFIRSTSID;
else if (swFrameType == UNUSABLE)
swDecoMode = SPEECH;
else if (swFrameType == GOODSPEECH)
swDecoMode = SPEECH;
}
else
{
/* comfort noise insertion mode */
/* ---------------------------- */
if (swFrameType == VALIDSID)
swDecoMode = CNICONT;
else if (swFrameType == INVALIDSID)
swDecoMode = CNICONT;
else if (swFrameType == UNUSABLE)
swDecoMode = CNIBFI;
else if (swFrameType == GOODSPEECH)
swDecoMode = SPEECH;
}
if (swDecoMode == SPEECH)
{
/* speech decoding mode */
/* -------------------- */
/* Perform parameter concealment, depending on BFI (pswParameters[18]) */
/* or UFI (pswParameters[19]) */
/* ------------------------------------------------------------------- */
para_conceal_speech_decoder(&pswParameters[18],
pswParameters, &swMutePermit);
/* copy the frame rate parameters */
/* ------------------------------ */
swR0Index = pswParameters[0]; /* R0 Index */
pswVq[0] = pswParameters[1]; /* LPC1 */
pswVq[1] = pswParameters[2]; /* LPC2 */
pswVq[2] = pswParameters[3]; /* LPC3 */
swSi = pswParameters[4]; /* INT_LPC */
swVoicingMode = pswParameters[5]; /* MODE */
/* lookup R0 and VQ parameters */
/* --------------------------- */
swR0Dec = psrR0DecTbl[swR0Index * 2]; /* R0 */
lookupVq(pswVq, pswFrmKs);
/* save this frames GS values */
/* -------------------------- */
for (i = 0; i < N_SUB; i++)
{
pL_RxGsHist[swRxGsHistPtr] =
ppLr_gsTable[swVoicingMode][pswParameters[(i * 3) + 8]];
swRxGsHistPtr++;
if (swRxGsHistPtr > ((OVERHANG - 1) * N_SUB) - 1)
swRxGsHistPtr = 0;
}
/* DTX variables */
/* ------------- */
swDtxBfiCnt = 0;
swDtxMuting = 0;
swRxDTXState = CNINTPER - 1;
}
else
{
/* comfort noise insertion mode */
/*----------------------------- */
/* copy the frame rate parameters */
/* ------------------------------ */
swR0Index = pswParameters[0]; /* R0 Index */
pswVq[0] = pswParameters[1]; /* LPC1 */
pswVq[1] = pswParameters[2]; /* LPC2 */
pswVq[2] = pswParameters[3]; /* LPC3 */
swSi = 1; /* INT_LPC */
swVoicingMode = 0; /* MODE */
/* bad frame handling in comfort noise insertion mode */
/* -------------------------------------------------- */
if (swDecoMode == CNIFIRSTSID) /* first SID frame */
{
swDtxBfiCnt = 0;
swDtxMuting = 0;
swRxDTXState = CNINTPER - 1;
if (swFrameType == VALIDSID) /* valid SID frame */
{
swR0NewCN = psrR0DecTbl[swR0Index * 2];
lookupVq(pswVq, pswFrmKs);
}
else if (swFrameType == INVALIDSID) /* invalid SID frame */
{
swR0NewCN = psrR0DecTbl[swOldR0IndexDec * 2];
swR0Index = swOldR0IndexDec;
for (i = 0; i < NP; i++)
pswFrmKs[i] = pswOldFrmKsDec[i];
}
}
else if (swDecoMode == CNICONT) /* SID frame detected, but */
{ /* not the first SID */
swDtxBfiCnt = 0;
swDtxMuting = 0;
if (swFrameType == VALIDSID) /* valid SID frame */
{
swRxDTXState = 0;
swR0NewCN = psrR0DecTbl[swR0Index * 2];
lookupVq(pswVq, pswFrmKs);
}
else if (swFrameType == INVALIDSID) /* invalid SID frame */
{
if (swRxDTXState < (CNINTPER - 1))
swRxDTXState = add(swRxDTXState, 1);
swR0Index = swOldR0IndexDec;
}
}
else if (swDecoMode == CNIBFI) /* bad frame received in */
{ /* CNI mode */
if (swRxDTXState < (CNINTPER - 1))
swRxDTXState = add(swRxDTXState, 1);
swR0Index = swOldR0IndexDec;
if (swDtxMuting == 1)
{
swOldR0IndexDec = sub(swOldR0IndexDec, 2); /* attenuate
* by 4 dB */
if (swOldR0IndexDec < 0)
swOldR0IndexDec = 0;
swR0Index = swOldR0IndexDec;
swR0NewCN = psrR0DecTbl[swOldR0IndexDec * 2]; /* R0 */
}
swDtxBfiCnt = add(swDtxBfiCnt, 1);
if ((swTAF == 1) && (swDtxBfiCnt >= (2 * CNINTPER + 1))) /* 25 */
swDtxMuting = 1;
}
if (swDecoMode == CNIFIRSTSID)
{
/* the first SID frame is received */
/* ------------------------------- */
/* initialize the decoders pn-generator */
/* ------------------------------------ */
L_RxPNSeed = PN_INIT_SEED;
/* using the stored rx history, generate averaged GS */
/* ------------------------------------------------- */
avgGsHistQntz(pL_RxGsHist, &L_RxDTXGs);
swRxDtxGsIndex = gsQuant(L_RxDTXGs, 0);
}
/* Replace the "transmitted" subframe parameters with */
/* synthetic ones */
/* -------------------------------------------------- */
for (i = 0; i < 4; i++)
{
/* initialize the GSP0 parameter */
pswParameters[(i * 3) + 8] = swRxDtxGsIndex;
/* CODE1 */
pswParameters[(i * 3) + 6] = getPnBits(7, &L_RxPNSeed);
/* CODE2 */
pswParameters[(i * 3) + 7] = getPnBits(7, &L_RxPNSeed);
}
/* Interpolation of CN parameters */
/* ------------------------------ */
rxInterpR0Lpc(pswOldFrmKsDec, pswFrmKs, swRxDTXState,
swDecoMode, swFrameType);
}
/* ------------------- */
/* do frame processing */
/* ------------------- */
/* generate the direct form coefs */
/* ------------------------------ */
if (!rcToADp(ASCALE, pswFrmKs, pswFrmAs))
{
/* widen direct form coefficients using the widening coefs */
/* ------------------------------------------------------- */
for (i = 0; i < NP; i++)
{
pswFrmPFDenom[i] = mult_r(pswFrmAs[i], psrSPFDenomWidenCf[i]);
}
a_sst(ASHIFT, ASCALE, pswFrmPFDenom, pswFrmPFNum);
}
else
{
for (i = 0; i < NP; i++)
{
pswFrmKs[i] = pswOldFrmKsDec[i];
pswFrmAs[i] = pswOldFrmAsDec[i];
pswFrmPFDenom[i] = pswOldFrmPFDenom[i];
pswFrmPFNum[i] = pswOldFrmPFNum[i];
}
}
/* interpolate, or otherwise get sfrm reflection coefs */
/* --------------------------------------------------- */
getSfrmLpc(swSi, swOldR0Dec, swR0Dec, pswOldFrmKsDec, pswOldFrmAsDec,
pswOldFrmPFNum, pswOldFrmPFDenom, pswFrmKs, pswFrmAs,
pswFrmPFNum, pswFrmPFDenom, psnsSqrtRs, ppswSynthAs,
ppswPFNumAs, ppswPFDenomAs);
/* calculate shift for spectral postfilter */
/* --------------------------------------- */
swEngyRShift = r0BasedEnergyShft(swR0Index);
/* ----------------------- */
/* do sub-frame processing */
/* ----------------------- */
for (giSfrmCnt = 0; giSfrmCnt < 4; giSfrmCnt++)
{
/* copy this sub-frame's parameters */
/* -------------------------------- */
if (sub(swVoicingMode, 0) == 0)
{ /* unvoiced */
psiVselpCw[0] = pswParameters[(giSfrmCnt * 3) + 6]; /* CODE_1 */
psiVselpCw[1] = pswParameters[(giSfrmCnt * 3) + 7]; /* CODE_2 */
siGsp0Code = pswParameters[(giSfrmCnt * 3) + 8]; /* GSP0 */
}
else
{ /* voiced */
siLagCode = pswParameters[(giSfrmCnt * 3) + 6]; /* LAG */
psiVselpCw[0] = pswParameters[(giSfrmCnt * 3) + 7]; /* CODE */
siGsp0Code = pswParameters[(giSfrmCnt * 3) + 8]; /* GSP0 */
}
/* for voiced mode, reconstruct the pitch vector */
/* --------------------------------------------- */
if (swVoicingMode)
{
/* convert delta lag to lag and convert to fractional lag */
/* ------------------------------------------------------ */
swLag = lagDecode(siLagCode);
/* state followed by out */
/* --------------------- */
fp_ex(swLag, pswLtpStateOut);
/* extract a piece of pswLtpStateOut into newly named vector pswPVec */
/* ----------------------------------------------------------------- */
for (i = 0; i < S_LEN; i++)
{
pswPVec[i] = pswLtpStateOut[i];
}
}
/* for unvoiced, do not reconstruct a pitch vector */
/* ----------------------------------------------- */
else
{
swLag = 0; /* indicates invalid lag
* and unvoiced */
}
/* now work on the VSELP codebook excitation output */
/* x_vec, x_a_vec here named ppswVselpEx[0] and [1] */
/* ------------------------------------------------ */
if (swVoicingMode)
{ /* voiced */
siNumBits = C_BITS_V;
siVselpCw = psiVselpCw[0];
b_con(siVselpCw, siNumBits, pswBitArray);
v_con(pppsrVcdCodeVec[0][0], ppswVselpEx[0], pswBitArray, siNumBits);
}
else
{ /* unvoiced */
siNumBits = C_BITS_UV;
for (siCodeBook = 0; siCodeBook < 2; siCodeBook++)
{
siVselpCw = psiVselpCw[siCodeBook];
b_con(siVselpCw, siNumBits, (int16_t *) pswBitArray);
v_con(pppsrUvCodeVec[siCodeBook][0], ppswVselpEx[siCodeBook],
pswBitArray, siNumBits);
}
}
/* all excitation vectors have been created: ppswVselpEx and pswPVec */
/* if voiced compute rs00 and rs11; if unvoiced cmpute rs11 and rs22 */
/* ------------------------------------------------------------------ */
if (swLag)
{
rs_rr(pswPVec, psnsSqrtRs[giSfrmCnt], &snsRs00);
}
rs_rrNs(ppswVselpEx[0], psnsSqrtRs[giSfrmCnt], &snsRs11);
if (!swVoicingMode)
{
rs_rrNs(ppswVselpEx[1], psnsSqrtRs[giSfrmCnt], &snsRs22);
}
/* now implement synthesis - combine the excitations */
/* ------------------------------------------------- */
if (swVoicingMode)
{ /* voiced */
/* scale pitch and codebook excitations and get beta */
/* ------------------------------------------------- */
swSemiBeta = scaleExcite(pswPVec,
pppsrGsp0[swVoicingMode][siGsp0Code][0],
snsRs00, pswPVec);
scaleExcite(ppswVselpEx[0],
pppsrGsp0[swVoicingMode][siGsp0Code][1],
snsRs11, ppswVselpEx[0]);
/* combine the two scaled excitations */
/* ---------------------------------- */
for (i = 0; i < S_LEN; i++)
{
pswExcite[i] = add(pswPVec[i], ppswVselpEx[0][i]);
}
}
else
{ /* unvoiced */
/* scale codebook excitations and set beta to 0 as not applicable */
/* -------------------------------------------------------------- */
swSemiBeta = 0;
scaleExcite(ppswVselpEx[0],
pppsrGsp0[swVoicingMode][siGsp0Code][0],
snsRs11, ppswVselpEx[0]);
scaleExcite(ppswVselpEx[1],
pppsrGsp0[swVoicingMode][siGsp0Code][1],
snsRs22, ppswVselpEx[1]);
/* combine the two scaled excitations */
/* ---------------------------------- */
for (i = 0; i < S_LEN; i++)
{
pswExcite[i] = add(ppswVselpEx[1][i], ppswVselpEx[0][i]);
}
}
/* now update the pitch state using the combined/scaled excitation */
/* --------------------------------------------------------------- */
for (i = 0; i < LTP_LEN; i++)
{
pswLtpStateBaseDec[i] = pswLtpStateBaseDec[i + S_LEN];
}
/* add the current sub-frames data to the state */
/* -------------------------------------------- */
for (i = -S_LEN, j = 0; j < S_LEN; i++, j++)
{
pswLtpStateOut[i] = pswExcite[j];/* add new frame at t = -S_LEN */
}
/* given the excitation perform pitch prefiltering */
/* ----------------------------------------------- */
pitchPreFilt(pswExcite, siGsp0Code, swLag,
swVoicingMode, swSemiBeta, psnsSqrtRs[giSfrmCnt],
pswPPFExcit, pswPPreState);
/* Concealment on subframe signal level: */
/* ------------------------------------- */
level_estimator(0, &swLevelMean, &swLevelMax,
&pswDecodedSpeechFrame[giSfrmCnt * S_LEN]);
signal_conceal_sub(pswPPFExcit, ppswSynthAs[giSfrmCnt], pswSynthFiltState,
&pswLtpStateOut[-S_LEN], &pswPPreState[LTP_LEN - S_LEN],
swLevelMean, swLevelMax,
pswParameters[19], swMuteFlagOld,
&swMuteFlag, swMutePermit);
/* synthesize the speech through the synthesis filter */
/* -------------------------------------------------- */
lpcIir(pswPPFExcit, ppswSynthAs[giSfrmCnt], pswSynthFiltState,
pswSynthFiltOut);
/* pass reconstructed speech through adaptive spectral postfilter */
/* -------------------------------------------------------------- */
spectralPostFilter(pswSynthFiltOut, ppswPFNumAs[giSfrmCnt],
ppswPFDenomAs[giSfrmCnt],
&pswDecodedSpeechFrame[giSfrmCnt * S_LEN]);
level_estimator(1, &swLevelMean, &swLevelMax,
&pswDecodedSpeechFrame[giSfrmCnt * S_LEN]);
}
/* Save muting information for next frame */
/* -------------------------------------- */
swMuteFlagOld = swMuteFlag;
/* end of frame processing - save this frame's frame energy, */
/* reflection coefs, direct form coefs, and post filter coefs */
/* ---------------------------------------------------------- */
swOldR0Dec = swR0Dec;
swOldR0IndexDec = swR0Index; /* DTX mode */
for (i = 0; i < NP; i++)
{
pswOldFrmKsDec[i] = pswFrmKs[i];
pswOldFrmAsDec[i] = pswFrmAs[i];
pswOldFrmPFNum[i] = pswFrmPFNum[i];
pswOldFrmPFDenom[i] = pswFrmPFDenom[i];
}
}
/***************************************************************************
*
* FUNCTION NAME: sqroot
*
* PURPOSE:
*
* The purpose of this function is to perform a single precision square
* root function on a int32_t
*
* INPUTS:
*
* L_SqrtIn
* input to square root function
*
* OUTPUTS:
*
* none
*
* RETURN VALUE:
*
* swSqrtOut
* output to square root function
*
* DESCRIPTION:
*
* Input assumed to be normalized
*
* The algorithm is based around a six term Taylor expansion :
*
* y^0.5 = (1+x)^0.5
* ~= 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3)
* - 0.625*((x/2)^4) + 0.875*((x/2)^5)
*
* Max error less than 0.08 % for normalized input ( 0.5 <= x < 1 )
*
* REFERENCES: Sub-clause 4.1.4.1, 4.1.7, 4.1.11.1, 4.2.1,
* 4.2.2, 4.2.3 and 4.2.4 of GSM Recomendation 06.20
*
* KEYWORDS: sqrt, squareroot, sqrt016
*
*************************************************************************/
int16_t sqroot(int32_t L_SqrtIn)
{
/*_________________________________________________________________________
| |
| Local Constants |
|_________________________________________________________________________|
*/
#define PLUS_HALF 0x40000000L /* 0.5 */
#define MINUS_ONE 0x80000000L /* -1 */
#define TERM5_MULTIPLER 0x5000 /* 0.625 */
#define TERM6_MULTIPLER 0x7000 /* 0.875 */
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Temp0,
L_Temp1;
int16_t swTemp,
swTemp2,
swTemp3,
swTemp4,
swSqrtOut;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* determine 2nd term x/2 = (y-1)/2 */
/* -------------------------------- */
L_Temp1 = L_shr(L_SqrtIn, 1); /* L_Temp1 = y/2 */
L_Temp1 = L_sub(L_Temp1, PLUS_HALF); /* L_Temp1 = (y-1)/2 */
swTemp = extract_h(L_Temp1); /* swTemp = x/2 */
/* add contribution of 2nd term */
/* ---------------------------- */
L_Temp1 = L_sub(L_Temp1, MINUS_ONE); /* L_Temp1 = 1 + x/2 */
/* determine 3rd term */
/* ------------------ */
L_Temp0 = L_msu(0L, swTemp, swTemp); /* L_Temp0 = -(x/2)^2 */
swTemp2 = extract_h(L_Temp0); /* swTemp2 = -(x/2)^2 */
L_Temp0 = L_shr(L_Temp0, 1); /* L_Temp0 = -0.5*(x/2)^2 */
/* add contribution of 3rd term */
/* ---------------------------- */
L_Temp0 = L_add(L_Temp1, L_Temp0); /* L_Temp0 = 1 + x/2 - 0.5*(x/2)^2 */
/* determine 4rd term */
/* ------------------ */
L_Temp1 = L_msu(0L, swTemp, swTemp2);/* L_Temp1 = (x/2)^3 */
swTemp3 = extract_h(L_Temp1); /* swTemp3 = (x/2)^3 */
L_Temp1 = L_shr(L_Temp1, 1); /* L_Temp1 = 0.5*(x/2)^3 */
/* add contribution of 4rd term */
/* ---------------------------- */
/* L_Temp1 = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 */
L_Temp1 = L_add(L_Temp0, L_Temp1);
/* determine partial 5th term */
/* -------------------------- */
L_Temp0 = L_mult(swTemp, swTemp3); /* L_Temp0 = (x/2)^4 */
swTemp4 = round(L_Temp0); /* swTemp4 = (x/2)^4 */
/* determine partial 6th term */
/* -------------------------- */
L_Temp0 = L_msu(0L, swTemp2, swTemp3); /* L_Temp0 = (x/2)^5 */
swTemp2 = round(L_Temp0); /* swTemp2 = (x/2)^5 */
/* determine 5th term and add its contribution */
/* ------------------------------------------- */
/* L_Temp0 = -0.625*(x/2)^4 */
L_Temp0 = L_msu(0L, TERM5_MULTIPLER, swTemp4);
/* L_Temp1 = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 - 0.625*(x/2)^4 */
L_Temp1 = L_add(L_Temp0, L_Temp1);
/* determine 6th term and add its contribution */
/* ------------------------------------------- */
/* swSqrtOut = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 */
/* - 0.625*(x/2)^4 + 0.875*(x/2)^5 */
swSqrtOut = mac_r(L_Temp1, TERM6_MULTIPLER, swTemp2);
/* return output */
/* ------------- */
return (swSqrtOut);
}
/***************************************************************************
*
* FUNCTION NAME: v_con
*
* PURPOSE:
*
* This subroutine constructs a codebook excitation
* vector from basis vectors
*
* INPUTS:
*
* pswBVects[0:siNumBVctrs*S_LEN-1]
*
* Array containing a set of basis vectors.
*
* pswBitArray[0:siNumBVctrs-1]
*
* Bit array dictating the polarity of the
* basis vectors in the output vector.
* Each element of the bit array is either -0.5 or +0.5
*
* siNumBVctrs
* Number of bits in codeword
*
* OUTPUTS:
*
* pswOutVect[0:39]
*
* Array containing the contructed output vector
*
* RETURN VALUE:
*
* none
*
* DESCRIPTION:
*
* The array pswBitArray is used to multiply each of the siNumBVctrs
* basis vectors. The input pswBitArray[] is an array whose
* elements are +/-0.5. These multiply the VSELP basis vectors and
* when summed produce a VSELP codevector. b_con() is the function
* used to translate a VSELP codeword into pswBitArray[].
*
*
* REFERENCES: Sub-clause 4.1.10 and 4.2.1 of GSM Recomendation 06.20
*
* KEYWORDS: v_con, codeword, reconstruct, basis vector, excitation
*
*************************************************************************/
void v_con(int16_t pswBVects[], int16_t pswOutVect[],
int16_t pswBitArray[], short int siNumBVctrs)
{
/*_________________________________________________________________________
| |
| Automatic Variables |
|_________________________________________________________________________|
*/
int32_t L_Temp;
short int siSampleCnt,
siCVectCnt;
/*_________________________________________________________________________
| |
| Executable Code |
|_________________________________________________________________________|
*/
/* Sample loop */
/*--------------*/
for (siSampleCnt = 0; siSampleCnt < S_LEN; siSampleCnt++)
{
/* First element of output vector */
L_Temp = L_mult(pswBitArray[0], pswBVects[0 * S_LEN + siSampleCnt]);
/* Construct output vector */
/*-------------------------*/
for (siCVectCnt = 1; siCVectCnt < siNumBVctrs; siCVectCnt++)
{
L_Temp = L_mac(L_Temp, pswBitArray[siCVectCnt],
pswBVects[siCVectCnt * S_LEN + siSampleCnt]);
}
/* store the output vector sample */
/*--------------------------------*/
L_Temp = L_shl(L_Temp, 1);
pswOutVect[siSampleCnt] = extract_h(L_Temp);
}
}