FreeCalypso > hg > gsmhr-codec-ref
diff dtx.c @ 0:9008dbc8ca74
import original C code from GSM 06.06
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 14 Jun 2024 23:27:16 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dtx.c Fri Jun 14 23:27:16 2024 +0000 @@ -0,0 +1,1341 @@ +/*************************************************************************** + * + * File Name: dtx.c + * + * Purpose: DTX and comfort noise functions of the GSM half rate + * system + * + * Reference: Recommendation GSM 06.41 (DTX) + * Recommendation GSM 06.22 (Comfort Noise) + * + * 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. + * + * Evaluation of comfort noise parameters + * swComfortNoise() + * updateCNHist() + * avgGsHistQntz() + * gsQuant() + * avgCNHist() + * lpcCorrQntz() + * getPnBits() + * + * Interpolation of comfort noise parameters + * rxInterpR0Lpc() + * linInterpSid() + * + **************************************************************************/ + +/*________________________________________________________________________ + | | + | Include Files | + |________________________________________________________________________| +*/ + +#include "typedefs.h" +#include "mathhalf.h" +#include "mathdp31.h" +#include "dtx.h" +#include "sp_dec.h" +#include "sp_rom.h" +#include "sp_frm.h" + +/*________________________________________________________________________ + | | + | Defines | + |________________________________________________________________________| +*/ + +#define PN_XOR_REG (Longword)0x00000005L +#define PN_XOR_ADD (Longword)0x40000000L + +#define OH_SHIFT 3 /* shift corresponding to OVERHANG */ + +#define NP_AFLAT 4 +#define LPC_VQ_SEG 3 + +#define ASHIFT 4 +#define ASCALE 0x0800 + + +/*________________________________________________________________________ + | | + | Global Variables | + |________________________________________________________________________| +*/ + +Shortword swVadFrmCnt = 0; /* Indicates the number of sequential + * frames where VAD == 0 */ + +short int siUpdPointer = 0; +Shortword swNElapsed = 50; + + +Longword pL_GsHist[N_SUB * (OVERHANG - 1)]; + + +/*________________________________________________________________________ + | | + | Other External Variables | + |________________________________________________________________________| +*/ + +extern int iLimit; + +extern Shortword swR0Dec, + swOldR0Dec, + swR0NewCN; + +extern Shortword swCNR0, + pswCNLpc[], + pswCNGsp0Code[], + pswCNVSCode1[], + pswCNVSCode2[]; + +/*________________________________________________________________________ + | | + | DTX Rom Tables | + |________________________________________________________________________| +*/ + +/* interpolation curve for comfort noise (i*1/12) i=1..12 */ +Shortword psrCNNewFactor[12] = {0x0aaa, 0x1554, 0x1ffe, 0x2aa8, 0x3552, + 0x3ffc, 0x4aa6, 0x5550, 0x5ffa, 0x6aa4, +0x754e, 0x7fff}; + + +/* Values of GS for voicing state 0, all values shifted down by 2 + shifts */ +LongwordRom ppLr_gsTable[4][32] = +{ + { + 0x000011ab, 0x000038d2, 0x0000773e, 0x000144ef, + 0x00035675, 0x000648c5, 0x000c3d65, 0x0017ae17, + 0x002a3dbb, 0x005238e7, 0x00695c1a, 0x00a60d45, + 0x00e4cc68, 0x01c3ba6a, 0x019e3c96, 0x02d1fbac, + 0x030453ec, 0x0549a998, 0x05190298, 0x08258920, + 0x08daff30, 0x0c3150e0, 0x0e45d850, 0x14c111a0, + 0x0ff7e1c0, 0x18a06860, 0x13810400, 0x1abc9ee0, + 0x28500940, 0x41f22800, 0x22fc5040, 0x2cd90180 + }, + + { + 0x00003ede, 0x00021fc9, 0x0013f0c3, 0x003a7be2, + 0x007a6663, 0x00fe3773, 0x012fabf4, 0x02275cd0, + 0x01c0ef14, 0x02c0b1d8, 0x0350fc70, 0x05505078, + 0x04175f30, 0x052c1098, 0x08ed3310, 0x0a63b470, + 0x05417870, 0x08995ee0, 0x07bbe018, 0x0a19fa10, + 0x0b5818c0, 0x0fd96ea0, 0x0e5cad10, 0x13b40d40, + 0x12d45840, 0x14577320, 0x2b2e5e00, 0x333e9640, + 0x194c35c0, 0x1c30f8c0, 0x2d16db00, 0x2cc970ff + }, + { + 0x002f18e7, 0x00a47be0, 0x01222efe, 0x01c42df8, + 0x024be794, 0x03424c40, 0x036950fc, 0x04973108, + 0x038405b4, 0x05d8c8f0, 0x05063e08, 0x070cdea0, + 0x05812be8, 0x06da5fc8, 0x088fcd60, 0x0a013cb0, + 0x0909a460, 0x09e6cf40, 0x0ee581d0, 0x0ec99f20, + 0x0b4e7470, 0x0c730e80, 0x0ff39d20, 0x105d0d80, + 0x158b0b00, 0x172babe0, 0x14576460, 0x181a6720, + 0x26126e80, 0x1f590180, 0x1fdaad60, 0x2e0e8000 + }, + { + 0x00c7f603, 0x01260cda, 0x01b3926a, 0x026d82bc, + 0x0228fba0, 0x036ec5b0, 0x034bf4cc, 0x043a55d0, + 0x044f9c20, 0x05c66f50, 0x0515f890, 0x06065300, + 0x0665dc00, 0x0802b630, 0x0737a1c0, 0x087294e0, + 0x09253fc0, 0x0a619760, 0x097bd060, 0x0a6d4e50, + 0x0d19e520, 0x0e15c420, 0x0c4e4eb0, 0x0e8880e0, + 0x11cdf480, 0x12c85800, 0x10f4c0a0, 0x13e51b00, + 0x189dbaa0, 0x18a6bb60, 0x22e31500, 0x21615240 + } +}; + +/************************************************************************* + * + * FUNCTION NAME: swComfortNoise + * + * PURPOSE: + * + * This routine perform the following tasks: + * - generation of the speech flag (swSP) + * - averaging and encoding of the comfort noise parameters + * - randomization of the codebook indices + * + * + * INPUTS: + * + * swVadFrmCnt (global) - swVadFlag=0 frame counter. + * If swVadFlag=1 then this counter is 0, the first frame with + * swVadFlag=0 will set this counter to 1, with each additional + * swVadFlag=0 frame the counter is incremented. + * + * swVadFlag - voise activity flag. swVadFlag=0 frame with + * no voice activity, swVadFlag=0 frame with voice activity + * + * L_UnqntzdR0 - unquantized R(0), 32 bit value, output of + * FLAT. + * + * pL_UnqntzdCorr[NP+1] - unquantized correlation sequence, + * also an output of FLAT. + * + * + * OUTPUTS: + * + * swCNR0 - global variable, the output quantized R0 index + * + * pswCNLpc[3] - global variable, the output quantized LPC to the + * transmitted in the SID frame + * + * pswCNGsp0Code[N_SUB] - global variable, the output quantized GSP0 indices + * + * pswCNVSCode1[N_SUB] - global variable, the output quantized codevector 1 + * indices. + * + * pswCNVSCode2[N_SUB] - global variable, the output quantized codevector 2 + * indices. + * + * + * RETURN VALUE: + * + * swSP - speech flag, swSP=1 speech frames are generated, swSP=0 + * SID frames are generated. + * + *************************************************************************/ + +Shortword swComfortNoise(Shortword swVadFlag, + Longword L_UnqntzdR0, Longword *pL_UnqntzdCorr) +{ + +/*________________________________________________________________________ + | | + | Static Variables | + |________________________________________________________________________| +*/ + + /* history of unquantized parameters */ + static Longword pL_R0Hist[OVERHANG]; + static Longword ppL_CorrHist[OVERHANG][NP + 1]; + + /* quantized reference parameters */ + static Shortword swQntRefR0, + swRefGsIndex; + static int piRefVqCodewds[3]; + + /* handling of short speech bursts */ + static Shortword swShortBurst; + + /* state value of random generator */ + static Longword L_TxPNSeed; + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword swSP; + Shortword pswFinalRc[NP]; + + /* unquantized reference parameters */ + Longword L_RefR0; + Longword pL_RefCorr[NP + 1]; + Longword L_RefGs; + + int i; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + swSP = 1; + + /* VadFrmCnt will indicate the number of sequential frames where */ + /* swVadFlag == 0 */ + /* ------------------------------------------------------------- */ + + if (swVadFlag) + swVadFrmCnt = 0; /* Voice acitvity present */ + else + swVadFrmCnt = add(swVadFrmCnt, 1); /* no voice activity */ + + + /* swNElapsed will indicate the number of frames that have elapsed */ + /* since the last SID frame with updated comfort noise parameters */ + /* was generated */ + /* --------------------------------------------------------------- */ + + swNElapsed = add(swNElapsed, 1); + + + /* If no voice activity was detected. */ + /* ----------------------------------- */ + + if (swVadFrmCnt) + { + + /* Short speech burst ? */ + /* -------------------- */ + + if (swVadFrmCnt == 1) + { + if (sub(swNElapsed, 24) < 0) + swShortBurst = 1; /* short speech burst detected */ + else + swShortBurst = 0; /* long speech burst detected */ + } + + + /* Update history, with this frames data */ + /* ------------------------------------- */ + + updateCNHist(L_UnqntzdR0, pL_UnqntzdCorr, + pL_R0Hist, ppL_CorrHist); + + + /* first SID frame */ + /* --------------- */ + + if (((swShortBurst == 0) && (swVadFrmCnt == OVERHANG)) || + ((swShortBurst == 1) && (swVadFrmCnt == 1))) + { + + /* init. random generator */ + /* ---------------------- */ + L_TxPNSeed = PN_INIT_SEED; + + + /* average GS */ + /* ---------- */ + avgGsHistQntz(pL_GsHist, &L_RefGs); + + + /* GS quantization */ + /* --------------- */ + swRefGsIndex = gsQuant(L_RefGs, 0); + + } + + + /* No Overhang in case of short speech bursts, */ + /* generate SID frames with repeated comfort noise parameters */ + /* ---------------------------------------------------------- */ + + if ((swShortBurst == 1) && (swVadFrmCnt < OVERHANG)) + { + + /* generate a SID frame with repeated parameters */ + /* --------------------------------------------- */ + + swSP = 0; + + + /* repeat data: r0, LPC, GS */ + /* ------------------------ */ + + swCNR0 = swQntRefR0; + + for (i = 0; i < 3; i++) + pswCNLpc[i] = piRefVqCodewds[i]; + + for (i = 0; i < N_SUB; i++) + pswCNGsp0Code[i] = swRefGsIndex; + + } + + + /* generate SID frames with updated comfort noise parameters */ + /* --------------------------------------------------------- */ + + if (swVadFrmCnt >= OVERHANG) + { + + /* A SID frame with updated parameters */ + /* ----------------------------------- */ + + swSP = 0; + swNElapsed = 0; + + + /* average R0 and correlation values */ + /* --------------------------------- */ + + avgCNHist(pL_R0Hist, ppL_CorrHist, &L_RefR0, + pL_RefCorr); + + + /* now quantize the averaged R(0) */ + /* ------------------------------ */ + + swQntRefR0 = r0Quant(L_RefR0); + + + /* Quantize the averaged correlation */ + /* --------------------------------- */ + + lpcCorrQntz(pL_RefCorr, + pswFinalRc, + piRefVqCodewds); + + + /* update frame data: r0, LPC */ + /* -------------------------- */ + + swCNR0 = swQntRefR0; + for (i = 0; i < 3; i++) + pswCNLpc[i] = piRefVqCodewds[i]; + + + /* update subframe data (unvoiced mode): GSP0 */ + /* ------------------------------------------ */ + + for (i = 0; i < N_SUB; i++) + pswCNGsp0Code[i] = swRefGsIndex; + + } + + + /* random codevectors */ + /* ------------------ */ + + if (swSP == 0) + { + for (i = 0; i < N_SUB; i++) + { + pswCNVSCode1[i] = getPnBits(7, &L_TxPNSeed); + pswCNVSCode2[i] = getPnBits(7, &L_TxPNSeed); + } + } + + + } + + return (swSP); +} + + +/************************************************************************* + * + * FUNCTION NAME: updateCNHist + * + * PURPOSE: + * + * Add current frame's unquantized R(0) and LPC information to the + * comfort noise history, so that it will be available for + * averaging. + * + * INPUTS: + * + * Unquantized values from the coder: + * + * + * L_UnqntzdR0 - unquantized frame energy R(0), an output of FLAT + * + * pL_UnqntzdCorr[NP+1] - unquantized correlation coefficient + * array. Also an output of FLAT. + * + * siUpdPointer (global) - A modulo counter which counts up from + * 0 to OVERHANG-1. + * + * OUTPUTS: + * + * pL_R0History[OVERHANG] - history of the OVERHANG frames worth of + * R(0). + * + * ppL_CorrHistory[OVERHANG][NP+1] - - history of the OVERHANG + * frames worth of pL_UnqntzdCorr[]. + * + * RETURN VALUE: + * + * none + * + *************************************************************************/ + +void updateCNHist(Longword L_UnqntzdR0, + Longword *pL_UnqntzdCorr, + Longword pL_R0History[], + Longword ppL_CorrHistory[OVERHANG][NP + 1]) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + int i; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /* update */ + pL_R0History[siUpdPointer] = L_UnqntzdR0; + + for (i = 0; i < NP + 1; i++) + ppL_CorrHistory[siUpdPointer][i] = pL_UnqntzdCorr[i]; + + siUpdPointer = (siUpdPointer + 1) % OVERHANG; +} + + +/************************************************************************* + * + * FUNCTION NAME: avgGsHistQntz + * + * PURPOSE: + * + * Average gs history, where history is of length OVERHANG-1 + * frames. The last frame's (i.e. this frame) gs values are not + * available since quantization would have occured only after the + * VAD decision is made. + * + * INPUTS: + * + * pL_GsHistory[(OVERHANG-1)*N_SUB] - the GS of the past + * OVERHANG-1 frames. The GS values are stored shifted down by 2 + * shifts to avoid overflow (the largest GS is greater than 2.0). + * + * + * OUTPUTS: + * + * *pL_GsAvgd - the average of pL_GsHistory[], also shifted down + * by two shifts. + * + * RETURN VALUE: + * + * none. + * + * + *************************************************************************/ + +void avgGsHistQntz(Longword pL_GsHistory[], Longword *pL_GsAvgd) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + int i; + Longword L_avg; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + L_avg = L_shift_r(pL_GsHistory[0], -(OH_SHIFT + 2)); + + for (i = 1; i < N_SUB * (OVERHANG - 1); i++) + L_avg = L_add(L_shift_r(pL_GsHistory[i], -(OH_SHIFT + 2)), L_avg); + + /* avg number x/32 not x/28 */ + + *pL_GsAvgd = L_add(L_avg, L_mpy_ls(L_avg, 0x1249)); /* L_avg *= 32/28 */ + +} + + +/************************************************************************* + * + * FUNCTION NAME: gsQuant + * + * PURPOSE: + * + * Quantize a value of gs in any of the voicing modes. Input GS + * is a 32 bit number. The GSP0 index is returned. + * + * INPUTS: + * + * L_GsIn - 32 bit GS value, shifted down by 2 shifts. + * + * swVoicingMode - voicing level + * + * ppLr_gsTable[4][32] - Rom GS Table. (global), all GS values + * have been shifted down by 2 from their true value. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * + * GSP0 Index closest to the input value of GS. + * + * + *************************************************************************/ + +Shortword gsQuant(Longword L_GsIn, Shortword swVoicingMode) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword swGsIndex, + swBestGs; + Longword L_diff, + L_min = LW_MAX; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + for (swGsIndex = 0; swGsIndex < 32; swGsIndex++) + { + L_diff = L_abs(L_sub(L_GsIn, ppLr_gsTable[swVoicingMode][swGsIndex])); + + if (L_sub(L_diff, L_min) < 0) + { + /* new minimum */ + /* ----------- */ + + swBestGs = swGsIndex; + L_min = L_diff; + + } + } + + return (swBestGs); + +} + + +/************************************************************************* + * + * FUNCTION NAME: avgCNHist + * + * PURPOSE: + * + * Average the unquantized R0 and LPC data stored at the encoder + * to arrive at an average R0 and LPC frame for use in a SID + * frame. + * + * INPUTS: + * + * pL_R0History[OVERHANG] - contains unquantized R(0) data from the + * most recent OVERHANG frame (including this one). + * + * ppL_CorrHistory[OVERHANG][NP+1] - Unquantized correlation + * coefficients from the most recent OVERHANG frame (including this + * one). The data stored here is an output of FLAT. + * + * OUTPUTS: + * + * *pL_AvgdR0 - the average of pL_R0History[] + * + * pL_AvgdCorrSeq[NP+1] - the average of ppL_CorrHistory[][]. + * + * + * RETURN VALUE: + * + * none + * + *************************************************************************/ + +void avgCNHist(Longword pL_R0History[], + Longword ppL_CorrHistory[OVERHANG][NP + 1], + Longword *pL_AvgdR0, + Longword pL_AvgdCorrSeq[]) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + int i, + j; + Longword L_avg; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /* R0 Averaging */ + /* ------------ */ + + for (L_avg = 0, i = 0; i < OVERHANG; i++) + L_avg = L_add(L_shr(pL_R0History[i], OH_SHIFT), L_avg); + + *pL_AvgdR0 = L_avg; + + + /* LPC: average the last OVERHANG frames */ + /* ------------------------------------- */ + + for (j = 0; j < NP + 1; j++) + { + for (L_avg = 0, i = 0; i < OVERHANG; i++) + { + L_avg = L_add(L_shift_r(ppL_CorrHistory[i][j], -OH_SHIFT), L_avg); + } + + pL_AvgdCorrSeq[j] = L_avg; + } + +} + + +/*************************************************************************** + * + * FUNCTION NAME: lpcCorrQntz + * + * PURPOSE: Quantize a correlation sequence + * + * + * INPUT: + * + * pL_CorrelSeq[NP+1] + * Correlation sequence to quantize. + * + * OUTPUTS: + * + * pswFinalRc[0:NP-1] + * A quantized set of NP reflection coefficients. + * + * piVQCodewds[0:2] + * An array containing the indices of the 3 reflection + * coefficient vectors selected from the three segment + * Rc-VQ. + * + * RETURN: + * None. + * + * KEYWORDS: AFLAT,aflat,flat,vectorquantization, reflectioncoefficients + * + *************************************************************************/ + +void lpcCorrQntz(Longword pL_CorrelSeq[], + Shortword pswFinalRc[], + int piVQCodewds[]) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword pswPOldSpace[NP_AFLAT], + pswPNewSpace[NP_AFLAT], + pswVOldSpace[2 * NP_AFLAT - 1], + pswVNewSpace[2 * NP_AFLAT - 1], + *ppswPAddrs[2], + *ppswVAddrs[2], + *pswVBar, + pswPBar[NP_AFLAT], + pswVBarSpace[2 * NP_AFLAT - 1], + pswFlatsRc[NP], /* Unquantized Rc's computed by FLAT */ + pswRc[NP + 1]; /* Temp list for the converted RC's */ + Longword *pL_VBarFull, + pL_PBarFull[NP], + pL_VBarFullSpace[2 * NP - 1]; + + int i, + iVec, + iSeg, + iCnt; /* Loop counter */ + struct QuantList quantList, /* A list of vectors */ + bestPql[4]; /* The four best vectors from + * the PreQ */ + struct QuantList bestQl[LPC_VQ_SEG + 1]; /* Best vectors for each of + * the three segments */ + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /* Setup pointers temporary space */ + /*--------------------------------*/ + + pswVBar = pswVBarSpace + NP_AFLAT - 1; + pL_VBarFull = pL_VBarFullSpace + NP - 1; + ppswPAddrs[0] = pswPOldSpace; + ppswPAddrs[1] = pswPNewSpace; + ppswVAddrs[0] = pswVOldSpace + NP_AFLAT - 1; + ppswVAddrs[1] = pswVNewSpace + NP_AFLAT - 1; + + + /* Set up pL_PBarFull and pL_VBarFull initial conditions, using the */ + /* autocorrelation sequence derived from the optimal reflection */ + /* coefficients computed by FLAT. The initial conditions are shifted */ + /* right by RSHIFT bits. These initial conditions, stored as */ + /* Longwords, are used to initialize PBar and VBar arrays for the */ + /* next VQ segment. */ + /*--------------------------------------------------------------------*/ + + initPBarFullVBarFullL(pL_CorrelSeq, pL_PBarFull, pL_VBarFull); + + /* Set up initial PBar and VBar initial conditions, using pL_PBarFull */ + /* and pL_VBarFull arrays initialized above. These are the initial */ + /* PBar and VBar conditions to be used by the AFLAT recursion at the */ + /* 1-st Rc-VQ segment. */ + /*--------------------------------------------------------------------*/ + + initPBarVBarL(pL_PBarFull, pswPBar, pswVBar); + + for (iSeg = 1; iSeg <= LPC_VQ_SEG; iSeg++) + { + /* initialize candidate list */ + /*---------------------------*/ + + quantList.iNum = psrPreQSz[iSeg - 1]; + quantList.iRCIndex = 0; + + /* do aflat for all vectors in the list */ + /*--------------------------------------*/ + + setupPreQ(iSeg, quantList.iRCIndex); /* set up vector ptrs */ + + for (iCnt = 0; iCnt < quantList.iNum; iCnt++) + { + /* get a vector */ + /*--------------*/ + + getNextVec(pswRc); + + /* clear the limiter flag */ + /*------------------------*/ + + iLimit = 0; + + /* find the error values for each vector */ + /*---------------------------------------*/ + + quantList.pswPredErr[iCnt] = + aflatRecursion(&pswRc[psvqIndex[iSeg - 1].l], + pswPBar, pswVBar, + ppswPAddrs, ppswVAddrs, + psvqIndex[iSeg - 1].len); + + /* check the limiter flag */ + /*------------------------*/ + + if (iLimit) + quantList.pswPredErr[iCnt] = 0x7fff; /* set error to bad value */ + + } /* done list loop */ + + /* find 4 best prequantizer levels */ + /*---------------------------------*/ + + findBestInQuantList(quantList, 4, bestPql); + + for (iVec = 0; iVec < 4; iVec++) + { + + /* initialize quantizer list */ + /*---------------------------*/ + + quantList.iNum = psrQuantSz[iSeg - 1]; + quantList.iRCIndex = bestPql[iVec].iRCIndex * psrQuantSz[iSeg - 1]; + + setupQuant(iSeg, quantList.iRCIndex); /* set up vector ptrs */ + + /* do aflat recursion on each element of list */ + /*--------------------------------------------*/ + + for (iCnt = 0; iCnt < quantList.iNum; iCnt++) + { + /* get a vector */ + /*--------------*/ + + getNextVec(pswRc); + + /* clear the limiter flag */ + /*------------------------*/ + + iLimit = 0; + + /* find the error values for each vector */ + /*---------------------------------------*/ + + quantList.pswPredErr[iCnt] = + aflatRecursion(&pswRc[psvqIndex[iSeg - 1].l], + pswPBar, pswVBar, + ppswPAddrs, ppswVAddrs, + psvqIndex[iSeg - 1].len); + + /* check the limiter flag */ + /*------------------------*/ + + if (iLimit) + quantList.pswPredErr[iCnt] = 0x7fff; /* set error to the worst + * value */ + + } /* done list loop */ + + /* find best quantizer vector for this segment, and save it */ + /*----------------------------------------------------------*/ + + findBestInQuantList(quantList, 1, bestQl); + if (iVec == 0) + bestQl[iSeg] = bestQl[0]; + else if (sub(bestQl[iSeg].pswPredErr[0], bestQl[0].pswPredErr[0]) > 0) + bestQl[iSeg] = bestQl[0]; + + } + + /* find the quantized reflection coefficients */ + /*--------------------------------------------*/ + + setupQuant(iSeg, bestQl[iSeg].iRCIndex); /* set up vector ptrs */ + getNextVec((Shortword *) (pswFinalRc - 1)); + + + /* Update pBarFull and vBarFull for the next Rc-VQ segment, and */ + /* update the pswPBar and pswVBar for the next Rc-VQ segment */ + /*--------------------------------------------------------------*/ + + if (iSeg < LPC_VQ_SEG) + aflatNewBarRecursionL(&pswFinalRc[psvqIndex[iSeg - 1].l - 1], iSeg, + pL_PBarFull, pL_VBarFull, pswPBar, pswVBar); + + } + + /* find the quantizer index (the values to be output in the symbol file) */ + /*-----------------------------------------------------------------*/ + + for (iSeg = 1; iSeg <= LPC_VQ_SEG; iSeg++) + piVQCodewds[iSeg - 1] = bestQl[iSeg].iRCIndex; + +} + + +/************************************************************************* + * + * FUNCTION NAME: getPnBits + * + * PURPOSE: + * + * Generate iBits pseudo-random bits using *pL_PNSeed as the + * pn-generators seed. + * + * INPUTS: + * + * iBits - integer indicating how many random bits to return. + * range [0,15], 0 yields 1 bit output + * + * *pL_PNSeed - 32 bit seed (changed by function) + * + * OUTPUTS: + * + * *pL_PNSeed - 32 bit seed, modified. + * + * RETURN VALUE: + * + * random bits in iBits LSB's. + * + * + * IMPLEMENTATION: + * + * implementation of x**31 + x**3 + 1 == PN_XOR_REG | PN_XOR_ADD a + * PN sequence generator using Longwords generating a 2**31 -1 + * length pn-sequence. + * + *************************************************************************/ + +Shortword getPnBits(int iBits, Longword *pL_PNSeed) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword swPnBits = 0; + Longword L_Taps, + L_FeedBack; + int i; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + for (i = 0; i < iBits; i++) + { + /* update the state */ + /* ---------------- */ + + L_Taps = *pL_PNSeed & PN_XOR_REG; + L_FeedBack = L_Taps; /* Xor tap bits to yield + * feedback bit */ + L_Taps = L_shr(L_Taps, 1); + + while (L_Taps) + { + L_FeedBack = L_FeedBack ^ L_Taps; + L_Taps = L_shr(L_Taps, 1); + } + + /* LSB of L_FeedBack is next MSB of PN register */ + + *pL_PNSeed = L_shr(*pL_PNSeed, 1); + if (L_FeedBack & 1) + *pL_PNSeed = *pL_PNSeed | PN_XOR_ADD; + + /* State update complete. Get the output bit from the state, add/or it + * into output */ + + swPnBits = shl(swPnBits, 1); + swPnBits = swPnBits | (extract_l(*pL_PNSeed) & 0x0001); + + } + return (swPnBits); +} + + +/************************************************************************* + * + * FUNCTION NAME: rxInterpR0Lpc + * + * PURPOSE: + * + * Perform part of the comfort noise algorithm at the decoder. + * LPC and R0 are derived in this routine + * + * INPUTS: + * + * pswOldKs - Last frame's reflection coeffs. + * + * pswNewKs - This frame's decoded/received reflection coeffs. + * This will serve a new endpoint in interpolation. + * + * swRxDTXState - primary DTX state variable (at the receiver). A + * modulo 12 counter, which is 0 at SID frame. + * + * swDecoMode - actual mode the decoder: speech decoding mode + * or comfort noise insertion mode (SPEECH = speech decoding; + * CNIFIRSTSID = comfort noise, 1st SID received; CNICONT = comfort + * noise, SID frame received, but not 1st SID; CNIBFI = comfort + * noise, bad frame received) + * + * swFrameType - type of the received frame (VALIDSID, INVALIDSID + * GOODSPEECH or UNUSABLE) + * + * swOldR0Dec - global variable, the decoded R0 value from the last + * frame . This will be modified. + * + * swR0NewCN - global variable the decoded R0 value from the frame + * just received. Valid information if current frame is a SID frame. + * + * + * OUTPUTS: + * + * pswNewKs - This frames LPC coeffs. modified to reflect + * interpolated correlation sequence pL_CorrSeq[]. + * + * swR0Dec - global variable, interpolated R0 value + * + * swR0OldCN - global variable, R0 interpolation point to + * interpolate from. + * + * swR0NewCN - global variable, R0 interpolation point to + * interpolate to. + * + * pL_OldCorrSeq[NP+1] - global variable, starting point for + * interpolation of LPC information. + * + * pL_NewCorrSeq[NP+1] - global variable, end point for + * interpolation of LPC information. + * + * pL_CorrSeq[NP+1] - global variable, interpolated value of LPC + * information to be used in this frame. + * + * + * RETURN VALUE: + * + * None. + * + * KEYWORDS: interpolation, comfort noise, SID, DTX + * + *************************************************************************/ + +void rxInterpR0Lpc(Shortword *pswOldKs, Shortword *pswNewKs, + Shortword swRxDTXState, + Shortword swDecoMode, Shortword swFrameType) +{ + +/*________________________________________________________________________ + | | + | Static Variables | + |________________________________________________________________________| +*/ + + static Shortword swR0OldCN; + static Longword pL_OldCorrSeq[NP + 1], + pL_NewCorrSeq[NP + 1], + pL_CorrSeq[NP + 1]; + + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + int i; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + if (swDecoMode == CNIFIRSTSID) + { + /* first SID frame arrived */ + /* ----------------------- */ + + /* use tx'd R0 frame as both endpoints of interp curve. */ + /* i.e. no interpolation for the first frames */ + /* ---------------------------------------------------- */ + + + swR0OldCN = swOldR0Dec; /* last non-SID, received R0 */ + swR0Dec = linInterpSidShort(swR0NewCN, swR0OldCN, swRxDTXState); + + + /* generate the LPC end points for interpolation */ + /* --------------------------------------------- */ + + rcToCorrDpL(ASHIFT, ASCALE, pswOldKs, pL_OldCorrSeq); + rcToCorrDpL(ASHIFT, ASCALE, pswNewKs, pL_NewCorrSeq); + + /* linearly interpolate between the two sets of correlation coefs */ + /* -------------------------------------------------------------- */ + + for (i = 0; i < NP + 1; i++) + { + pL_CorrSeq[i] = linInterpSid(pL_NewCorrSeq[i], pL_OldCorrSeq[i], + swRxDTXState); + } + + /* Generate this frames K's (overwrite input) */ + /* ------------------------------------------ */ + + aFlatRcDp(pL_CorrSeq, pswNewKs); + + } + else if ((swDecoMode == CNICONT) && (swFrameType == VALIDSID)) + { + /* new (not the first) SID frame arrived */ + /* ------------------------------------- */ + + swR0OldCN = swOldR0Dec; /* move current state of R0 to old */ + swR0Dec = linInterpSidShort(swR0NewCN, swR0OldCN, swRxDTXState); + + + /* LPC: generate new endpoints for interpolation */ + /* --------------------------------------------- */ + + for (i = 0; i < NP + 1; i++) + { + pL_OldCorrSeq[i] = pL_CorrSeq[i]; + } + + rcToCorrDpL(ASHIFT, ASCALE, pswNewKs, pL_NewCorrSeq); + + + /* linearly interpolate between the two sets of correlation coefs */ + /* -------------------------------------------------------------- */ + + for (i = 0; i < NP + 1; i++) + { + pL_CorrSeq[i] = linInterpSid(pL_NewCorrSeq[i], pL_OldCorrSeq[i], + swRxDTXState); + } + + + /* Use interpolated LPC for this frame, overwrite the input K's */ + /* ------------------------------------------------------------ */ + + aFlatRcDp(pL_CorrSeq, pswNewKs); + + } + else + { + /* in between SID frames / invalid SID frames */ + /* ------------------------------------------ */ + + swR0Dec = linInterpSidShort(swR0NewCN, swR0OldCN, swRxDTXState); + + + /* linearly interpolate between the two sets of correlation coefs */ + /* -------------------------------------------------------------- */ + + for (i = 0; i < NP + 1; i++) + { + pL_CorrSeq[i] = linInterpSid(pL_NewCorrSeq[i], pL_OldCorrSeq[i], + swRxDTXState); + } + + + /* Use interpolated LPC for this frame, overwrite the input K's */ + /* ------------------------------------------------------------ */ + + aFlatRcDp(pL_CorrSeq, pswNewKs); + + } +} + + +/************************************************************************* + * + * FUNCTION NAME: linInterpSid + * + * PURPOSE: + * + * Linearly interpolate between two input numbers based on what the + * current DtxState is. + * + * INPUTS: + * + * L_New - longword more current value + * + * L_Old - longword oldest value + * + * swDtxState - state is 0 at the transmitted SID Frame. + * + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * A value between old and new inputs with dtxState+1/12 of the new + * (dtxState+1)-12/12 of the old + * + * + *************************************************************************/ + +Longword linInterpSid(Longword L_New, Longword L_Old, Shortword swDtxState) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword swOldFactor; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /* old factor = (1.0 - newFactor) */ + /* ------------------------------ */ + + swOldFactor = sub(0x7fff, psrCNNewFactor[swDtxState]); + swOldFactor = add(0x1, swOldFactor); + + + /* contributions from new and old */ + /* ------------------------------ */ + + L_New = L_mpy_ls(L_New, psrCNNewFactor[swDtxState]); + L_Old = L_mpy_ls(L_Old, swOldFactor); + + return (L_add(L_New, L_Old)); + +} + + +/************************************************************************* + * + * FUNCTION NAME: linInterpSidShort + * + * PURPOSE: + * + * Linearly interpolate between two input numbers based on what + * the current DtxState is. + * + * INPUTS: + * + * swNew - 16 bit, more current value + * + * swOld - 16 bit, oldest value + * + * swDtxState - state is 0 at the transmitted SID Frame. + * + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * A value between old and new inputs with dtxState+1/12 of the new + * (dtxState+1)-12/12 of the old + * + *************************************************************************/ + +Shortword linInterpSidShort(Shortword swNew, Shortword swOld, + Shortword swDtxState) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword swOldFactor; + Longword L_New, + L_Old; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /* old factor = (1.0 - newFactor) */ + /* ------------------------------ */ + + swOldFactor = sub(0x7fff, psrCNNewFactor[swDtxState]); + swOldFactor = add(0x1, swOldFactor); + + + /* contributions from new and old */ + /* ------------------------------ */ + + L_New = L_mult(swNew, psrCNNewFactor[swDtxState]); + L_Old = L_mult(swOld, swOldFactor); + + + return (round(L_add(L_New, L_Old))); + +}