diff sp_frm.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/sp_frm.c	Fri Jun 14 23:27:16 2024 +0000
@@ -0,0 +1,5908 @@
+/***************************************************************************
+ *
+ *   File Name:  sp_frm.c
+ *
+ *   Purpose:  Contains all functions for frame-based processing in the
+ *      speech encoder.  The frame-based processing yields the following:
+ *      energy in the speech signal, LPC filter coefficients, perceptually-
+ *      weighted filter coefficients (for H(z) and C(z)), perceptually-
+ *      weighted speech, voicing level, and constrained adaptive-codebook
+ *      (long-term predictor) choices.
+ *
+ *     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.
+ *
+ *     High pass filtering:
+ *       filt4_2nd()
+ *         iir_d()
+ *
+ *     AFLAT, vector quantization of LPC coefficients:
+ *       aflat()
+ *         aflatNewBarRecursionL()
+ *         aflatRecursion()
+ *         findBestInQuantList()
+ *         getNextVec()
+ *         initPBarVBarFullL()
+ *         initPBarVBarL()
+ *         setupPreQ()
+ *         setupQuant()
+ *
+ *     FLAT:  derivation of the unquantized LPC coefficients:
+ *       flat()
+ *         cov32()
+ *         r0Quant()
+ *
+ *
+ *     Generation of LPC filters for each subframe:
+ *       getSfrmLpcTx()
+ *         compResidEnergy()
+ *
+ *     Perceptual weighting:
+ *       weightSpeechFrame()
+ *
+ *     Generation of the noise weighting filter:
+ *       getNWCoefs()
+ *
+ *     Open loop lag search:
+ *       openLoopLagSearch()
+ *         bestDelta()
+ *           maxCCOverGWithSign()
+ *         getCCThreshold()
+ *           fnExp2()
+ *           fnLog2()
+ *         pitchLags()
+ *           CGInterp()
+ *           CGInterpValid()
+ *           findPeak()
+ *           fnBest_CG()
+ *           quantLag()
+ *
+ **************************************************************************/
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Include Files                                |
+ |_________________________________________________________________________|
+*/
+
+#include "mathhalf.h"
+#include "mathdp31.h"
+#include "sp_rom.h"
+#include "sp_dec.h"
+#include "sp_frm.h"
+#include "sp_sfrm.h"
+#include "vad.h"
+#include "dtx.h"
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Local Constants                              |
+ |_________________________________________________________________________|
+*/
+
+#define ASCALE  0x0800
+#define ASHIFT 4
+#define CG_INT_MACS     6
+#define CG_TERMS        (LSMAX - LSMIN + 1)
+#define CVSHIFT 2                      /* Number of right shifts to be
+                                        * applied to the normalized Phi
+                                        * array in cov32, also used in flat
+                                        * to shift down normalized F, B, C
+                                        * matrices.                        */
+#define C_FRAME_LEN     (N_SUB * CG_TERMS)
+#define DELTA_LEVELS    16
+#define G_FRAME_LEN     (LSMAX + (N_SUB-1) * S_LEN - LSMIN  + 1)
+#define HIGH 1
+#define INV_OS_FCTR     0x1555         /* 1.0/6.0 */
+#define LAG_TABLE_LEN   (1 << L_BITS)
+#define LMAX            142
+#define LMAX_FR         (LMAX * OS_FCTR)
+#define LMIN            21
+#define LMIN_FR         (LMIN * OS_FCTR)
+#define LOW 0
+#define LPC_VQ_SEG 3
+#define LSMAX           (LMAX + CG_INT_MACS/2)
+#define LSMIN           (LMIN - CG_INT_MACS/2)
+#define LSP_MASK  0xffff
+#define L_BITS          8
+#define L_ROUND (Longword)0x8000       /* Preload accumulator value for
+                                        * rounding  */
+#define NP_AFLAT     4
+#define NUM_CLOSED      3
+#define NUM_TRAJ_MAX    2
+#define ONE_EIGHTH      0x1000
+#define ONE_HALF        0x4000
+#define ONE_QUARTER     0x2000
+#define PEAK_VICINITY   3
+#define PGAIN_CLAMP    0x0021          /* 0.001 */
+#define PGAIN_SCALE    0x6000          /* 0.75 */
+#define PW_FRAC         0x3333         /* 0.4 */
+#define R0BITS 5
+#define RSHIFT  2
+#define S_SH    6                      /* Shift offset for computing frame
+                                        * energy */
+#define UV_SCALE0       -0x2976
+#define UV_SCALE1       -0x46d3
+#define UV_SCALE2       -0x6676
+#define W_F_BUFF_LEN  (F_LEN + LSMAX)
+#define high(x) (shr(x,8) & 0x00ff)
+#define low(x) x & 0x00ff              /* This macro will return the low
+                                        * byte of a word */
+#define odd(x) (x & 0x0001)            /* This macro will determine if an
+                                        * integer is odd */
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                         State Variables (globals)                       |
+ |_________________________________________________________________________|
+*/
+
+Shortword pswAnalysisState[NP];
+
+Shortword pswWStateNum[NP],
+       pswWStateDenom[NP];
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                         Other External Variables                        |
+ |_________________________________________________________________________|
+*/
+
+static ShortwordRom *psrTable;         /* points to correct table of
+                                        * vectors */
+int iLimit;                            /* accessible to all in this file
+                                        * and to lpcCorrQntz() in dtx.c */
+static int iLow;                       /* the low element in this segment */
+static int iThree;                     /* boolean, is this a three element
+                                        * vector */
+static int iWordHalfPtr;               /* points to the next byte */
+static int iWordPtr;                   /* points to the next word to be
+                                        * read */
+
+extern Shortword pswCNVSCode1[],       /* comfort noise parameters */
+                 pswCNVSCode2[],
+                 pswCNGsp0Code[],
+                 pswCNLpc[],
+                 swCNR0;
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: aflat
+ *
+ *    PURPOSE:  Given a vector of high-pass filtered input speech samples
+ *              (A_LEN samples), function aflat computes the NP unquantized
+ *              reflection coefficients using the FLAT algorithm, searches
+ *              the three segment Rc-VQ based on the AFLAT recursion, and
+ *              outputs a quantized set of NP reflection coefficients, along
+ *              with the three indices specifying the selected vectors
+ *              from the Rc-VQ. The index of the quantized frame energy R0
+ *              is also output.
+ *
+ *
+ *    INPUT:
+ *
+ *        pswSpeechToLpc[0:A_LEN-1]
+ *                     A vector of high-pass filtered input speech, from
+ *                     which the unquantized reflection coefficients and
+ *                     the index of the quantized frame energy are
+ *                     computed.
+ *
+ *    OUTPUTS:
+ *
+ *        piR0Index[0:0]
+ *                     An index into a 5 bit table of quantized frame
+ *                     energies.
+ *
+ *        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.
+ *
+ *        swPtch
+ *                     Flag to indicate a periodic signal component
+ *
+ *        pswVadFlag
+ *                     Voice activity decision flag
+ *                      = 1: voice activity
+ *                      = 0: no voice activity
+ *
+ *        pswSP
+ *                     Speech flag
+ *                      = 1: encoder generates speech frames
+ *                      = 0: encoder generate SID frames
+ *
+ *
+ *    RETURN:
+ *        None.
+ *
+ *    REFERENCE:  Sub-clauses 4.1.3, 4.1.4, and 4.1.4.1
+ *        of GSM Recommendation 06.20
+ *
+ *    KEYWORDS: AFLAT,aflat,flat,vectorquantization, reflectioncoefficients
+ *
+ *************************************************************************/
+
+  void   aflat(Shortword pswSpeechToLPC[],
+                      int piR0Index[],
+                      Shortword pswFinalRc[],
+                      int piVQCodewds[],
+                      Shortword swPtch,
+                      Shortword *pswVadFlag,
+                      Shortword *pswSP)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            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_CorrelSeq[NP + 1],
+        *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 */
+  Shortword swVadScalAuto;
+  Shortword pswVadRc[4];
+  Longword pL_VadAcf[9];
+
+  Longword L_R0;                       /* Normalized R0 (use swRShifts to 
+                                        * unnormalize). This is done prior
+                                        * to r0quant(). After this, its is
+                                        * a unnormalized number */
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              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;
+
+  /* Given the input speech, compute the optimal reflection coefficients */
+  /* using the FLAT algorithm.                                           */
+  /*---------------------------------------------------------------------*/
+
+  L_R0 = flat(pswSpeechToLPC, pswFlatsRc, piR0Index, pL_VadAcf, 
+              &swVadScalAuto);
+
+  /* Get unquantized reflection coefficients for VAD */      /* DTX mode */
+  /* algorithm                                       */      /* DTX mode */
+  /* ----------------------------------------------- */      /* DTX mode */
+
+  for (i = 0; i < 4; i++)                                    /* DTX mode */
+    pswVadRc[i] = pswFlatsRc[i];                             /* DTX mode */
+
+
+  /* convert reflection coefficients to correlation */       /* DTX mode */
+  /* sequence                                       */       /* DTX mode */
+  /* ---------------------------------------------- */       /* DTX mode */
+
+  rcToCorrDpL(ASHIFT, ASCALE, pswFlatsRc, pL_CorrelSeq);     /* DTX mode */
+
+
+  /* Make the voice activity detection. Only swVadFlag is */ /* DTX mode */
+  /*  modified.                                           */ /* DTX mode */
+  /* ---------------------------------------------------- */ /* DTX mode */
+
+  vad_algorithm(pL_VadAcf, swVadScalAuto, pswVadRc, swPtch,  /* DTX mode */
+                pswVadFlag);
+
+
+  /* if DTX mode off, then always voice activity */          /* DTX mode */
+  /* ------------------------------------------- */          /* DTX mode */
+  if (!giDTXon) *pswVadFlag = 1;                             /* DTX mode */
+
+
+  /* determination of comfort noise parameters */            /* DTX mode */
+  /* ----------------------------------------- */            /* DTX mode */
+
+  *pswSP = swComfortNoise(*pswVadFlag,                       /* DTX mode */
+                          L_R0,                              /* DTX mode */
+                          pL_CorrelSeq);                     /* DTX mode */
+
+  if (*pswSP == 0)                                           /* DTX mode */
+  {   /* SID frame generation */                             /* DTX mode */
+
+    /* use unquantized reflection coefficients in the */     /* DTX mode */
+    /* encoder, when SID frames are generated         */     /* DTX mode */
+    /* ---------------------------------------------- */     /* DTX mode */
+
+    for (i = 0; i < NP; i++)                                 /* DTX mode */
+      pswFinalRc[i] = pswFlatsRc[i];                         /* DTX mode */
+
+  }                                                          /* DTX mode */
+  else                                                       /* DTX mode */
+  { /* speech frame generation */
+
+    /* 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: aflatNewBarRecursionL
+ *
+ *    PURPOSE:  Given the Longword initial condition arrays, pL_PBarFull and
+ *              pL_VBarFull, a reflection coefficient vector selected from
+ *              the Rc-VQ at the current stage, and index of the current
+ *              Rc-VQ stage, the AFLAT recursion is evaluated to obtain the
+ *              updated initial conditions for the AFLAT recursion at the
+ *              next Rc-VQ stage. At each lattice stage the pL_PBarFull and
+ *              pL_VBarFull arrays are shifted to be RSHIFT down from full
+ *              scale. Two sets of initial conditions are output:
+ *
+ *              1) pswPBar and pswVBar Shortword arrays are used at the
+ *                 next Rc-VQ segment as the AFLAT initial conditions
+ *                 for the Rc prequantizer and the Rc quantizer searches.
+ *              2) pL_PBarFull and pL_VBarFull arrays are output and serve
+ *                 as the initial conditions for the function call to
+ *                 aflatNewBarRecursionL at the next lattice stage.
+ *
+ *
+ *              This is an implementation of equations 4.24 through
+ *              4.27.
+ *    INPUTS:
+ *
+ *        pswQntRc[0:NP_AFLAT-1]
+ *                     An input reflection coefficient vector selected from
+ *                     the Rc-VQ quantizer at the current stage.
+ *
+ *        iSegment
+ *                    An input describing the current Vector quantizer
+ *                    quantizer segment (1, 2, or 3).
+ *
+ *        RSHIFT      The number of shifts down from full scale the
+ *                     pL_PBarFull and pL_VBarFull arrays are to be shifted
+ *                     at each lattice stage. RSHIFT is a global constant.
+ *
+ *        pL_PBar[0:NP-1]
+ *                     A Longword input array containing the P initial
+ *                     conditions for the full 10-th order LPC filter.
+ *                     The address of the 0-th element of  pL_PBarFull
+ *                     is passed in when function aflatNewBarRecursionL
+ *                     is called.
+ *
+ *        pL_VBar[-NP+1:NP-1]
+ *                     A Longword input array containing the V initial
+ *                     conditions for the full 10-th order LPC filter.
+ *                     The address of the 0-th element of  pL_VBarFull
+ *                     is passed in when function aflatNewBarRecursionL
+ *                     is called.
+ *
+ *    OUTPUTS:
+ *
+ *        pL_PBar[0:NP-1]
+ *                     A Longword output array containing the updated P
+ *                     initial conditions for the full 10-th order LPC
+ *                     filter.
+ *
+ *        pL_VBar[-NP+1:NP-1]
+ *                     A Longword output array containing the updated V
+ *                     initial conditions for the full 10-th order LPC
+ *                     filter.
+ *
+ *        pswPBar[0:NP_AFLAT-1]
+ *                     An output Shortword array containing the P initial
+ *                     conditions for the P-V AFLAT recursion for the next
+ *                     Rc-VQ segment. The address of the 0-th element of
+ *                     pswVBar is passed in.
+ *
+ *        pswVBar[-NP_AFLAT+1:NP_AFLAT-1]
+ *                     The output Shortword array containing the V initial
+ *                     conditions for the P-V AFLAT recursion, for the next
+ *                     Rc-VQ segment. The address of the 0-th element of
+ *                     pswVBar is passed in.
+ *
+ *    RETURN:
+ *        None.
+ *
+ *    REFERENCE:  Sub-clause 4.1.4.1 GSM Recommendation 06.20
+ *
+ *************************************************************************/
+
+void   aflatNewBarRecursionL(Shortword pswQntRc[], int iSegment,
+                                    Longword pL_PBar[], Longword pL_VBar[],
+                                 Shortword pswPBar[], Shortword pswVBar[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+  Longword *pL_VOld,
+        *pL_VNew,
+        *pL_POld,
+        *pL_PNew,
+        *ppL_PAddrs[2],
+        *ppL_VAddrs[2],
+         pL_VOldSpace[2 * NP - 1],
+         pL_VNewSpace[2 * NP - 1],
+         pL_POldSpace[NP],
+         pL_PNewSpace[NP],
+         L_temp,
+         L_sum;
+  Shortword swQntRcSq,
+         swNShift;
+  short int i,
+         j,
+         bound;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+  /* Copy the addresses of the input PBar and VBar arrays into  */
+  /* pL_POld and pL_VOld respectively.                          */
+  /*------------------------------------------------------------*/
+
+  pL_POld = pL_PBar;
+  pL_VOld = pL_VBar;
+
+  /* Point to PNew and VNew temporary arrays */
+  /*-----------------------------------------*/
+
+  pL_PNew = pL_PNewSpace;
+  pL_VNew = pL_VNewSpace + NP - 1;
+
+  /* Load the addresses of the temporary buffers into the address arrays. */
+  /* The address arrays are used to swap PNew and POld (VNew and VOLd)    */
+  /* buffers to avoid copying of the buffer contents at the end of a      */
+  /* lattice filter stage.                                                */
+  /*----------------------------------------------------------------------*/
+
+  ppL_PAddrs[0] = pL_POldSpace;
+  ppL_PAddrs[1] = pL_PNewSpace;
+  ppL_VAddrs[0] = pL_VOldSpace + NP - 1;
+  ppL_VAddrs[1] = pL_VNewSpace + NP - 1;
+
+
+  /* Update AFLAT recursion initial conditions for searching the Rc vector */
+  /* quantizer at the next VQ segment.                                     */
+  /*-------------------------------------------------------------------*/
+
+  for (j = 0; j < psvqIndex[iSegment - 1].len; j++)
+  {
+    bound = NP - psvqIndex[iSegment - 1].l - j - 1;
+
+    /* Compute rc squared, used by the recursion at the j-th lattice stage. */
+    /*---------------------------------------------------------------------*/
+
+    swQntRcSq = mult_r(pswQntRc[j], pswQntRc[j]);
+
+    /* Calculate PNew(i) */
+    /*-------------------*/
+
+    L_temp = L_mpy_ls(pL_VOld[0], pswQntRc[j]);
+    L_sum = L_add(L_temp, pL_POld[0]);
+    L_temp = L_mpy_ls(pL_POld[0], swQntRcSq);
+    L_sum = L_add(L_temp, L_sum);
+    L_temp = L_mpy_ls(pL_VOld[0], pswQntRc[j]);
+    L_temp = L_add(L_sum, L_temp);
+
+    /* Compute the number of bits to shift left by to achieve  */
+    /* the nominal value of PNew[0] which is right shifted by  */
+    /* RSHIFT bits relative to full scale.                     */
+    /*---------------------------------------------------------*/
+
+    swNShift = sub(norm_s(extract_h(L_temp)), RSHIFT);
+
+    /* Rescale PNew[0] by shifting left by swNShift bits */
+    /*---------------------------------------------------*/
+
+    pL_PNew[0] = L_shl(L_temp, swNShift);
+
+    for (i = 1; i <= bound; i++)
+    {
+      L_temp = L_mpy_ls(pL_VOld[i], pswQntRc[j]);
+      L_sum = L_add(L_temp, pL_POld[i]);
+      L_temp = L_mpy_ls(pL_POld[i], swQntRcSq);
+      L_sum = L_add(L_temp, L_sum);
+      L_temp = L_mpy_ls(pL_VOld[-i], pswQntRc[j]);
+      L_temp = L_add(L_sum, L_temp);
+      pL_PNew[i] = L_shl(L_temp, swNShift);
+    }
+
+    /* Calculate VNew(i) */
+    /*-------------------*/
+
+    for (i = -bound; i < 0; i++)
+    {
+      L_temp = L_mpy_ls(pL_VOld[-i - 1], swQntRcSq);
+      L_sum = L_add(L_temp, pL_VOld[i + 1]);
+      L_temp = L_mpy_ls(pL_POld[-i - 1], pswQntRc[j]);
+      L_temp = L_shl(L_temp, 1);
+      L_temp = L_add(L_temp, L_sum);
+      pL_VNew[i] = L_shl(L_temp, swNShift);
+    }
+    for (i = 0; i <= bound; i++)
+    {
+      L_temp = L_mpy_ls(pL_VOld[-i - 1], swQntRcSq);
+      L_sum = L_add(L_temp, pL_VOld[i + 1]);
+      L_temp = L_mpy_ls(pL_POld[i + 1], pswQntRc[j]);
+      L_temp = L_shl(L_temp, 1);
+      L_temp = L_add(L_temp, L_sum);
+      pL_VNew[i] = L_shl(L_temp, swNShift);
+    }
+
+    if (j < psvqIndex[iSegment - 1].len - 2)
+    {
+
+      /* Swap POld and PNew buffers, using modulo addressing */
+      /*-----------------------------------------------------*/
+
+      pL_POld = ppL_PAddrs[(j + 1) % 2];
+      pL_PNew = ppL_PAddrs[j % 2];
+
+      /* Swap VOld and VNew buffers, using modulo addressing */
+      /*-----------------------------------------------------*/
+
+      pL_VOld = ppL_VAddrs[(j + 1) % 2];
+      pL_VNew = ppL_VAddrs[j % 2];
+    }
+    else
+    {
+      if (j == psvqIndex[iSegment - 1].len - 2)
+      {
+
+        /* Then recursion to be done for one more lattice stage */
+        /*------------------------------------------------------*/
+
+        /* Copy address of PNew into POld */
+        /*--------------------------------*/
+        pL_POld = ppL_PAddrs[(j + 1) % 2];
+
+        /* Copy address of the input pL_PBar array into pswPNew; this will */
+        /* cause the PNew array to overwrite the input pL_PBar array, thus */
+        /* updating it at the final lattice stage of the current segment   */
+        /*-----------------------------------------------------------------*/
+
+        pL_PNew = pL_PBar;
+
+        /* Copy address of VNew into VOld */
+        /*--------------------------------*/
+
+        pL_VOld = ppL_VAddrs[(j + 1) % 2];
+
+        /* Copy address of the input pL_VBar array into pswVNew; this will */
+        /* cause the VNew array to overwrite the input pL_VBar array, thus */
+        /* updating it at the final lattice stage of the current segment   */
+        /*-----------------------------------------------------------------*/
+
+        pL_VNew = pL_VBar;
+
+      }
+    }
+  }
+
+  /* Update the pswPBar and pswVBar initial conditions for the AFLAT      */
+  /* Rc-VQ search at the next segment.                                    */
+  /*----------------------------------------------------------------------*/
+
+  bound = psvqIndex[iSegment].len - 1;
+
+  for (i = 0; i <= bound; i++)
+  {
+    pswPBar[i] = round(pL_PBar[i]);
+    pswVBar[i] = round(pL_VBar[i]);
+  }
+  for (i = -bound; i < 0; i++)
+  {
+    pswVBar[i] = round(pL_VBar[i]);
+  }
+
+  return;
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: aflatRecursion
+ *
+ *    PURPOSE:  Given the Shortword initial condition arrays, pswPBar and
+ *              pswVBar, a reflection coefficient vector from the quantizer
+ *              (or a prequantizer), and the order of the current Rc-VQ
+ *              segment, function aflatRecursion computes and returns the
+ *              residual error energy by evaluating the AFLAT recursion.
+ *
+ *              This is an implementation of equations 4.18 to 4.23.
+ *    INPUTS:
+ *
+ *        pswQntRc[0:NP_AFLAT-1]
+ *                     An input reflection coefficient vector from the
+ *                     Rc-prequantizer or the Rc-VQ codebook.
+ *
+ *        pswPBar[0:NP_AFLAT-1]
+ *                     The input Shortword array containing the P initial
+ *                     conditions for the P-V AFLAT recursion at the current
+ *                     Rc-VQ segment. The address of the 0-th element of
+ *                     pswVBar is passed in.
+ *
+ *        pswVBar[-NP_AFLAT+1:NP_AFLAT-1]
+ *                     The input Shortword array containing the V initial
+ *                     conditions for the P-V AFLAT recursion, at the current
+ *                     Rc-VQ segment. The address of the 0-th element of
+ *                     pswVBar is passed in.
+ *
+ *        *ppswPAddrs[0:1]
+ *                     An input array containing the address of temporary
+ *                     space P1 in its 0-th element, and the address of
+ *                     temporary space P2 in its 1-st element. Each of
+ *                     these addresses is alternately assigned onto
+ *                     pswPNew and pswPOld pointers using modulo
+ *                     arithmetic, so as to avoid copying the contents of
+ *                     pswPNew array into the pswPOld array at the end of
+ *                     each lattice stage of the AFLAT recursion.
+ *                     Temporary space P1 and P2 is allocated outside
+ *                     aflatRecursion by the calling function aflat.
+ *
+ *        *ppswVAddrs[0:1]
+ *                     An input array containing the address of temporary
+ *                     space V1 in its 0-th element, and the address of
+ *                     temporary space V2 in its 1-st element. Each of
+ *                     these addresses is alternately assigned onto
+ *                     pswVNew and pswVOld pointers using modulo
+ *                     arithmetic, so as to avoid copying the contents of
+ *                     pswVNew array into the pswVOld array at the end of
+ *                     each lattice stage of the AFLAT recursion.
+ *                     Temporary space V1 and V2 is allocated outside
+ *                     aflatRecursion by the calling function aflat.
+ *
+ *        swSegmentOrder
+ *                     This input short word describes the number of
+ *                     stages needed to compute the vector
+ *                     quantization of the given segment.
+ *
+ *    OUTPUTS:
+ *        None.
+ *
+ *    RETURN:
+ *        swRe         The Shortword value of residual energy for the
+ *                     Rc vector, given the pswPBar and pswVBar initial
+ *                     conditions.
+ *
+ *    REFERENCE:  Sub-clause 4.1.4.1 GSM Recommendation 06.20
+ *
+ *************************************************************************/
+
+Shortword aflatRecursion(Shortword pswQntRc[],
+                                Shortword pswPBar[],
+                                Shortword pswVBar[],
+                                Shortword *ppswPAddrs[],
+                                Shortword *ppswVAddrs[],
+                                Shortword swSegmentOrder)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword *pswPOld,
+        *pswPNew,
+        *pswVOld,
+        *pswVNew,
+         pswQntRcSqd[NP_AFLAT],
+         swRe;
+  Longword L_sum;
+  short int i,
+         j,
+         bound;                        /* loop control variables */
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Point to PBar and VBar, the initial condition arrays for the AFLAT  */
+  /* recursion.                                                          */
+  /*---------------------------------------------------------------------*/
+
+  pswPOld = pswPBar;
+  pswVOld = pswVBar;
+
+  /* Point to PNew and VNew, the arrays into which updated values of  P  */
+  /* and V functions will be written.                                    */
+  /*---------------------------------------------------------------------*/
+
+  pswPNew = ppswPAddrs[1];
+  pswVNew = ppswVAddrs[1];
+
+  /* Compute the residual error energy due to the selected Rc vector */
+  /* using the AFLAT recursion.                                      */
+  /*-----------------------------------------------------------------*/
+
+  /* Compute rc squared, used by the recursion */
+  /*-------------------------------------------*/
+
+  for (j = 0; j < swSegmentOrder; j++)
+  {
+    pswQntRcSqd[j] = mult_r(pswQntRc[j], pswQntRc[j]);
+  }
+
+  /* Compute the residual error energy due to the selected Rc vector */
+  /* using the AFLAT recursion.                                      */
+  /*-----------------------------------------------------------------*/
+
+  for (j = 0; j < swSegmentOrder - 1; j++)
+  {
+    bound = swSegmentOrder - j - 2;
+
+    /* Compute Psubj(i), for i = 0, bound  */
+    /*-------------------------------------*/
+
+    for (i = 0; i <= bound; i++)
+    {
+      L_sum = L_mac(L_ROUND, pswVOld[i], pswQntRc[j]);
+      L_sum = L_mac(L_sum, pswVOld[-i], pswQntRc[j]);
+      L_sum = L_mac(L_sum, pswPOld[i], pswQntRcSqd[j]);
+      L_sum = L_msu(L_sum, pswPOld[i], SW_MIN);
+      pswPNew[i] = extract_h(L_sum);
+    }
+
+    /* Check if potential for limiting exists. */
+    /*-----------------------------------------*/
+
+    if (sub(pswPNew[0], 0x4000) >= 0)
+      iLimit = 1;
+
+    /* Compute the new Vsubj(i) */
+    /*--------------------------*/
+
+    for (i = -bound; i < 0; i++)
+    {
+      L_sum = L_msu(L_ROUND, pswVOld[i + 1], SW_MIN);
+      L_sum = L_mac(L_sum, pswQntRcSqd[j], pswVOld[-i - 1]);
+      L_sum = L_mac(L_sum, pswQntRc[j], pswPOld[-i - 1]);
+      L_sum = L_mac(L_sum, pswQntRc[j], pswPOld[-i - 1]);
+      pswVNew[i] = extract_h(L_sum);
+    }
+
+    for (i = 0; i <= bound; i++)
+    {
+      L_sum = L_msu(L_ROUND, pswVOld[i + 1], SW_MIN);
+      L_sum = L_mac(L_sum, pswQntRcSqd[j], pswVOld[-i - 1]);
+      L_sum = L_mac(L_sum, pswQntRc[j], pswPOld[i + 1]);
+      L_sum = L_mac(L_sum, pswQntRc[j], pswPOld[i + 1]);
+      pswVNew[i] = extract_h(L_sum);
+    }
+
+    if (j < swSegmentOrder - 2)
+    {
+
+      /* Swap POld and PNew buffers, using modulo addressing */
+      /*-----------------------------------------------------*/
+
+      pswPOld = ppswPAddrs[(j + 1) % 2];
+      pswPNew = ppswPAddrs[j % 2];
+
+      /* Swap VOld and VNew buffers, using modulo addressing */
+      /*-----------------------------------------------------*/
+
+      pswVOld = ppswVAddrs[(j + 1) % 2];
+      pswVNew = ppswVAddrs[j % 2];
+
+    }
+  }
+
+  /* Computing Psubj(0) for the last lattice stage */
+  /*-----------------------------------------------*/
+
+  j = swSegmentOrder - 1;
+
+  L_sum = L_mac(L_ROUND, pswVNew[0], pswQntRc[j]);
+  L_sum = L_mac(L_sum, pswVNew[0], pswQntRc[j]);
+  L_sum = L_mac(L_sum, pswPNew[0], pswQntRcSqd[j]);
+  L_sum = L_msu(L_sum, pswPNew[0], SW_MIN);
+  swRe = extract_h(L_sum);
+
+  /* Return the residual energy corresponding to the reflection   */
+  /* coefficient vector being evaluated.                          */
+  /*--------------------------------------------------------------*/
+
+  return (swRe);                       /* residual error is returned */
+
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: bestDelta
+ *
+ *   PURPOSE:
+ *
+ *     This function finds the delta-codeable lag which maximizes CC/G.
+ *
+ *   INPUTS:
+ *
+ *     pswLagList[0:siNumLags-1]
+ *
+ *                     List of delta-codeable lags over which search is done.
+ *
+ *     pswCSfrm[0:127]
+ *
+ *                     C(k) sequence, k integer.
+ *
+ *     pswGSfrm[0:127]
+ *
+ *                     G(k) sequence, k integer.
+ *
+ *     siNumLags
+ *
+ *                     Number of lags in contention.
+ *
+ *     siSfrmIndex
+ *
+ *                     The index of the subframe to which the delta-code
+ *                     applies.
+ *
+ *
+ *   OUTPUTS:
+ *
+ *     pswLTraj[0:3]
+ *
+ *                     The winning lag is put into this array at
+ *                     pswLTraj[siSfrmIndex]
+ *
+ *     pswCCTraj[0:3]
+ *
+ *                     The corresponding winning C**2 is put into this
+ *                     array at pswCCTraj[siSfrmIndex]
+ *
+ *     pswGTraj[0:3]
+ *
+ *                     The corresponding winning G is put into this arrray
+ *                     at pswGTraj[siSfrmIndex]
+ *
+ *   RETURN VALUE:
+ *
+ *     none
+ *
+ *   DESCRIPTION:
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.3 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS:
+ *
+ *************************************************************************/
+
+void   bestDelta(Shortword pswLagList[],
+                        Shortword pswCSfrm[],
+                        Shortword pswGSfrm[],
+                        short int siNumLags,
+                        short int siSfrmIndex,
+                        Shortword pswLTraj[],
+                        Shortword pswCCTraj[],
+                        Shortword pswGTraj[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword pswCBuf[DELTA_LEVELS + CG_INT_MACS + 2],
+         pswGBuf[DELTA_LEVELS + CG_INT_MACS + 2],
+         pswCInterp[DELTA_LEVELS + 2],
+         pswGInterp[DELTA_LEVELS + 2],
+        *psw1,
+        *psw2,
+         swCmaxSqr,
+         swGmax,
+         swPeak;
+  short int siIPLo,
+         siRemLo,
+         siIPHi,
+         siRemHi,
+         siLoLag,
+         siHiLag,
+         siI;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* get bounds for integer C's and G's needed for interpolation */
+  /* get integer and fractional portions of boundary lags        */
+  /* ----------------------------------------------------------- */
+
+  get_ipjj(pswLagList[0], &siIPLo, &siRemLo);
+
+  get_ipjj(pswLagList[siNumLags - 1], &siIPHi, &siRemHi);
+
+  /* get lag for first and last C and G required */
+  /* ------------------------------------------- */
+
+  siLoLag = sub(siIPLo, CG_INT_MACS / 2 - 1);
+
+  if (siRemHi != 0)
+  {
+    siHiLag = add(siIPHi, CG_INT_MACS / 2);
+  }
+  else
+  {
+    siHiLag = add(siIPHi, CG_INT_MACS / 2 - 1);
+  }
+
+  /* transfer needed integer C's and G's to temp buffers */
+  /* --------------------------------------------------- */
+
+  psw1 = pswCBuf;
+  psw2 = pswGBuf;
+
+  if (siRemLo == 0)
+  {
+
+    /* first lag in list is integer: don't care about first entries */
+    /* (they will be paired with zero tap in interpolating filter)  */
+    /* ------------------------------------------------------------ */
+
+    psw1[0] = 0;
+    psw2[0] = 0;
+    psw1 = &psw1[1];
+    psw2 = &psw2[1];
+  }
+
+  for (siI = siLoLag; siI <= siHiLag; siI++)
+  {
+    psw1[siI - siLoLag] = pswCSfrm[siI - LSMIN];
+    psw2[siI - siLoLag] = pswGSfrm[siI - LSMIN];
+  }
+
+  if (siRemLo == 0)
+  {
+    /* make siLoLag correspond to first entry in temp buffers */
+    /* ------------------------------------------------------ */
+    siLoLag = sub(siLoLag, 1);
+  }
+
+  /* interpolate to get C's and G's which correspond to lags in list */
+  /* --------------------------------------------------------------- */
+
+  CGInterp(pswLagList, siNumLags, pswCBuf, pswGBuf, siLoLag,
+           pswCInterp, pswGInterp);
+
+  /* find max C*C*sgn(C)/G */
+  /* --------------------- */
+
+  swPeak = maxCCOverGWithSign(pswCInterp, pswGInterp, &swCmaxSqr, &swGmax,
+                              siNumLags);
+
+  /* store best lag and corresponding C*C and G */
+  /* ------------------------------------------ */
+
+  pswLTraj[siSfrmIndex] = pswLagList[swPeak];
+  pswCCTraj[siSfrmIndex] = swCmaxSqr;
+  pswGTraj[siSfrmIndex] = swGmax;
+
+}
+
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: CGInterp
+ *
+ *   PURPOSE:
+ *
+ *     Given a list of fractional lags, a C(k) array, and a G(k) array
+ *     (k integer), this function generates arrays of C's and G's
+ *     corresponding to the list of fractional lags by interpolating the
+ *     integer C(k) and G(k) arrays.
+ *
+ *   INPUTS:
+ *
+ *     pswLIn[0:siNum-1]
+ *
+ *                     List of valid lags
+ *
+ *     siNum
+ *
+ *                     Length of output lists
+ *
+ *     pswCIn[0:variable]
+ *
+ *                     C(k) sequence, k integer.  The zero index corresponds
+ *                     to k = siLoIntLag.
+ *
+ *     pswGIn[0:variable]
+ *
+ *                     G(k) sequence, k integer.  The zero index corresponds
+ *                     to k = siLoIntLag.
+ *
+ *     siLoIntLag
+ *
+ *                     Integer lag corresponding to the first entry in the
+ *                     C(k) and G(k) input arrays.
+ *
+ *     ppsrCGIntFilt[0:5][0:5]
+ *
+ *                     The FIR interpolation filter for C's and G's.
+ *
+ *   OUTPUTS:
+ *
+ *     pswCOut[0:siNum-1]
+ *
+ *                     List of interpolated C's corresponding to pswLIn.
+ *
+ *     pswGOut[0:siNum-1]
+ *
+ *                     List of interpolated G's corresponding to pswLIn
+ *
+ *   RETURN VALUE: none
+ *
+ *   DESCRIPTION:
+ *
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.2, 4.1.8.3 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS: lag, interpolateCG
+ *
+ *************************************************************************/
+
+void   CGInterp(Shortword pswLIn[],
+                       short siNum,
+                       Shortword pswCIn[],
+                       Shortword pswGIn[],
+                       short siLoIntLag,
+                       Shortword pswCOut[],
+                       Shortword pswGOut[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+  Shortword i,
+         swBig,
+         swLoIntLag;
+  Shortword swLagInt,
+         swTempRem,
+         swLagRem;
+  Longword L_Temp,
+         L_Temp1,
+         L_Temp2;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  swLoIntLag = add(siLoIntLag, (CG_INT_MACS / 2) - 1);
+
+  for (swBig = 0; swBig < siNum; swBig++)
+  {
+
+    /* Separate integer and fractional portions of lag */
+    /*-------------------------------------------------*/
+    L_Temp = L_mult(pswLIn[swBig], INV_OS_FCTR);
+    swLagInt = extract_h(L_Temp);
+
+    /* swLagRem = (OS_FCTR - pswLIn[iBig] % OS_FCTR)) */
+    /*---------------------------------------------------*/
+    swTempRem = extract_l(L_Temp);
+    swTempRem = shr(swTempRem, 1);
+    swLagRem = swTempRem & SW_MAX;
+    swLagRem = mult_r(swLagRem, OS_FCTR);
+    swLagRem = sub(OS_FCTR, swLagRem);
+
+    /* Get interpolated C and G values */
+    /*--------------------------*/
+
+    L_Temp1 = L_mac(32768, pswCIn[swLagInt - swLoIntLag],
+                    ppsrCGIntFilt[0][swLagRem]);
+    L_Temp2 = L_mac(32768, pswGIn[swLagInt - swLoIntLag],
+                    ppsrCGIntFilt[0][swLagRem]);
+
+    for (i = 1; i <= CG_INT_MACS - 1; i++)
+    {
+      L_Temp1 = L_mac(L_Temp1, pswCIn[i + swLagInt - swLoIntLag],
+                      ppsrCGIntFilt[i][swLagRem]);
+      L_Temp2 = L_mac(L_Temp2, pswGIn[i + swLagInt - swLoIntLag],
+                      ppsrCGIntFilt[i][swLagRem]);
+
+    }
+    pswCOut[swBig] = extract_h(L_Temp1);
+    pswGOut[swBig] = extract_h(L_Temp2);
+  }
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: CGInterpValid
+ *
+ *   PURPOSE:
+ *
+ *     The purpose of this function is to retrieve the valid (codeable) lags
+ *     within one (exclusive) integer sample of the given integer lag, and
+ *     interpolate the corresponding C's and G's from the integer arrays
+ *
+ *   INPUTS:
+ *
+ *     swFullResLag
+ *
+ *                     integer lag * OS_FCTR
+ *
+ *     pswCIn[0:127]
+ *
+ *                     integer C sequence
+ *
+ *     pswGIn[0:127]
+ *
+ *                     integer G sequence
+ *
+ *     psrLagTbl[0:255]
+ *
+ *                     reference table of valid (codeable) lags
+ *
+ *
+ *   OUTPUTS:
+ *
+ *     pswLOut[0:*psiNum-1]
+ *
+ *                     list of valid lags within 1 of swFullResLag
+ *
+ *     pswCOut[0:*psiNum-1]
+ *
+ *                     list of interpolated C's corresponding to pswLOut
+ *
+ *     pswGOut[0:*psiNum-1]
+ *
+ *                     list of interpolated G's corresponding to pswLOut
+ *
+ *   RETURN VALUE:
+ *
+ *     siNum
+ *
+ *                     length of output lists
+ *
+ *   DESCRIPTION:
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.2, 4.1.9 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS: CGInterpValid, cginterpvalid, CG_INT_VALID
+ *
+ *************************************************************************/
+
+short  CGInterpValid(Shortword swFullResLag,
+                            Shortword pswCIn[],
+                            Shortword pswGIn[],
+                            Shortword pswLOut[],
+                            Shortword pswCOut[],
+                            Shortword pswGOut[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  short int siLowerBound,
+         siUpperBound,
+         siNum,
+         siI;
+  Shortword swLag;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Get lower and upper bounds for valid lags     */
+  /* within 1 (exclusive) integer lag of input lag */
+  /* --------------------------------------------- */
+
+  swLag = sub(swFullResLag, OS_FCTR);
+  swLag = quantLag(swLag, &siLowerBound);
+  if (sub(swLag, swFullResLag) != 0)
+  {
+    siLowerBound = add(siLowerBound, 1);
+  }
+
+  swLag = add(swFullResLag, OS_FCTR);
+  swLag = quantLag(swLag, &siUpperBound);
+  if (sub(swLag, swFullResLag) != 0)
+  {
+    siUpperBound = sub(siUpperBound, 1);
+  }
+
+  /* Get list of full resolution lags whose */
+  /* C's and G's will be interpolated       */
+  /* -------------------------------------- */
+
+  siNum = sub(siUpperBound, siLowerBound);
+  siNum = add(siNum, 1);
+
+  for (siI = 0; siI < siNum; siI++)
+  {
+    pswLOut[siI] = psrLagTbl[siI + siLowerBound];
+  }
+
+  /* Interpolate C's and G's */
+  /* ----------------------- */
+
+  CGInterp(pswLOut, siNum, pswCIn, pswGIn, LSMIN, pswCOut,
+           pswGOut);
+
+  /* Return the length of the output lists */
+  /* ------------------------------------- */
+
+  return (siNum);
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: compResidEnergy
+ *
+ *   PURPOSE:
+ *
+ *     Computes and compares the residual energy from interpolated and
+ *     non-interpolated coefficients. From the difference determines
+ *     the soft interpolation decision.
+ *
+ *   INPUTS:
+ *
+ *     pswSpeech[0:159] ( [0:F_LEN-1] )
+ *
+ *                     Input speech frame (after high-pass filtering).
+ *
+ *     ppswInterpCoef[0:3][0:9] ( [0:N_SUB-1][0:NP-1] )
+ *
+ *                     Set of interpolated LPC direct-form coefficients for
+ *                     each subframe.
+ *
+ *     pswPreviousCoef[0:9} ( [0:NP-1] )
+ *
+ *                     Set of LPC direct-form coefficients corresponding to
+ *                     the previous frame
+ *
+ *     pswCurrentCoef[0:9} ( [0:NP-1] )
+ *
+ *                     Set of LPC direct-form coefficients corresponding to
+ *                     the current frame
+ *
+ *     psnsSqrtRs[0:3] ( [0:N_SUB-1] )
+ *
+ *                     Array of residual energy estimates for each subframe
+ *                     based on interpolated coefficients.  Used for scaling.
+ *
+ *   RETURN:
+ *
+ *     Returned value indicates the coefficients to use for each subframe:
+ *     One indicates interpolated coefficients are to be used, zero indicates
+ *     un-interpolated coefficients are to be used.
+ *
+ *   DESCRIPTION:
+ *
+ *
+ *   REFERENCE:  Sub-clause 4.1.6 of GSM Recommendation 06.20
+ *
+ *   Keywords: openlooplagsearch, openloop, lag, pitch
+ *
+ **************************************************************************/
+
+
+
+short  compResidEnergy(Shortword pswSpeech[],
+                              Shortword ppswInterpCoef[][NP],
+                              Shortword pswPreviousCoef[],
+                              Shortword pswCurrentCoef[],
+                              struct NormSw psnsSqrtRs[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  short  i,
+         j,
+         siOverflowPossible,
+         siInterpDecision;
+  Shortword swMinShift,
+         swShiftFactor,
+         swSample,
+        *pswCoef;
+  Shortword pswTempState[NP];
+  Shortword pswResidual[S_LEN];
+  Longword L_ResidualEng;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Executable Code                              |
+ |_________________________________________________________________________|
+*/
+
+  /* Find minimum shift count of the square-root of residual energy */
+  /* estimates over the four subframes.  According to this minimum, */
+  /* find a shift count for the residual signal which will be used  */
+  /* to avoid overflow when the actual residual energies are        */
+  /* calculated over the frame                                      */
+  /*----------------------------------------------------------------*/
+
+  swMinShift = SW_MAX;
+  for (i = 0; i < N_SUB; i++)
+  {
+
+    if (sub(psnsSqrtRs[i].sh, swMinShift) < 0 && psnsSqrtRs[i].man > 0)
+      swMinShift = psnsSqrtRs[i].sh;
+  }
+
+  if (sub(swMinShift, 1) >= 0)
+  {
+
+    siOverflowPossible = 0;
+  }
+
+  else if (swMinShift == 0)
+  {
+    siOverflowPossible = 1;
+    swShiftFactor = ONE_HALF;
+  }
+
+  else if (sub(swMinShift, -1) == 0)
+  {
+    siOverflowPossible = 1;
+    swShiftFactor = ONE_QUARTER;
+  }
+
+  else
+  {
+    siOverflowPossible = 1;
+    swShiftFactor = ONE_EIGHTH;
+  }
+
+  /* Copy analysis filter state into temporary buffer */
+  /*--------------------------------------------------*/
+
+  for (i = 0; i < NP; i++)
+    pswTempState[i] = pswAnalysisState[i];
+
+  /* Send the speech frame, one subframe at a time, through the analysis */
+  /* filter which is based on interpolated coefficients.  After each     */
+  /* subframe, accumulate the energy in the residual signal, scaling to  */
+  /* avoid overflow if necessary.                                        */
+  /*---------------------------------------------------------------------*/
+
+  L_ResidualEng = 0;
+
+  for (i = 0; i < N_SUB; i++)
+  {
+
+    lpcFir(&pswSpeech[i * S_LEN], ppswInterpCoef[i], pswTempState,
+           pswResidual);
+
+    if (siOverflowPossible)
+    {
+
+      for (j = 0; j < S_LEN; j++)
+      {
+
+        swSample = mult_r(swShiftFactor, pswResidual[j]);
+        L_ResidualEng = L_mac(L_ResidualEng, swSample, swSample);
+      }
+    }
+
+    else
+    {
+
+      for (j = 0; j < S_LEN; j++)
+      {
+
+        L_ResidualEng = L_mac(L_ResidualEng, pswResidual[j], pswResidual[j]);
+      }
+    }
+  }
+
+  /* Send the speech frame, one subframe at a time, through the analysis */
+  /* filter which is based on un-interpolated coefficients.  After each  */
+  /* subframe, subtract the energy in the residual signal from the       */
+  /* accumulated residual energy due to the interpolated coefficient     */
+  /* analysis filter, again scaling to avoid overflow if necessary.      */
+  /* Note that the analysis filter state is updated during these         */
+  /* filtering operations.                                               */
+  /*---------------------------------------------------------------------*/
+
+  for (i = 0; i < N_SUB; i++)
+  {
+
+    switch (i)
+    {
+
+      case 0:
+
+        pswCoef = pswPreviousCoef;
+        break;
+
+      case 1:
+      case 2:
+      case 3:
+
+        pswCoef = pswCurrentCoef;
+        break;
+    }
+
+    lpcFir(&pswSpeech[i * S_LEN], pswCoef, pswAnalysisState,
+           pswResidual);
+
+    if (siOverflowPossible)
+    {
+
+      for (j = 0; j < S_LEN; j++)
+      {
+
+        swSample = mult_r(swShiftFactor, pswResidual[j]);
+        L_ResidualEng = L_msu(L_ResidualEng, swSample, swSample);
+      }
+    }
+
+    else
+    {
+
+      for (j = 0; j < S_LEN; j++)
+      {
+
+        L_ResidualEng = L_msu(L_ResidualEng, pswResidual[j], pswResidual[j]);
+      }
+    }
+  }
+
+  /* Make soft-interpolation decision based on the difference in residual */
+  /* energies                                                             */
+  /*----------------------------------------------------------------------*/
+
+  if (L_ResidualEng < 0)
+    siInterpDecision = 1;
+
+  else
+    siInterpDecision = 0;
+
+  return siInterpDecision;
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: cov32
+ *
+ *    PURPOSE: Calculates B, F, and C correlation matrices from which
+ *             the reflection coefficients are computed using the FLAT
+ *             algorithm. The Spectral Smoothing Technique (SST) is applied
+ *             to the correlations. End point correction is employed
+ *             in computing the correlations to minimize computation.
+ *
+ *    INPUT:
+ *
+ *       pswIn[0:169]
+ *                     A sampled speech vector used to compute
+ *                     correlations need for generating the optimal
+ *                     reflection coefficients via the FLAT algorithm.
+ *
+ *       CVSHIFT       The number of right shifts by which the normalized
+ *                     correlations are to be shifted down prior to being
+ *                     rounded into the Shortword output correlation arrays
+ *                     B, F, and C.
+ *
+ *       pL_rFlatSstCoefs[NP]
+ *
+ *                     A table stored in Rom containing the spectral
+ *                     smoothing function coefficients.
+ *
+ *    OUTPUTS:
+ *
+ *       pppL_B[0:NP-1][0:NP-1][0:1]
+ *                     An output correlation array containing the backward
+ *                     correlations of the input signal. It is a square
+ *                     matrix symmetric about the diagonal. Only the upper
+ *                     right hand triangular region of this matrix is
+ *                     initialized, but two dimensional indexing is retained
+ *                     to enhance clarity. The third array dimension is used
+ *                     by function flat to swap the current and the past
+ *                     values of B array, eliminating the need to copy
+ *                     the updated B values onto the old B values at the
+ *                     end of a given lattice stage. The third dimension
+ *                     is similarily employed in arrays F and C.
+ *
+ *       pppL_F[0:NP-1][0:NP-1][0:1]
+ *                     An output correlation array containing the forward
+ *                     correlations of the input signal. It is a square
+ *                     matrix symmetric about the diagonal. Only the upper
+ *                     right hand triangular region of this matrix is
+ *                     initialized.
+ *
+ *       pppL_C[0:NP-1][0:NP-1][0:1]
+ *                     An output correlation array containing the cross
+ *                     correlations of the input signal. It is a square
+ *                     matrix which is not symmetric. All its elements
+ *                     are initialized, for the third dimension index = 0.
+ *
+ *       pL_R0         Average normalized signal power over F_LEN
+ *                     samples, given by 0.5*(Phi(0,0)+Phi(NP,NP)), where
+ *                     Phi(0,0) and Phi(NP,NP) are normalized signal
+ *                     autocorrelations.  The average unnormalized signal
+ *                     power over the frame is given by adjusting L_R0 by
+ *                     the shift count which is returned. pL_R0 along
+ *                     with the returned shift count are the inputs to
+ *                     the frame energy quantizer.
+ *
+ *        Longword pL_VadAcf[4]
+ *                     An array with the autocorrelation coefficients to be
+ *                     used by the VAD.
+ *
+ *        Shortword *pswVadScalAuto
+ *                     Input scaling factor used by the VAD.
+ *
+ *    RETURN:
+ *
+ *       swNormPwr     The shift count to be applied to pL_R0 for
+ *                     reconstructing the average unnormalized
+ *                     signal power over the frame.
+ *                     Negative shift count means that a left shift was
+ *                     applied to the correlations to achieve a normalized
+ *                     value of pL_R0.
+ *
+ *   DESCRIPTION:
+ *
+ *
+ *      The input energy of the signal is assumed unknown.  It maximum
+ *      can be F_LEN*0.5. The 0.5 factor accounts for scaling down of the
+ *      input signal in the high-pass filter.  Therefore the signal is
+ *      shifted down by 3 shifts producing an energy reduction of 2^(2*3)=64.
+ *      The resulting energy is then normalized.  Based on the shift count,
+ *      the correlations F, B, and C are computed using as few shifts as
+ *      possible, so a precise result is attained.
+ *      This is an implementation of equations: 2.1 through 2.11.
+ *
+ *   REFERENCE:  Sub-clause 4.1.3 of GSM Recommendation 06.20
+ *
+ *   keywords: energy, autocorrelation, correlation, cross-correlation
+ *   keywords: spectral smoothing, SST, LPC, FLAT, flat
+ *
+ *************************************************************************/
+
+Shortword cov32(Shortword pswIn[],
+                       Longword pppL_B[NP][NP][2],
+                       Longword pppL_F[NP][NP][2],
+                       Longword pppL_C[NP][NP][2],
+                       Longword *pL_R0,
+                       Longword pL_VadAcf[],
+                       Shortword *pswVadScalAuto)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Longword L_max,
+         L_Pwr0,
+         L_Pwr,
+         L_temp,
+         pL_Phi[NP + 1];
+  Shortword swTemp,
+         swNorm,
+         swNormSig,
+         swNormPwr,
+         pswInScale[A_LEN],
+         swPhiNorm;
+  short int i,
+         k,
+         kk,
+         n;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Calculate energy in the frame vector (160 samples) for each   */
+  /* of NP frame placements. The energy is reduced by 64. This is  */
+  /* accomplished by shifting the input right by 3 bits. An offset */
+  /* of 0x117f0b is placed into the accumulator to account for     */
+  /* the worst case power gain due to the 3 LSB's of the input     */
+  /* signal which were right shifted. The worst case is that the   */
+  /* 3 LSB's were all set to 1 for each of the samples. Scaling of */
+  /* the input by a half is assumed here.                          */
+  /*---------------------------------------------------------------*/
+
+  L_max = 0;
+  for (L_Pwr = 0x117f0b, i = 0; i < F_LEN; i++)
+  {
+    swTemp = shr(pswIn[i], 3);
+    L_Pwr = L_mac(L_Pwr, swTemp, swTemp);
+  }
+  L_max |= L_Pwr;
+
+  /* L_max tracks the maximum power over NP window placements */
+  /*----------------------------------------------------------*/
+
+  for (i = 1; i <= NP; i++)
+  {
+
+    /* Subtract the power due to 1-st sample from previous window
+     * placement. */
+    /*-----------------------------------------------------------*/
+
+    swTemp = shr(pswIn[i - 1], 3);
+    L_Pwr = L_msu(L_Pwr, swTemp, swTemp);
+
+    /* Add the power due to new sample at the current window placement. */
+    /*------------------------------------------------------------------*/
+
+    swTemp = shr(pswIn[F_LEN + i - 1], 3);
+    L_Pwr = L_mac(L_Pwr, swTemp, swTemp);
+
+    L_max |= L_Pwr;
+
+  }
+
+  /* Compute the shift count needed to achieve normalized value */
+  /* of the correlations.                                       */
+  /*------------------------------------------------------------*/
+
+  swTemp = norm_l(L_max);
+  swNorm = sub(6, swTemp);
+
+  if (swNorm >= 0)
+  {
+
+    /* The input signal needs to be shifted down, to avoid limiting */
+    /* so compute the shift count to be applied to the input.       */
+    /*--------------------------------------------------------------*/
+
+    swTemp = add(swNorm, 1);
+    swNormSig = shr(swTemp, 1);
+    swNormSig = add(swNormSig, 0x0001);
+
+  }
+  else
+  {
+    /* No scaling down of the input is necessary */
+    /*-------------------------------------------*/
+
+    swNormSig = 0;
+
+  }
+
+  /* Convert the scaling down, if any, which was done to the time signal */
+  /* to the power domain, and save.                                      */
+  /*---------------------------------------------------------------------*/
+
+  swNormPwr = shl(swNormSig, 1);
+
+  /* Buffer the input signal, scaling it down if needed. */
+  /*-----------------------------------------------------*/
+
+  for (i = 0; i < A_LEN; i++)
+  {
+    pswInScale[i] = shr(pswIn[i], swNormSig);
+  }
+
+  /* Compute from buffered (scaled) input signal the correlations     */
+  /* needed for the computing the reflection coefficients.            */
+  /*------------------------------------------------------------------*/
+
+  /* Compute correlation Phi(0,0) */
+  /*------------------------------*/
+
+  L_Pwr = L_mult(pswInScale[NP], pswInScale[NP]);
+  for (n = 1; n < F_LEN; n++)
+  {
+    L_Pwr = L_mac(L_Pwr, pswInScale[NP + n], pswInScale[NP + n]);
+  }
+  pL_Phi[0] = L_Pwr;
+
+  /* Get ACF[0] and input scaling factor for VAD algorithm */
+  *pswVadScalAuto = swNormSig;
+  pL_VadAcf[0] = L_Pwr;
+
+  /* Compute the remaining correlations along the diagonal which */
+  /* starts at Phi(0,0). End-point correction is employed to     */
+  /* limit computation.                                          */
+  /*-------------------------------------------------------------*/
+
+  for (i = 1; i <= NP; i++)
+  {
+
+    /* Compute the power in the last sample from the previous         */
+    /* window placement, and subtract it from correlation accumulated */
+    /* at the previous window placement.                              */
+    /*----------------------------------------------------------------*/
+
+    L_Pwr = L_msu(L_Pwr, pswInScale[NP + F_LEN - i],
+                  pswInScale[NP + F_LEN - i]);
+
+    /* Compute the power in the new sample for the current window       */
+    /* placement, and add it to L_Pwr to obtain the value of Phi(i,i). */
+    /*------------------------------------------------------------------*/
+
+    L_Pwr = L_mac(L_Pwr, pswInScale[NP - i], pswInScale[NP - i]);
+
+    pL_Phi[i] = L_Pwr;
+
+  }
+
+  /* Compute the shift count necessary to normalize the Phi array  */
+  /*---------------------------------------------------------------*/
+
+  L_max = 0;
+  for (i = 0; i <= NP; i++)
+  {
+    L_max |= pL_Phi[i];
+  }
+  swPhiNorm = norm_l(L_max);
+
+  /* Adjust the shift count to be returned to account for any scaling */
+  /* down which might have been done to the input signal prior to     */
+  /* computing the correlations.                                      */
+  /*------------------------------------------------------------------*/
+
+  swNormPwr = sub(swNormPwr, swPhiNorm);
+
+  /* Compute the average power over the frame; i.e.,                   */
+  /* 0.5*(Phi(0,0)+Phi(NP,NP)), given a normalized pL_Phi array.       */
+  /*-------------------------------------------------------------------*/
+
+  swTemp = sub(swPhiNorm, 1);
+  L_Pwr0 = L_shl(pL_Phi[0], swTemp);
+  L_Pwr = L_shl(pL_Phi[NP], swTemp);
+  *pL_R0 = L_add(L_Pwr, L_Pwr0);       /* Copy power to output pointer */
+
+  /* Check if the average power is normalized; if not, shift left by 1 bit */
+  /*-----------------------------------------------------------------------*/
+
+  if (!(*pL_R0 & 0x40000000))
+  {
+    *pL_R0 = L_shl(*pL_R0, 1);         /* normalize the average power    */
+    swNormPwr = sub(swNormPwr, 1);     /* adjust the shift count         */
+  }
+
+  /* Reduce the shift count needed to normalize the correlations   */
+  /* by CVSHIFT bits.                                              */
+  /*---------------------------------------------------------------*/
+
+  swNorm = sub(swPhiNorm, CVSHIFT);
+
+  /* Initialize the F, B, and C output correlation arrays, using the */
+  /* Phi correlations computed along the diagonal of symmetry.       */
+  /*-----------------------------------------------------------------*/
+
+  L_temp = L_shl(pL_Phi[0], swNorm);   /* Normalize the result     */
+
+  pppL_F[0][0][0] = L_temp;            /* Write to output array    */
+
+  for (i = 1; i <= NP - 1; i++)
+  {
+
+    L_temp = L_shl(pL_Phi[i], swNorm); /* Normalize the result     */
+
+
+    pppL_F[i][i][0] = L_temp;          /* Write to output array    */
+    pppL_B[i - 1][i - 1][0] = L_temp;  /* Write to output array    */
+    pppL_C[i][i - 1][0] = L_temp;      /* Write to output array    */
+
+  }
+
+  L_temp = L_shl(pL_Phi[NP], swNorm);  /* Normalize the result     */
+
+  pppL_B[NP - 1][NP - 1][0] = L_temp;  /* Write to output array    */
+
+  for (k = 1; k <= NP - 1; k++)
+  {
+
+    /* Compute correlation Phi(0,k) */
+    /*------------------------------*/
+
+    L_Pwr = L_mult(pswInScale[NP], pswInScale[NP - k]);
+    for (n = 1; n < F_LEN; n++)
+    {
+      L_Pwr = L_mac(L_Pwr, pswInScale[NP + n], pswInScale[NP + n - k]);
+    }
+    /* convert covariance values to ACF and store for VAD algorithm */
+    if (k < 9)
+    {
+      pL_VadAcf[k] = L_Pwr;
+      for (kk = 0; kk < k; kk++)
+      {
+        pL_VadAcf[k] = L_msu(pL_VadAcf[k], pswInScale[NP + kk],
+                             pswInScale[NP + kk - k]);
+      }
+    }
+
+    L_temp = L_shl(L_Pwr, swNorm);     /* Normalize the result */
+    L_temp = L_mpy_ll(L_temp, pL_rFlatSstCoefs[k - 1]); /* Apply SST */
+
+    pppL_F[0][k][0] = L_temp;          /* Write to output array    */
+    pppL_C[0][k - 1][0] = L_temp;      /* Write to output array    */
+
+
+    /* Compute the remaining correlations along the diagonal which */
+    /* starts at Phi(0,k). End-point correction is employed to     */
+    /* limit computation.                                          */
+    /*-------------------------------------------------------------*/
+
+    for (kk = k + 1, i = 1; kk <= NP - 1; kk++, i++)
+    {
+
+      /* Compute the power in the last sample from the previous         */
+      /* window placement, and subtract it from correlation accumulated */
+      /* at the previous window placement.                              */
+      /*----------------------------------------------------------------*/
+
+      L_Pwr = L_msu(L_Pwr, pswInScale[NP + F_LEN - i],
+                    pswInScale[NP + F_LEN - kk]);
+
+      /* Compute the power in the new sample for the current window       */
+      /* placement, and add it to L_Pwr to obtain the value of Phi(i,kk). */
+      /*------------------------------------------------------------------*/
+
+      L_Pwr = L_mac(L_Pwr, pswInScale[NP - i], pswInScale[NP - kk]);
+
+      L_temp = L_shl(L_Pwr, swNorm);   /* Normalize */
+      L_temp = L_mpy_ll(L_temp, pL_rFlatSstCoefs[k - 1]);     /* Apply SST */
+
+      pppL_F[i][kk][0] = L_temp;       /* Write to output array */
+      pppL_B[i - 1][kk - 1][0] = L_temp;        /* Write to output array */
+      pppL_C[i][kk - 1][0] = L_temp;   /* Write to output array    */
+      pppL_C[kk][i - 1][0] = L_temp;   /* Write to output array    */
+
+    }
+
+    /* Compute the power in the last sample from the previous         */
+    /* window placement, and subtract it from correlation accumulated */
+    /* at the previous window placement.                              */
+    /*----------------------------------------------------------------*/
+
+    L_Pwr = L_msu(L_Pwr, pswInScale[F_LEN + k], pswInScale[F_LEN]);
+
+    /* Compute the power in the new sample for the current window       */
+    /* placement, and add it to L_Pwr to obtain the value of Phi(i,kk). */
+    /*------------------------------------------------------------------*/
+
+    L_Pwr = L_mac(L_Pwr, pswInScale[k], pswInScale[0]);
+
+    L_temp = L_shl(L_Pwr, swNorm);     /* Normalize the result */
+    L_temp = L_mpy_ll(L_temp, pL_rFlatSstCoefs[k - 1]); /* Apply SST */
+
+    pppL_B[NP - k - 1][NP - 1][0] = L_temp;     /* Write to output array */
+    pppL_C[NP - k][NP - 1][0] = L_temp;/* Write to output array */
+
+  }
+
+  /* Compute correlation Phi(0,NP) */
+  /*-------------------------------*/
+
+  L_Pwr = L_mult(pswInScale[NP], pswInScale[0]);
+  for (n = 1; n < F_LEN; n++)
+  {
+    L_Pwr = L_mac(L_Pwr, pswInScale[NP + n], pswInScale[n]);
+  }
+
+  L_temp = L_shl(L_Pwr, swNorm);       /* Normalize the result */
+  L_temp = L_mpy_ll(L_temp, pL_rFlatSstCoefs[NP - 1]);  /* Apply SST */
+
+  pppL_C[0][NP - 1][0] = L_temp;       /* Write to output array */
+
+  return (swNormPwr);
+
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: filt4_2nd
+ *
+ *    PURPOSE:  Implements a fourth order filter by cascading two second
+ *              order sections.
+ *
+ *    INPUTS:
+ *
+ *      pswCoef[0:9]   An array of two sets of filter coefficients.
+ *
+ *      pswIn[0:159]   An array of input samples to be filtered, filtered
+ *                     output samples written to the same array.
+ *
+ *      pswXstate[0:3] An array containing x-state memory for two 2nd order
+ *                     filter sections.
+ *
+ *      pswYstate[0:7] An array containing y-state memory for two 2nd order
+ *                     filter sections.
+ *
+ *      npts           Number of samples to filter (must be even).
+ *
+ *      shifts         number of shifts to be made on output y(n).
+ *
+ *    OUTPUTS:
+ *
+ *       pswIn[0:159]  Output array containing the filtered input samples.
+ *
+ *    RETURN:
+ *
+ *       none.
+ *
+ *    DESCRIPTION:
+ *
+ *    data structure:
+ *
+ *    Coeff array order:  (b2,b1,b0,a2,a1)Section 1;(b2,b1,b0,a2,a1)Section 2
+ *    Xstate array order: (x(n-2),x(n-1))Section 1; (x(n-2),x(n-1))Section 2
+ *    Ystate array order: y(n-2)MSB,y(n-2)LSB,y(n-1)MSB,y(n-1)LSB Section 1
+ *                        y(n-2)MSB,y(n-2)LSB,y(n-1)MSB,y(n-1)LSB Section 2
+ *
+ *    REFERENCE:  Sub-clause 4.1.1 GSM Recommendation 06.20
+ *
+ *    KEYWORDS: highpass filter, hp, HP, filter
+ *
+ *************************************************************************/
+
+void   filt4_2nd(Shortword pswCoeff[], Shortword pswIn[],
+                        Shortword pswXstate[], Shortword pswYstate[],
+                        int npts, int shifts)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Do first second order section */
+  /*-------------------------------*/
+
+  iir_d(&pswCoeff[0],pswIn,&pswXstate[0],&pswYstate[0],npts,shifts,1,0);
+
+
+  /* Do second second order section */
+  /*--------------------------------*/
+
+  iir_d(&pswCoeff[5],pswIn,&pswXstate[2],&pswYstate[4],npts,shifts,0,1);
+
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: findBestInQuantList
+ *
+ *   PURPOSE:
+ *     Given a list of quantizer vectors and their associated prediction
+ *     errors, search the list for the iNumVectOut vectors and output them
+ *     as a new list.
+ *
+ *   INPUTS: psqlInList, iNumVectOut
+ *
+ *   OUTPUTS: psqlBestOutList
+ *
+ *   RETURN VALUE: none
+ *
+ *   DESCRIPTION:
+ *
+ *     The AFLAT recursion yields prediction errors.  This routine finds
+ *     the lowest candidate is the AFLAT recursion outputs.
+ *
+ *
+ *   KEYWORDS: best quantlist find
+ *
+ *   REFERENCE:  Sub-clause 4.1.4.1 GSM Recommendation 06.20
+ *
+ *************************************************************************/
+
+void findBestInQuantList(struct QuantList psqlInList,
+                                int iNumVectOut,
+                                struct QuantList psqlBestOutList[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+  int    quantIndex,
+         bstIndex,
+         i;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* initialize the best list */
+  /* invalidate, ensure they will be dropped */
+  for (bstIndex = 0; bstIndex < iNumVectOut; bstIndex++)
+  {
+    psqlBestOutList[bstIndex].iNum = 1;
+    psqlBestOutList[bstIndex].iRCIndex = psqlInList.iRCIndex;
+    psqlBestOutList[bstIndex].pswPredErr[0] = 0x7fff;
+  }
+
+  /* best list elements replaced in the order:  0,1,2,3... challenger must
+   * be < (not <= ) current best */
+  for (quantIndex = 0; quantIndex < psqlInList.iNum; quantIndex++)
+  {
+    bstIndex = 0;
+    while (sub(psqlInList.pswPredErr[quantIndex],
+               psqlBestOutList[bstIndex].pswPredErr[0]) >= 0 &&
+           bstIndex < iNumVectOut)
+    {
+      bstIndex++;                      /* only increments to next upon
+                                        * failure to beat "best" */
+    }
+
+    if (bstIndex < iNumVectOut)
+    {                                  /* a new value is found */
+      /* now add challenger to best list at index bstIndex */
+      for (i = iNumVectOut - 1; i > bstIndex; i--)
+      {
+        psqlBestOutList[i].pswPredErr[0] =
+                psqlBestOutList[i - 1].pswPredErr[0];
+        psqlBestOutList[i].iRCIndex =
+                psqlBestOutList[i - 1].iRCIndex;
+      }
+      /* get new best value and place in list */
+      psqlBestOutList[bstIndex].pswPredErr[0] =
+              psqlInList.pswPredErr[quantIndex];
+      psqlBestOutList[bstIndex].iRCIndex =
+              psqlInList.iRCIndex + quantIndex;
+    }
+  }
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: findPeak
+ *
+ *   PURPOSE:
+ *
+ *     The purpose of this function is to return the lag
+ *     that maximizes CC/G within +- PEAK_VICINITY of the
+ *     input lag.  The input lag is an integer lag, and
+ *     the search for a peak is done on the surrounding
+ *     integer lags.
+ *
+ *   INPUTS:
+ *
+ *     swSingleResLag
+ *
+ *                     Input integer lag, expressed as lag * OS_FCTR
+ *
+ *     pswCIn[0:127]
+ *
+ *                     C(k) sequence, k an integer
+ *
+ *     pswGIn[0:127]
+ *
+ *                     G(k) sequence, k an integer
+ *
+ *   OUTPUTS:
+ *
+ *     none
+ *
+ *   RETURN VALUE:
+ *
+ *     Integer lag where peak was found, or zero if no peak was found.
+ *     The lag is expressed as lag * OS_FCTR
+ *
+ *   DESCRIPTION:
+ *
+ *     This routine is called from pitchLags(), and is used to do the
+ *     interpolating CC/G peak search.  This is used in a number of
+ *     places in pitchLags().  See description 5.3.1.
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.2 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS:
+ *
+ *************************************************************************/
+
+Shortword findPeak(Shortword swSingleResLag,
+                          Shortword pswCIn[],
+                          Shortword pswGIn[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword swCmaxSqr,
+         swGmax,
+         swFullResPeak;
+  short int siUpperBound,
+         siLowerBound,
+         siRange,
+         siPeak;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* get upper and lower bounds for integer lags for peak search */
+  /* ----------------------------------------------------------- */
+
+  siUpperBound = add(swSingleResLag, PEAK_VICINITY + 1);
+  if (sub(siUpperBound, LMAX + 1) > 0)
+  {
+    siUpperBound = LMAX + 1;
+  }
+
+  siLowerBound = sub(swSingleResLag, PEAK_VICINITY + 1);
+  if (sub(siLowerBound, LMIN - 1) < 0)
+  {
+    siLowerBound = LMIN - 1;
+  }
+
+  siRange = sub(siUpperBound, siLowerBound);
+  siRange = add(siRange, 1);
+
+  /* do peak search */
+  /* -------------- */
+
+  swCmaxSqr = 0;
+  swGmax = 0x3f;
+
+  siPeak = fnBest_CG(&pswCIn[siLowerBound - LSMIN],
+                     &pswGIn[siLowerBound - LSMIN], &swCmaxSqr, &swGmax,
+                     siRange);
+
+  /* if no max found, flag no peak */
+  /* ----------------------------- */
+
+  if (add(siPeak, 1) == 0)
+  {
+    swFullResPeak = 0;
+  }
+
+  /* determine peak location      */
+  /* if at boundary, flag no peak */
+  /* else return lag at peak      */
+  /* ---------------------------- */
+
+  else
+  {
+    siPeak = add(siPeak, siLowerBound);
+
+    if ((sub(siPeak, siLowerBound) == 0) ||
+        (sub(siPeak, siUpperBound) == 0))
+    {
+      swFullResPeak = 0;
+    }
+    else
+    {
+      swFullResPeak = shr(extract_l(L_mult(siPeak, OS_FCTR)), 1);
+    }
+  }
+  return (swFullResPeak);
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: flat
+ *
+ *    PURPOSE:  Computes the unquantized reflection coefficients from the
+ *              input speech using the FLAT algorithm. Also computes the
+ *              frame energy, and the index of the element in the R0
+ *              quantization table which best represents the frame energy.
+ *              Calls function cov32 which computes the F, B, and C
+ *              correlation arrays, required by the FLAT algorithm to
+ *              compute the reflection coefficients.
+ *
+ *    INPUT:
+ *
+ *       pswSpeechIn[0:169]
+ *                     A sampled speech vector used to compute
+ *                     correlations need for generating the optimal
+ *                     reflection coefficients via the FLAT algorithm.
+ *
+ *    OUTPUTS:
+ *
+ *       pswRc[NP]     An array of unquantized reflection coefficients.
+ *
+ *       *piR0Inx      An index of the quantized frame energy value.
+ *
+ *       Longword pL_VadAcf[4]
+ *                     An array with the autocorrelation coefficients to be
+ *                     used by the VAD.  Generated by cov16(), a daughter
+ *                     function of flat().
+ *
+ *       Shortword *pswVadScalAuto
+ *                     Input scaling factor used by the VAD.
+ *                     Generated by cov16(), a daughter function of flat().
+ *                     function.
+ *
+ *    RETURN:          L_R0 normalized frame energy value, required in DTX
+ *                     mode.
+ *
+ *   DESCRIPTION:
+ *
+ *    An efficient Fixed point LAtice Technique (FLAT) is used to compute
+ *    the reflection coefficients, given B, F, and C arrays returned by
+ *    function cov32. B, F, and C are backward, forward, and cross
+ *    correlations computed from the input speech. The correlations
+ *    are spectrally smoothed in cov32.
+ *
+ *
+ *   REFERENCE:  Sub-clause 4.1.3 of GSM Recommendation 06.20
+ *
+ *   keywords: LPC, FLAT, reflection coefficients, covariance, correlation,
+ *   keywords: spectrum, energy, R0, spectral smoothing, SST
+ *
+ *************************************************************************/
+
+Longword   flat(Shortword pswSpeechIn[],
+                   Shortword pswRc[],
+                   int *piR0Inx,
+                   Longword pL_VadAcf[],
+                   Shortword *pswVadScalAuto)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+  Shortword
+         swNum,
+         swDen,
+         swRcSq,
+         swSqrtOut,
+         swRShifts,
+         swShift,
+         swShift1;
+  Longword
+         pppL_F[NP][NP][2],
+         pppL_B[NP][NP][2],
+         pppL_C[NP][NP][2],
+         L_Num,
+         L_TmpA,
+         L_TmpB,
+         L_temp,
+         L_sum,
+         L_R0,
+         L_Fik,
+         L_Bik,
+         L_Cik,
+         L_Cki;
+  short int i,
+         j,
+         k,
+         l,
+         j_0,
+         j_1;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Compute from the input speech the elements of the B, F, and C     */
+  /* arrays, which form the initial conditions for the FLAT algorithm. */
+  /*-------------------------------------------------------------------*/
+
+  swRShifts = cov32(pswSpeechIn, pppL_B, pppL_F, pppL_C, &L_R0,
+                    pL_VadAcf, pswVadScalAuto);
+
+  /* Compute the intermediate quantities required by the R0 quantizer */
+  /*------------------------------------------------------------------*/
+
+  if (L_R0 != 0)
+  {
+    swSqrtOut = sqroot(L_R0);          /* If L_R0 > 0, compute sqrt */
+  }
+  else
+  {
+    swSqrtOut = 0;                     /* L_R0 = 0, initialize sqrt(0) */
+  }
+
+  swRShifts = sub(S_SH + 2, swRShifts);
+
+  /* If odd number of shifts compensate by sqrt(0.5) */
+  /*-------------------------------------------------*/
+
+  if (swRShifts & 1)
+  {
+    L_temp = L_mult(swSqrtOut, 0x5a82);
+  }
+  else
+  {
+    L_temp = L_deposit_h(swSqrtOut);
+  }
+  swRShifts = shr(swRShifts, 1);
+
+  if (swRShifts > 0)
+  {
+    L_temp = L_shr(L_temp, swRShifts);
+  }
+  else if (swRShifts < 0)
+  {
+    L_temp = 0;
+  }
+
+  /* Given average energy L_temp, find the index in the R0 quantization */
+  /* table which best represents it.                                    */
+  /*--------------------------------------------------------------------*/
+
+  *piR0Inx = r0Quant(L_temp);
+
+  L_R0 = L_temp; /* save the unquantized R0 */             /* DTX mode */
+
+  /* Zero out the number of left-shifts to be applied to the  */
+  /* F, B, and C matrices.                                    */
+  /*----------------------------------------------------------*/
+
+  swShift = 0;
+
+  /* Now compute the NP reflection coefficients  */
+  /*---------------------------------------------*/
+
+  for (j = 0; j < NP; j++)
+  {
+
+    /* Initialize the modulo indices of the third dimension of arrays  */
+    /* F, B, and C, where indices j_0 and j_1 point to:                */
+    /* */
+    /* j_0 = points to F, B, and C matrix values at stage j-0, which   */
+    /* is the current  lattice stage.                                  */
+    /* j_1 = points to F, B, and C matrix values at stage j-1, which   */
+    /* is the previous lattice stage.                                  */
+    /* */
+    /* Use of modulo address arithmetic permits to swap values of j_0 and */
+    /* and j_1 at each lattice stage, thus eliminating the need to copy   */
+    /* the current elements of F, B, and C arrays, into the F, B, and C   */
+    /* arrays corresponding to the previous lattice stage, prior to       */
+    /* incrementing j, the index of the lattice filter stage.             */
+    /*--------------------------------------------------------------------*/
+
+    j_0 = (j + 1) % 2;
+    j_1 = j % 2;
+
+    /* Get the numerator for computing the j-th reflection coefficient */
+    /*-----------------------------------------------------------------*/
+
+    L_Num = L_add(L_shl(pppL_C[0][0][j_1], swShift),
+                  L_shl(pppL_C[NP - j - 1][NP - j - 1][j_1], swShift));
+
+    /* Get the denominator for computing the j-th reflection coefficient */
+    /*-------------------------------------------------------------------*/
+
+    L_temp = L_add(L_shl(pppL_F[0][0][j_1], swShift),
+                   L_shl(pppL_B[0][0][j_1], swShift));
+    L_TmpA = L_add(L_shl(pppL_F[NP - j - 1][NP - j - 1][j_1], swShift),
+                   L_shl(pppL_B[NP - j - 1][NP - j - 1][j_1], swShift));
+    L_sum = L_add(L_TmpA, L_temp);
+    L_sum = L_shr(L_sum, 1);
+
+    /* Normalize the numerator and the denominator terms */
+    /*---------------------------------------------------*/
+
+    swShift1 = norm_s(extract_h(L_sum));
+
+    L_sum = L_shl(L_sum, swShift1);
+    L_Num = L_shl(L_Num, swShift1);
+
+    swNum = round(L_Num);
+    swDen = round(L_sum);
+
+    if (swDen <= 0)
+    {
+
+      /* Zero prediction error at the j-th lattice stage, zero */
+      /* out remaining reflection coefficients and return.     */
+      /*-------------------------------------------------------*/
+
+      for (i = j; i < NP; i++)
+      {
+        pswRc[i] = 0;
+      }
+
+      return (L_R0);
+    }
+    else
+    {
+
+      /* Non-zero prediction error, check if the j-th reflection
+       * coefficient */
+      /* about to be computed is stable.                           */
+      /*-----------------------------------------------------------*/
+
+      if (sub(abs_s(swNum), swDen) >= 0)
+      {
+
+        /* Reflection coefficient at j-th lattice stage unstable, so zero  */
+        /* out reflection coefficients for lattice stages i=j,...,NP-1, and */
+        /* return.                                                         */
+        /*-----------------------------------------------------------------*/
+
+        for (i = j; i < NP; i++)
+        {
+          pswRc[i] = 0;
+        }
+
+        return (L_R0);
+      }
+      else
+      {
+
+        /* j-th reflection coefficient is stable, compute it. */
+        /*----------------------------------------------------*/
+
+        if (swNum < 0)
+        {
+
+          swNum = negate(swNum);
+          pswRc[j] = divide_s(swNum, swDen);
+
+        }
+        else
+        {
+
+          pswRc[j] = divide_s(swNum, swDen);
+          pswRc[j] = negate(pswRc[j]);
+
+        }                              /* j-th reflection coefficient
+                                        * sucessfully computed. */
+        /*----------------------------------------------------*/
+
+
+      }                                /* End of reflection coefficient
+                                        * stability test (and computation) */
+      /*------------------------------------------------------------------*/
+
+    }                                  /* End of non-zero prediction error
+                                        * case */
+    /*----------------------------------------*/
+
+
+
+    /* If not at the last lattice stage, update F, B, and C arrays */
+    /*-------------------------------------------------------------*/
+
+    if (j != NP - 1)
+    {
+
+      /* Compute squared Rc[j] */
+      /*-----------------------*/
+
+      swRcSq = mult_r(pswRc[j], pswRc[j]);
+
+      i = 0;
+      k = 0;
+
+      /* Compute the common terms used by the FLAT recursion to reduce */
+      /* computation.                                                  */
+      /*---------------------------------------------------------------*/
+
+      L_Cik = L_shl(pppL_C[i][k][j_1], swShift);
+
+      L_TmpA = L_add(L_Cik, L_Cik);
+      L_TmpA = L_mpy_ls(L_TmpA, pswRc[j]);
+
+      /* Update the F array */
+      /*--------------------*/
+
+      L_Fik = L_shl(pppL_F[i][k][j_1], swShift);
+      L_Bik = L_shl(pppL_B[i][k][j_1], swShift);
+
+      L_temp = L_mpy_ls(L_Bik, swRcSq);
+      L_temp = L_add(L_temp, L_Fik);
+      pppL_F[i][k][j_0] = L_add(L_temp, L_TmpA);
+
+      for (k = i + 1; k <= NP - j - 2; k++)
+      {
+
+        /* Compute the common terms used by the FLAT recursion to reduce */
+        /* computation.                                                  */
+        /*---------------------------------------------------------------*/
+
+        L_Cik = L_shl(pppL_C[i][k][j_1], swShift);
+        L_Cki = L_shl(pppL_C[k][i][j_1], swShift);
+
+        L_TmpA = L_add(L_Cik, L_Cki);
+        L_TmpA = L_mpy_ls(L_TmpA, pswRc[j]);
+
+        L_Bik = L_shl(pppL_B[i][k][j_1], swShift);
+        L_Fik = L_shl(pppL_F[i][k][j_1], swShift);
+
+        L_TmpB = L_add(L_Bik, L_Fik);
+        L_TmpB = L_mpy_ls(L_TmpB, pswRc[j]);
+
+        /* Update the F and C arrays */
+        /*---------------------------------*/
+
+        L_temp = L_mpy_ls(L_Bik, swRcSq);
+        L_temp = L_add(L_temp, L_Fik);
+        pppL_F[i][k][j_0] = L_add(L_temp, L_TmpA);
+
+        L_temp = L_mpy_ls(L_Cki, swRcSq);
+        L_temp = L_add(L_temp, L_Cik);
+        pppL_C[i][k - 1][j_0] = L_add(L_temp, L_TmpB);
+
+      }
+
+      k = NP - j - 1;
+
+      /* Compute the common terms used by the FLAT recursion to reduce */
+      /* computation.                                                  */
+      /*---------------------------------------------------------------*/
+
+      L_Bik = L_shl(pppL_B[i][k][j_1], swShift);
+      L_Fik = L_shl(pppL_F[i][k][j_1], swShift);
+
+      L_TmpB = L_add(L_Bik, L_Fik);
+      L_TmpB = L_mpy_ls(L_TmpB, pswRc[j]);
+
+      /* Update the C array */
+      /*-----------------------*/
+
+      L_Cik = L_shl(pppL_C[i][k][j_1], swShift);
+      L_Cki = L_shl(pppL_C[k][i][j_1], swShift);
+
+      L_temp = L_mpy_ls(L_Cki, swRcSq);
+      L_temp = L_add(L_temp, L_Cik);
+      pppL_C[i][k - 1][j_0] = L_add(L_temp, L_TmpB);
+
+
+      for (i = 1; i <= NP - j - 2; i++)
+      {
+
+        k = i;
+
+        /* Compute the common terms used by the FLAT recursion to reduce */
+        /* computation.                                                  */
+        /*---------------------------------------------------------------*/
+
+        L_Cik = L_shl(pppL_C[i][k][j_1], swShift);
+
+        L_TmpA = L_add(L_Cik, L_Cik);
+        L_TmpA = L_mpy_ls(L_TmpA, pswRc[j]);
+
+        L_Bik = L_shl(pppL_B[i][k][j_1], swShift);
+        L_Fik = L_shl(pppL_F[i][k][j_1], swShift);
+
+        L_TmpB = L_add(L_Bik, L_Fik);
+        L_TmpB = L_mpy_ls(L_TmpB, pswRc[j]);
+
+        /* Update F, B and C arrays */
+        /*-----------------------------------*/
+
+        L_temp = L_mpy_ls(L_Bik, swRcSq);
+        L_temp = L_add(L_temp, L_Fik);
+        pppL_F[i][k][j_0] = L_add(L_temp, L_TmpA);
+
+        L_temp = L_mpy_ls(L_Fik, swRcSq);
+        L_temp = L_add(L_temp, L_Bik);
+        pppL_B[i - 1][k - 1][j_0] = L_add(L_temp, L_TmpA);
+
+        L_temp = L_mpy_ls(L_Cik, swRcSq);
+        L_temp = L_add(L_temp, L_Cik);
+        pppL_C[i][k - 1][j_0] = L_add(L_temp, L_TmpB);
+
+        for (k = i + 1; k <= NP - j - 2; k++)
+        {
+
+          /* Compute the common terms used by the FLAT recursion to reduce */
+          /* computation.                                                  */
+          /*---------------------------------------------------------------*/
+
+          L_Cik = L_shl(pppL_C[i][k][j_1], swShift);
+          L_Cki = L_shl(pppL_C[k][i][j_1], swShift);
+
+          L_TmpA = L_add(L_Cik, L_Cki);
+          L_TmpA = L_mpy_ls(L_TmpA, pswRc[j]);
+
+          L_Bik = L_shl(pppL_B[i][k][j_1], swShift);
+          L_Fik = L_shl(pppL_F[i][k][j_1], swShift);
+
+          L_TmpB = L_add(L_Bik, L_Fik);
+          L_TmpB = L_mpy_ls(L_TmpB, pswRc[j]);
+
+          /* Update F, B and C arrays */
+          /*-----------------------------------*/
+
+          L_temp = L_mpy_ls(L_Bik, swRcSq);
+          L_temp = L_add(L_temp, L_Fik);
+          pppL_F[i][k][j_0] = L_add(L_temp, L_TmpA);
+
+          L_temp = L_mpy_ls(L_Fik, swRcSq);
+          L_temp = L_add(L_temp, L_Bik);
+          pppL_B[i - 1][k - 1][j_0] = L_add(L_temp, L_TmpA);
+
+          L_temp = L_mpy_ls(L_Cki, swRcSq);
+          L_temp = L_add(L_temp, L_Cik);
+          pppL_C[i][k - 1][j_0] = L_add(L_temp, L_TmpB);
+
+          L_temp = L_mpy_ls(L_Cik, swRcSq);
+          L_temp = L_add(L_temp, L_Cki);
+          pppL_C[k][i - 1][j_0] = L_add(L_temp, L_TmpB);
+
+        }                              /* end of loop indexed by k */
+        /*---------------------------*/
+
+        k = NP - j - 1;
+
+        /* Compute the common terms used by the FLAT recursion to reduce */
+        /* computation.                                                  */
+        /*---------------------------------------------------------------*/
+
+        L_Cik = L_shl(pppL_C[i][k][j_1], swShift);
+        L_Cki = L_shl(pppL_C[k][i][j_1], swShift);
+
+        L_TmpA = L_add(L_Cik, L_Cki);
+        L_TmpA = L_mpy_ls(L_TmpA, pswRc[j]);
+
+        L_Bik = L_shl(pppL_B[i][k][j_1], swShift);
+        L_Fik = L_shl(pppL_F[i][k][j_1], swShift);
+
+        L_TmpB = L_add(L_Bik, L_Fik);
+        L_TmpB = L_mpy_ls(L_TmpB, pswRc[j]);
+
+        /* Update B and C arrays */
+        /*-----------------------------------*/
+
+        L_temp = L_mpy_ls(L_Fik, swRcSq);
+        L_temp = L_add(L_temp, L_Bik);
+        pppL_B[i - 1][k - 1][j_0] = L_add(L_temp, L_TmpA);
+
+        L_temp = L_mpy_ls(L_Cki, swRcSq);
+        L_temp = L_add(L_temp, L_Cik);
+        pppL_C[i][k - 1][j_0] = L_add(L_temp, L_TmpB);
+
+      }                                /* end of loop indexed by i */
+      /*---------------------------*/
+
+      i = NP - j - 1;
+      for (k = i; k <= NP - j - 1; k++)
+      {
+
+        /* Compute the common terms used by the FLAT recursion to reduce */
+        /* computation.                                                  */
+        /*---------------------------------------------------------------*/
+
+        L_Cik = L_shl(pppL_C[i][k][j_1], swShift);
+
+        L_TmpA = L_add(L_Cik, L_Cik);
+        L_TmpA = L_mpy_ls(L_TmpA, pswRc[j]);
+
+        /* Update B array */
+        /*-----------------------------------*/
+
+        L_Bik = L_shl(pppL_B[i][k][j_1], swShift);
+        L_Fik = L_shl(pppL_F[i][k][j_1], swShift);
+
+        L_temp = L_mpy_ls(L_Fik, swRcSq);
+        L_temp = L_add(L_temp, L_Bik);
+        pppL_B[i - 1][k - 1][j_0] = L_add(L_temp, L_TmpA);
+
+      }                                /* end of loop indexed by k */
+      /*-----------------------------------------------------------*/
+
+      /* OR the F and B matrix diagonals to find maximum for normalization */
+      /*********************************************************************/
+
+      L_TmpA = 0;
+      for (l = 0; l <= NP - j - 2; l++)
+      {
+        L_TmpA |= pppL_F[l][l][j_0];
+        L_TmpA |= pppL_B[l][l][j_0];
+      }
+      /* Compute the shift count to be applied to F, B, and C arrays */
+      /* at the next lattice stage.                                  */
+      /*-------------------------------------------------------------*/
+
+      if (L_TmpA > 0)
+      {
+        swShift = norm_l(L_TmpA);
+        swShift = sub(swShift, CVSHIFT);
+      }
+      else
+      {
+        swShift = 0;
+      }
+
+    }                                  /* End of update of F, B, and C
+                                        * arrays for the next lattice stage */
+    /*----------------------------------------------------------------*/
+
+  }                                    /* Finished computation of
+                                        * reflection coefficients */
+  /*--------------------------------------------------------------*/
+
+  return (L_R0);
+
+}
+
+/**************************************************************************
+ *
+ *   FUNCTION NAME: fnBest_CG
+ *
+ *   PURPOSE:
+ *     The purpose of this function is to determine the C:G pair from the
+ *     input arrays which maximize C*C/G
+ *
+ *   INPUTS:
+ *
+ *     pswCframe[0:siNumPairs]
+ *
+ *                     pointer to start of the C frame vector
+ *
+ *     pswGframe[0:siNumPairs]
+ *
+ *                     pointer to start of the G frame vector
+ *
+ *     pswCmaxSqr
+ *
+ *                     threshold Cmax**2 or 0 if no threshold
+ *
+ *     pswGmax
+ *
+ *                     threshold Gmax, must be > 0
+ *
+ *     siNumPairs
+ *
+ *                     number of C:G pairs to test
+ *
+ *   OUTPUTS:
+ *
+ *     pswCmaxSqr
+ *
+ *                     final Cmax**2 value
+ *
+ *     pswGmax
+ *
+ *                     final Gmax value
+ *
+ *   RETURN VALUE:
+ *
+ *     siMaxLoc
+ *
+ *                     index of Cmax in the input C matrix or -1 if none
+ *
+ *   DESCRIPTION:
+ *
+ *     test the result of (C * C * Gmax) - (Cmax**2 * G)
+ *     if the result is > 0 then a new max has been found
+ *     the Cmax**2, Gmax and MaxLoc parameters are all updated accordingly.
+ *     if no new max is found for all NumPairs then MaxLoc will retain its
+ *     original value
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.1, 4.1.8.2, and 4.1.8.3 of GSM
+ *     Recommendation 06.20
+ *
+ *   KEYWORDS: C_Frame, G_Frame, Cmax, Gmax, DELTA_LAGS, PITCH_LAGS
+ *
+
+****************************************************************************/
+
+short int fnBest_CG(Shortword pswCframe[], Shortword pswGframe[],
+                           Shortword *pswCmaxSqr, Shortword *pswGmax,
+                           short int siNumPairs)
+{
+
+/*_________________________________________________________________________
+|                                                                           |
+|                            Automatic Variables                            |
+|___________________________________________________________________________|
+*/
+
+  Longword L_Temp2;
+  Shortword swCmaxSqr,
+         swGmax,
+         swTemp;
+  short int siLoopCnt,
+         siMaxLoc;
+
+/*_________________________________________________________________________
+|                                                                           |
+|                              Executable Code                              |
+|___________________________________________________________________________|
+*/
+
+  /* initialize */
+  /* ---------- */
+
+  swCmaxSqr = *pswCmaxSqr;
+  swGmax = *pswGmax;
+  siMaxLoc = -1;
+
+  for (siLoopCnt = 0; siLoopCnt < siNumPairs; siLoopCnt++)
+  {
+
+    /* make sure both C and energy > 0 */
+    /* ------------------------------- */
+
+    if ((pswGframe[siLoopCnt] > 0) && (pswCframe[siLoopCnt] > 0))
+    {
+
+      /* calculate (C * C) */
+      /* ----------------- */
+
+      swTemp = mult_r(pswCframe[siLoopCnt], pswCframe[siLoopCnt]);
+
+      /* calculate (C * C * Gmax) */
+      /* ------------------------ */
+
+      L_Temp2 = L_mult(swTemp, swGmax);
+
+      /* calculate (C * C * Gmax) - (Cmax**2 * G) */
+      /* ----------------------------------------- */
+
+      L_Temp2 = L_msu(L_Temp2, swCmaxSqr, pswGframe[siLoopCnt]);
+
+      /* if new max found, update it and its location */
+      /* -------------------------------------------- */
+
+      if (L_Temp2 > 0)
+      {
+        swCmaxSqr = swTemp;            /* Cmax**2 = current C * C */
+        swGmax = pswGframe[siLoopCnt]; /* Gmax */
+        siMaxLoc = siLoopCnt;          /* max location = current (C)
+                                        * location */
+      }
+    }
+  }
+
+  /* set output */
+  /* ---------- */
+
+  *pswCmaxSqr = swCmaxSqr;
+  *pswGmax = swGmax;
+  return (siMaxLoc);
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: fnExp2
+ *
+ *   PURPOSE:
+ *     The purpose of this function is to implement a base two exponential
+ *     2**(32*x) by polynomial approximation
+ *
+ *
+ *   INPUTS:
+ *
+ *     L_Input
+ *
+ *                     unnormalized input exponent (input range constrained
+ *                     to be < 0; for input < -0.46 output is 0)
+ *
+ *   OUTPUTS:
+ *
+ *     none
+ *
+ *   RETURN VALUE:
+ *
+ *     swTemp4
+ *
+ *                     exponential output
+ *
+ *   DESCRIPTION:
+ *
+ *     polynomial approximation is used for the generation of the exponential
+ *
+ *     2**(32*X) = 0.1713425*X*X + 0.6674432*X + 0.9979554
+ *                     c2              c1            c0
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.2 of GSM Recommendation 06.20, eqn 3.9
+ *
+ *   KEYWORDS: EXP2, DELTA_LAGS
+ *
+ *************************************************************************/
+
+Shortword fnExp2(Longword L_Input)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                           Local Static Variables                        |
+ |_________________________________________________________________________|
+*/
+  static Shortword pswPCoefE[3] =
+  {                                    /* c2,   c1,    c0 */
+    0x15ef, 0x556f, 0x7fbd
+  };
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword swTemp1,
+         swTemp2,
+         swTemp3,
+         swTemp4;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* initialize */
+  /* ---------- */
+
+  swTemp3 = 0x0020;
+
+  /* determine normlization shift count */
+  /* ---------------------------------- */
+
+  swTemp1 = extract_h(L_Input);
+  L_Input = L_mult(swTemp1, swTemp3);
+  swTemp2 = extract_h(L_Input);
+
+  /* determine un-normalized shift count */
+  /* ----------------------------------- */
+
+  swTemp3 = -0x0001;
+  swTemp4 = sub(swTemp3, swTemp2);
+
+  /* normalize input */
+  /* --------------- */
+
+  L_Input = L_Input & LSP_MASK;
+  L_Input = L_add(L_Input, L_deposit_h(swTemp3));
+
+  L_Input = L_shr(L_Input, 1);
+  swTemp1 = extract_l(L_Input);
+
+  /* calculate x*x*c2 */
+  /* ---------------- */
+
+  swTemp2 = mult_r(swTemp1, swTemp1);
+  L_Input = L_mult(swTemp2, pswPCoefE[0]);
+
+  /* calculate x*x*c2 + x*c1 */
+  /* ----------------------- */
+
+  L_Input = L_mac(L_Input, swTemp1, pswPCoefE[1]);
+
+  /* calculate x*x*c2 + x*c1 + c0 */
+  /* --------------------------- */
+
+  L_Input = L_add(L_Input, L_deposit_h(pswPCoefE[2]));
+
+  /* un-normalize exponent if its requires it */
+  /* ---------------------------------------- */
+
+  if (swTemp4 > 0)
+  {
+    L_Input = L_shr(L_Input, swTemp4);
+  }
+
+  /* return result */
+  /* ------------- */
+
+  swTemp4 = extract_h(L_Input);
+  return (swTemp4);
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: fnLog2
+ *
+ *   PURPOSE:
+ *     The purpose of this function is to take the log base 2 of input and
+ *     divide by 32 and return; i.e. output = log2(input)/32
+ *
+ *   INPUTS:
+ *
+ *     L_Input
+ *
+ *                     input
+ *
+ *   OUTPUTS:
+ *
+ *     none
+ *
+ *   RETURN VALUE:
+ *
+ *     Shortword
+ *
+ *                     output
+ *
+ *   DESCRIPTION:
+ *
+ *     log2(x) = 4.0 * (-.3372223*x*x + .9981958*x -.6626105)
+ *                           c0            c1          c2   (includes sign)
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.2 of GSM Recommendation 06.20, eqn 3.9
+ *
+ *   KEYWORDS: log, logarithm, logbase2, fnLog2
+ *
+ *************************************************************************/
+
+Shortword fnLog2(Longword L_Input)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                           Static Variables                              |
+ |_________________________________________________________________________|
+*/
+
+  static Shortword
+         swC0 = -0x2b2a,
+         swC1 = 0x7fc5,
+         swC2 = -0x54d0;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  short int siShiftCnt;
+  Shortword swInSqrd,
+         swIn;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* normalize input and store shifts required */
+  /* ----------------------------------------- */
+
+  siShiftCnt = norm_l(L_Input);
+  L_Input = L_shl(L_Input, siShiftCnt);
+  siShiftCnt = add(siShiftCnt, 1);
+  siShiftCnt = negate(siShiftCnt);
+
+  /* calculate x*x*c0 */
+  /* ---------------- */
+
+  swIn = extract_h(L_Input);
+  swInSqrd = mult_r(swIn, swIn);
+  L_Input = L_mult(swInSqrd, swC0);
+
+  /* add x*c1 */
+  /* --------- */
+
+  L_Input = L_mac(L_Input, swIn, swC1);
+
+  /* add c2 */
+  /* ------ */
+
+  L_Input = L_add(L_Input, L_deposit_h(swC2));
+
+  /* apply *(4/32) */
+  /* ------------- */
+
+  L_Input = L_shr(L_Input, 3);
+  L_Input = L_Input & 0x03ffffff;
+  siShiftCnt = shl(siShiftCnt, 10);
+  L_Input = L_add(L_Input, L_deposit_h(siShiftCnt));
+
+  /* return log */
+  /* ---------- */
+
+  return (round(L_Input));
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: getCCThreshold
+ *
+ *   PURPOSE:
+ *     The purpose of this function is to calculate a threshold for other
+ *     correlations (subject to limits), given subframe energy (Rp0),
+ *     correlation squared (CC), and energy of delayed sequence (G)
+ *
+ *   INPUTS:
+ *
+ *     swRp0
+ *
+ *                     energy of the subframe
+ *
+ *     swCC
+ *
+ *                     correlation (squared) of subframe and delayed sequence
+ *
+ *     swG
+ *
+ *                     energy of delayed sequence
+ *
+ *   OUTPUTS:
+ *
+ *     none
+ *
+ *   RETURN VALUE:
+ *
+ *     swCCThreshold
+ *
+ *                     correlation (squared) threshold
+ *
+ *   DESCRIPTION:
+ *
+ *     CCt/0.5 = R - R(antilog(SCALE*log(max(CLAMP,(RG-CC)/RG))))
+ *
+ *     The threshold CCt is then applied with an understood value of Gt = 0.5
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.2 of GSM Recommendation 06.20, eqn 3.9
+ *
+ *   KEYWORDS: getCCThreshold, getccthreshold, GET_CSQ_THRES
+ *
+ *************************************************************************/
+
+Shortword getCCThreshold(Shortword swRp0,
+                                Shortword swCC,
+                                Shortword swG)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword swPGainClamp,
+         swPGainScale,
+         sw1;
+  Longword L_1;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* load CLAMP and SCALE */
+  /* -------------------- */
+
+  swPGainClamp = PGAIN_CLAMP;
+  swPGainScale = PGAIN_SCALE;
+
+  /* calculate RG-CC */
+  /* --------------- */
+
+  L_1 = L_mult(swRp0, swG);
+  sw1 = extract_h(L_1);
+  L_1 = L_sub(L_1, L_deposit_h(swCC));
+
+  /* if RG - CC > 0 do max(CLAMP, (RG-CC)/RG) */
+  /* ---------------------------------------- */
+
+  if (L_1 > 0)
+  {
+
+    sw1 = divide_s(extract_h(L_1), sw1);
+
+    L_1 = L_deposit_h(sw1);
+
+    if (sub(sw1, swPGainClamp) <= 0)
+    {
+      L_1 = L_deposit_h(swPGainClamp);
+    }
+  }
+  /* else max(CLAMP, (RG-CC)/RG) is CLAMP */
+  /* ------------------------------------ */
+
+  else
+  {
+    L_1 = L_deposit_h(swPGainClamp);
+  }
+
+  /* L_1 holds max(CLAMP, (RG-CC)/RG)   */
+  /* do antilog( SCALE * log( max() ) ) */
+  /* ---------------------------------- */
+
+  sw1 = fnLog2(L_1);
+
+  L_1 = L_mult(sw1, swPGainScale);
+
+  sw1 = fnExp2(L_1);
+
+
+  /* do R - (R * antilog()) */
+  /* ---------------------- */
+
+  L_1 = L_deposit_h(swRp0);
+  L_1 = L_msu(L_1, swRp0, sw1);
+
+  /* apply Gt value */
+  /* -------------- */
+
+  L_1 = L_shr(L_1, 1);
+
+  return (extract_h(L_1));
+}
+
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: getNWCoefs
+ *
+ *   PURPOSE:
+ *
+ *     Obtains best all-pole fit to various noise weighting
+ *     filter combinations
+ *
+ *   INPUTS:
+ *
+ *     pswACoefs[0:9] - A(z) coefficient array
+ *     psrNWCoefs[0:9] - filter smoothing coefficients
+ *
+ *   OUTPUTS:
+ *
+ *     pswHCoefs[0:9] - H(z) coefficient array
+ *
+ *   RETURN VALUE:
+ *
+ *     None
+ *
+ *   DESCRIPTION:
+ *
+ *     The function getNWCoefs() derives the spectral noise weighting
+ *     coefficients W(z)and H(z).  W(z) and H(z) actually consist of
+ *     three filters in cascade.  To avoid having such a complicated
+ *     filter required for weighting, the filters are reduced to a
+ *     single filter.
+ *
+ *     This is accomplished by passing an impulse through the cascased
+ *     filters.  The impulse response of the filters is used to generate
+ *     autocorrelation coefficients, which are then are transformed into
+ *     a single direct form estimate of W(z) and H(z).  This estimate is
+ *     called HHat(z) in the documentation.
+ *
+ *
+ *   REFERENCE:  Sub-clause 4.1.7 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS: spectral noise weighting, direct form coefficients
+ *   KEYWORDS: getNWCoefs
+ *
+ *************************************************************************/
+
+void   getNWCoefs(Shortword pswACoefs[],
+                         Shortword pswHCoefs[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword pswCoefTmp2[NP],
+         pswCoefTmp3[NP],
+         pswVecTmp[S_LEN],
+         pswVecTmp2[S_LEN],
+         pswTempRc[NP];
+  Shortword swNormShift,
+         iLoopCnt,
+         iLoopCnt2;
+  Longword pL_AutoCorTmp[NP + 1],
+         L_Temp;
+  short int siNum,
+         k;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Calculate smoothing parameters for all-zero filter */
+  /* -------------------------------------------------- */
+
+  for (iLoopCnt = 0; iLoopCnt < NP; iLoopCnt++)
+  {
+    pswCoefTmp2[iLoopCnt]
+            = mult_r(psrNWCoefs[iLoopCnt], pswACoefs[iLoopCnt]);
+  }
+
+  /* Calculate smoothing parameters for all-pole filter */
+  /* -------------------------------------------------- */
+
+  for (iLoopCnt = 0; iLoopCnt < NP; iLoopCnt++)
+  {
+    pswCoefTmp3[iLoopCnt] = msu_r(0, psrNWCoefs[iLoopCnt + NP],
+                                  pswACoefs[iLoopCnt]);
+  }
+
+  /* Get impulse response of 1st filter                             */
+  /* Done by direct form IIR filter of order NP zero input response */
+  /* -------------------------------------------------------------- */
+
+  lpcIrZsIir(pswACoefs, pswVecTmp2);
+
+  /* Send impulse response of 1st filter through 2nd filter */
+  /* All-zero filter (FIR)                                  */
+  /* ------------------------------------------------------ */
+
+  lpcZsFir(pswVecTmp2, pswCoefTmp2, pswVecTmp);
+
+  /* Send impulse response of 2nd filter through 3rd filter */
+  /* All-pole filter (IIR)                                  */
+  /* ------------------------------------------------------ */
+
+  lpcZsIirP(pswVecTmp, pswCoefTmp3);
+
+  /* Calculate energy in impulse response */
+  /* ------------------------------------ */
+
+  swNormShift = g_corr1(pswVecTmp, &L_Temp);
+
+  pL_AutoCorTmp[0] = L_Temp;
+
+  /* Calculate normalized autocorrelation function */
+  /* --------------------------------------------- */
+
+  for (k = 1; k <= NP; k++)
+  {
+
+    /* Calculate R(k), equation 2.31 */
+    /* ----------------------------- */
+
+    L_Temp = L_mult(pswVecTmp[0], pswVecTmp[0 + k]);
+
+    for (siNum = S_LEN - k, iLoopCnt2 = 1; iLoopCnt2 < siNum; iLoopCnt2++)
+    {
+      L_Temp = L_mac(L_Temp, pswVecTmp[iLoopCnt2],
+                     pswVecTmp[iLoopCnt2 + k]);
+    }
+
+    /* Normalize R(k) relative to R(0): */
+    /* -------------------------------- */
+
+    pL_AutoCorTmp[k] = L_shl(L_Temp, swNormShift);
+
+  }
+
+
+  /* Convert normalized autocorrelations to direct form coefficients */
+  /* --------------------------------------------------------------- */
+
+  aFlatRcDp(pL_AutoCorTmp, pswTempRc);
+  rcToADp(ASCALE, pswTempRc, pswHCoefs);
+
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: getNextVec
+ *
+ *   PURPOSE:
+ *     The purpose of this function is to get the next vector in the list.
+ *
+ *   INPUTS: none
+ *
+ *   OUTPUTS: pswRc
+ *
+ *   RETURN VALUE: none
+ *
+ *   DESCRIPTION:
+ *
+ *     Both the quantizer and pre-quantizer are set concatenated 8 bit
+ *     words.  Each of these words represents a reflection coefficient.
+ *     The 8 bit words, are actually indices into a reflection
+ *     coefficient lookup table.  Memory is organized in 16 bit words, so
+ *     there are two reflection coefficients per ROM word.
+ *
+ *
+ *     The full quantizer is subdivided into blocks.  Each of the
+ *     pre-quantizers vectors "points" to a full quantizer block.  The
+ *     vectors in a block, are comprised of either three or four
+ *     elements.  These are concatenated, without leaving any space
+ *     between them.
+ *
+ *     A block of full quantizer elements always begins on an even word.
+ *     This may or may not leave a space depending on vector quantizer
+ *     size.
+ *
+ *     getNextVec(), serves to abstract this arcane data format.  Its
+ *     function is to simply get the next reflection coefficient vector
+ *     in the list, be it a pre or full quantizer list.  This involves
+ *     figuring out whether to pick the low or the high part of the 16
+ *     bit ROM word.  As well as transforming the 8 bit stored value
+ *     into a fractional reflection coefficient.  It also requires a
+ *     setup routine to initialize iWordPtr and iWordHalfPtr, two
+ *     variables global to this file.
+ *
+ *
+ *
+ *   REFERENCE:  Sub-clause 4.1.4.1 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS: Quant quant vector quantizer
+ *
+ *************************************************************************/
+
+void   getNextVec(Shortword pswRc[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+  int    i;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+  i = iLow;
+
+  if (iThree)
+  {
+
+    if (iWordHalfPtr == HIGH)
+    {
+      pswRc[i++] = psrSQuant[high(psrTable[iWordPtr])];
+      pswRc[i++] = psrSQuant[low(psrTable[iWordPtr++])];
+      pswRc[i] = psrSQuant[high(psrTable[iWordPtr])];
+      iWordHalfPtr = LOW;
+    }
+    else
+    {
+      pswRc[i++] = psrSQuant[low(psrTable[iWordPtr++])];
+      pswRc[i++] = psrSQuant[high(psrTable[iWordPtr])];
+      pswRc[i] = psrSQuant[low(psrTable[iWordPtr++])];
+      iWordHalfPtr = HIGH;
+    }
+
+  }
+  else
+  {
+    pswRc[i++] = psrSQuant[high(psrTable[iWordPtr])];
+    pswRc[i++] = psrSQuant[low(psrTable[iWordPtr++])];
+    pswRc[i++] = psrSQuant[high(psrTable[iWordPtr])];
+    pswRc[i] = psrSQuant[low(psrTable[iWordPtr++])];
+  }
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: getSfrmLpcTx
+ *
+ *    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.
+ *
+ *    INPUT:
+ *       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[NP-1]
+ *        t=-NP element.
+ *       pswPrevFrmKs[NP] - decoded version of the rc's tx'd last frame
+ *       pswPrevFrmAs[NP] - the above K's converted to A's.  i.e. direct
+ *          form coefficients.
+ *       pswPrevFrmSNWCoef[NP] - Coefficients for the Spectral Noise
+ *          weighting filter from the previous frame
+ *
+ *       pswHPFSppech - pointer to High Pass Filtered Input speech
+ *
+ *       pswSoftInterp - a flag containing the soft interpolation
+ *          decision.
+ *
+ *       Current lpc coefficients from the current frame:
+ *       pswNewFrmKs[NP],pswNewFrmAs[NP],
+ *       pswNewFrmSNWCoef[NP] - Spectral Noise Weighting Coefficients
+ *           for the current frame
+ *       ppswSNWCoefAs[1][NP] - pointer into a matrix containing
+ *           the interpolated and uninterpolated LP Coefficient
+ *           values for the Spectral Noise Weighting Filter.
+ *
+ *    OUTPUT:
+ *       psnsSqrtRs[N_SUB] - a normalized number (struct NormSw)
+ *          containing an estimate
+ *          of RS for each subframe.  (number and a shift)
+ *
+ *       ppswSynthAs[N_SUM][NP] - filter coefficients used by the
+ *          synthesis filter.
+ *
+ *    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.
+ *
+ *
+ *    REFERENCE: Sub-clause of 4.1.6 and 4.1.7 of GSM Recommendation
+ *        06.20
+ *
+ *    KEYWORDS: soft interpolation, int_lpc, interpolate, atorc, res_eng
+ *
+ *************************************************************************/
+
+
+void   getSfrmLpcTx(Shortword swPrevR0, Shortword swNewR0,
+/* last frm*/
+                       Shortword pswPrevFrmKs[], Shortword pswPrevFrmAs[],
+                           Shortword pswPrevFrmSNWCoef[],
+/* this frm*/
+                         Shortword pswNewFrmKs[], Shortword pswNewFrmAs[],
+                           Shortword pswNewFrmSNWCoef[],
+                           Shortword pswHPFSpeech[],
+/* output */
+                           short *pswSoftInterp,
+                           struct NormSw *psnsSqrtRs,
+               Shortword ppswSynthAs[][NP], Shortword ppswSNWCoefAs[][NP])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword swSi;
+  Longword L_Temp;
+  short int siSfrm,
+         siStable,
+         i;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* perform interpolation - both for synth filter and noise wgt filt */
+  /*------------------------------------------------------------------*/
+  siSfrm = 0;
+  siStable = interpolateCheck(pswPrevFrmKs, pswPrevFrmAs,
+                              pswPrevFrmAs, pswNewFrmAs,
+                              psrOldCont[siSfrm], psrNewCont[siSfrm],
+                              swPrevR0,
+                              &psnsSqrtRs[siSfrm],
+                              ppswSynthAs[siSfrm]);
+  if (siStable)
+  {
+    for (i = 0; i < NP; i++)
+    {
+      L_Temp = L_mult(pswNewFrmSNWCoef[i], psrNewCont[siSfrm]);
+      ppswSNWCoefAs[siSfrm][i] = mac_r(L_Temp, pswPrevFrmSNWCoef[i],
+                                       psrOldCont[siSfrm]);
+    }
+  }
+  else
+  {
+
+    /* this subframe is unstable */
+    /*---------------------------*/
+
+    for (i = 0; i < NP; i++)
+    {
+      ppswSNWCoefAs[siSfrm][i] = pswPrevFrmSNWCoef[i];
+    }
+
+  }
+
+  /* interpolate subframes one and two */
+  /*-----------------------------------*/
+
+  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)
+    {
+      for (i = 0; i < NP; i++)
+      {
+        L_Temp = L_mult(pswNewFrmSNWCoef[i], psrNewCont[siSfrm]);
+        ppswSNWCoefAs[siSfrm][i] = mac_r(L_Temp, pswPrevFrmSNWCoef[i],
+                                         psrOldCont[siSfrm]);
+      }
+    }
+    else
+    {
+      /* this sfrm has unstable filter coeffs, would like to interp but
+       * cant */
+      /*--------------------------------------*/
+
+      for (i = 0; i < NP; i++)
+      {
+        ppswSNWCoefAs[siSfrm][i] = pswNewFrmSNWCoef[i];
+      }
+
+    }
+  }
+
+
+  /* the last subframe: never interpolate. */
+  /*--------------------------------------*/
+
+  siSfrm = 3;
+  for (i = 0; i < NP; i++)
+  {
+    ppswSNWCoefAs[siSfrm][i] = pswNewFrmSNWCoef[i];
+    ppswSynthAs[siSfrm][i] = pswNewFrmAs[i];
+  }
+
+  /* calculate the residual energy for the last subframe */
+  /*-----------------------------------------------------*/
+
+  res_eng(pswNewFrmKs, swNewR0, &psnsSqrtRs[siSfrm]);
+
+
+
+  /* done with interpolation, now compare the two sets of coefs.   */
+  /* make the decision whether to interpolate (1) or not (0)       */
+  /*---------------------------------------------------------------*/
+
+  swSi = compResidEnergy(pswHPFSpeech,
+                         ppswSynthAs, pswPrevFrmAs,
+                         pswNewFrmAs, psnsSqrtRs);
+
+  if (swSi == 0)
+  {
+
+    /* no interpolation done: copy the frame based data to output
+     * coeffiecient arrays */
+
+    siSfrm = 0;
+    for (i = 0; i < NP; i++)
+    {
+      ppswSNWCoefAs[siSfrm][i] = pswPrevFrmSNWCoef[i];
+      ppswSynthAs[siSfrm][i] = pswPrevFrmAs[i];
+    }
+
+    /* get RS (energy in the residual) for subframe 0 */
+    /*------------------------------------------------*/
+
+    res_eng(pswPrevFrmKs, swPrevR0, &psnsSqrtRs[siSfrm]);
+
+    /* for subframe 1 and all subsequent sfrms, use lpc and R0 from new frm */
+    /*---------------------------------------------------------------------*/
+
+    res_eng(pswNewFrmKs, swNewR0, &psnsSqrtRs[1]);
+
+    for (siSfrm = 2; siSfrm < N_SUB; siSfrm++)
+      psnsSqrtRs[siSfrm] = psnsSqrtRs[1];
+
+    for (siSfrm = 1; siSfrm < N_SUB; siSfrm++)
+    {
+      for (i = 0; i < NP; i++)
+      {
+        ppswSNWCoefAs[siSfrm][i] = pswNewFrmSNWCoef[i];
+        ppswSynthAs[siSfrm][i] = pswNewFrmAs[i];
+      }
+    }
+  }
+
+  *pswSoftInterp = swSi;
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: iir_d
+ *
+ *    PURPOSE:  Performs one second order iir section using double-precision.
+ *              feedback,single precision xn and filter coefficients
+ *
+ *    INPUTS:
+ *
+ *      pswCoef[0:4]   An array of filter coefficients.
+ *
+ *      pswIn[0:159]   An array of input samples to be filtered, filtered
+ *                     output samples written to the same array.
+ *
+ *      pswXstate[0:1] An array containing x-state memory.
+ *
+ *      pswYstate[0:3] An array containing y-state memory.
+ *
+ *      npts           Number of samples to filter (must be even).
+ *
+ *      shifts         number of shifts to be made on output y(n) before
+ *                     storing to y(n) states.
+ *
+ *      swPreFirDownSh number of shifts apply to signal before the FIR.
+ *
+ *      swFinalUpShift number of shifts apply to signal before outputting.
+ *
+ *    OUTPUTS:
+ *
+ *       pswIn[0:159]  Output array containing the filtered input samples.
+ *
+ *    RETURN:
+ *
+ *       none.
+ *
+ *    DESCRIPTION:
+ *
+ *       Transfer function implemented:
+ *         (b0 + b1*z-1 + b2*z-2)/(a0 - a1*z-1 - a2*z-2+
+ *       data structure:
+ *         Coeff array order:  b2,b1,b0,a2,a1
+ *         Xstate array order: x(n-2),x(n-1)
+ *         Ystate array order: y(n-2)MSB,y(n-2)LSB,y(n-1)MSB,y(n-1)LSB
+ *
+ *       There is no elaborate discussion of the filter, since it is
+ *       trivial.
+ *
+ *       The filter's cutoff frequency is 120 Hz.
+ *
+ *    REFERENCE:  Sub-clause 4.1.1 GSM Recommendation 06.20
+ *
+ *    KEYWORDS: highpass filter, hp, HP, filter
+ *
+ *************************************************************************/
+
+void   iir_d(Shortword pswCoeff[], Shortword pswIn[], Shortword pswXstate[],
+                    Shortword pswYstate[], int npts, int shifts,
+                    Shortword swPreFirDownSh, Shortword swFinalUpShift)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  int    loop_cnt;
+  Longword L_sumA,
+         L_sumB;
+  Shortword swTemp,
+         pswYstate_0,
+         pswYstate_1,
+         pswYstate_2,
+         pswYstate_3,
+         pswXstate_0,
+         pswXstate_1,
+         swx0,
+         swx1;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* initialize the temporary state variables */
+  /*------------------------------------------*/
+
+  pswYstate_0 = pswYstate[0];
+  pswYstate_1 = pswYstate[1];
+  pswYstate_2 = pswYstate[2];
+  pswYstate_3 = pswYstate[3];
+
+  pswXstate_0 = pswXstate[0];
+  pswXstate_1 = pswXstate[1];
+
+  for (loop_cnt = 0; loop_cnt < npts; loop_cnt += 2)
+  {
+
+    swx0 = shr(pswIn[loop_cnt], swPreFirDownSh);
+    swx1 = shr(pswIn[loop_cnt + 1], swPreFirDownSh);
+
+    L_sumB = L_mult(pswYstate_1, pswCoeff[3]);
+    L_sumB = L_mac(L_sumB, pswYstate_3, pswCoeff[4]);
+    L_sumB = L_shr(L_sumB, 14);
+    L_sumB = L_mac(L_sumB, pswYstate_0, pswCoeff[3]);
+    L_sumB = L_mac(L_sumB, pswYstate_2, pswCoeff[4]);
+
+
+    L_sumA = L_mac(L_sumB, pswCoeff[0], pswXstate_0);
+    L_sumA = L_mac(L_sumA, pswCoeff[1], pswXstate_1);
+    L_sumA = L_mac(L_sumA, pswCoeff[2], swx0);
+
+    L_sumA = L_shl(L_sumA, shifts);
+
+    pswXstate_0 = swx0;                /* Update X state x(n-1) <- x(n) */
+
+    /* Update double precision Y state temporary variables */
+    /*-----------------------------------------------------*/
+
+    pswYstate_0 = extract_h(L_sumA);
+    swTemp = extract_l(L_sumA);
+    swTemp = shr(swTemp, 2);
+    pswYstate_1 = 0x3fff & swTemp;
+
+    /* Round, store output sample and increment to next input sample */
+    /*---------------------------------------------------------------*/
+
+    pswIn[loop_cnt] = round(L_shl(L_sumA, swFinalUpShift));
+
+    L_sumB = L_mult(pswYstate_3, pswCoeff[3]);
+    L_sumB = L_mac(L_sumB, pswYstate_1, pswCoeff[4]);
+    L_sumB = L_shr(L_sumB, 14);
+    L_sumB = L_mac(L_sumB, pswYstate_2, pswCoeff[3]);
+    L_sumB = L_mac(L_sumB, pswYstate_0, pswCoeff[4]);
+
+
+    L_sumA = L_mac(L_sumB, pswCoeff[0], pswXstate_1);
+    L_sumA = L_mac(L_sumA, pswCoeff[1], pswXstate_0);
+    L_sumA = L_mac(L_sumA, pswCoeff[2], swx1);
+
+    L_sumA = L_shl(L_sumA, shifts);
+
+    pswXstate_1 = swx1;                /* Update X state x(n-1) <- x(n) */
+
+    /* Update double precision Y state temporary variables */
+    /*-----------------------------------------------------*/
+
+    pswYstate_2 = extract_h(L_sumA);
+
+    swTemp = extract_l(L_sumA);
+    swTemp = shr(swTemp, 2);
+    pswYstate_3 = 0x3fff & swTemp;
+
+    /* Round, store output sample and increment to next input sample */
+    /*---------------------------------------------------------------*/
+
+    pswIn[loop_cnt + 1] = round(L_shl(L_sumA, swFinalUpShift));
+
+  }
+
+  /* update the states for the next frame */
+  /*--------------------------------------*/
+
+  pswYstate[0] = pswYstate_0;
+  pswYstate[1] = pswYstate_1;
+  pswYstate[2] = pswYstate_2;
+  pswYstate[3] = pswYstate_3;
+
+  pswXstate[0] = pswXstate_0;
+  pswXstate[1] = pswXstate_1;
+
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: initPBarVBarFullL
+ *
+ *    PURPOSE:  Given the Longword normalized correlation sequence, function
+ *              initPBarVBarL initializes the Longword initial condition
+ *              arrays pL_PBarFull and pL_VBarFull for a full 10-th order LPC
+ *              filter. It also shifts down the pL_VBarFull and pL_PBarFull
+ *              arrays by a global constant RSHIFT bits. The pL_PBarFull and
+ *              pL_VBarFull arrays are used to set the initial Shortword
+ *              P and V conditions which are used in the actual search of the
+ *              Rc prequantizer and the Rc quantizer.
+ *
+ *              This is an implementation of equations 4.14 and
+ *              4.15.
+ *
+ *    INPUTS:
+ *
+ *        pL_CorrelSeq[0:NP]
+ *                     A Longword normalized autocorrelation array computed
+ *                     from unquantized reflection coefficients.
+ *
+ *       RSHIFT       The number of right shifts to be applied to the
+ *                     input correlations prior to initializing the elements
+ *                     of pL_PBarFull and pL_VBarFull output arrays. RSHIFT
+ *                     is a global constant.
+ *
+ *    OUTPUTS:
+ *
+ *        pL_PBarFull[0:NP-1]
+ *                     A Longword output array containing the P initial
+ *                     conditions for the full 10-th order LPC filter.
+ *                     The address of the 0-th element of  pL_PBarFull
+ *                     is passed in when function initPBarVBarFullL is
+ *                     called.
+ *
+ *        pL_VBarFull[-NP+1:NP-1]
+ *                     A Longword output array containing the V initial
+ *                     conditions for the full 10-th order LPC filter.
+ *                     The address of the 0-th element of pL_VBarFull is
+ *                     passed in when function initPBarVBarFullL is called.
+ *    RETURN:
+ *        none.
+ *
+ *    REFERENCE:  Sub-clause 4.1.4.1 GSM Recommendation 06.20
+ *
+ *************************************************************************/
+
+void   initPBarFullVBarFullL(Longword pL_CorrelSeq[],
+                                    Longword pL_PBarFull[],
+                                    Longword pL_VBarFull[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  int    i,
+         bound;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Initialize the AFLAT recursion PBarFull and VBarFull 32 bit arrays */
+  /* for a 10-th order LPC filter.                                      */
+  /*--------------------------------------------------------------------*/
+
+  bound = NP - 1;
+
+  for (i = 0; i <= bound; i++)
+  {
+    pL_PBarFull[i] = L_shr(pL_CorrelSeq[i], RSHIFT);
+  }
+
+  for (i = -bound; i < 0; i++)
+  {
+    pL_VBarFull[i] = pL_PBarFull[-i - 1];
+  }
+
+  for (i = 0; i < bound; i++)
+  {
+    pL_VBarFull[i] = pL_PBarFull[i + 1];
+  }
+
+  pL_VBarFull[bound] = L_shr(pL_CorrelSeq[bound + 1], RSHIFT);
+
+}
+
+/***************************************************************************
+ *
+ *    FUNCTION NAME: initPBarVBarL
+ *
+ *    PURPOSE:  Given the Longword pL_PBarFull array,
+ *              function initPBarVBarL initializes the Shortword initial
+ *              condition arrays pswPBar and pswVBar for a 3-rd order LPC
+ *              filter, since the order of the 1st Rc-VQ segment is 3.
+ *              The pswPBar and pswVBar arrays are a Shortword subset
+ *              of the initial condition array pL_PBarFull.
+ *              pswPBar and pswVBar are the initial conditions for the AFLAT
+ *              recursion at a given segment. The AFLAT recursion is used
+ *              to evaluate the residual error due to an Rc vector selected
+ *              from a prequantizer or a quantizer.
+ *
+ *              This is an implementation of equation 4.18 and 4.19.
+ *
+ *    INPUTS:
+ *
+ *        pL_PBarFull[0:NP-1]
+ *                     A Longword input array containing the P initial
+ *                     conditions for the full 10-th order LPC filter.
+ *                     The address of the 0-th element of  pL_PBarFull
+ *                     is passed in when function initPBarVBarL is called.
+ *
+ *    OUTPUTS:
+ *
+ *        pswPBar[0:NP_AFLAT-1]
+ *                     The output Shortword array containing the P initial
+ *                     conditions for the P-V AFLAT recursion, set here
+ *                     for the Rc-VQ search at the 1st Rc-VQ segment.
+ *                     The address of the 0-th element of pswPBar is
+ *                     passed in when function initPBarVBarL is called.
+ *
+ *        pswVBar[-NP_AFLAT+1:NP_AFLAT-1]
+ *                     The output Shortword array containing the V initial
+ *                     conditions for the P-V AFLAT recursion, set here
+ *                     for the Rc-VQ search at the 1st Rc-VQ segment.
+ *                     The address of the 0-th element of pswVBar is
+ *                     passed in when function initPBarVBarL is called.
+ *
+ *    RETURN:
+ *
+ *        none.
+ *
+ *    REFERENCE:  Sub-clause 4.1.4.1 GSM Recommendation 06.20
+ *
+ *
+ *************************************************************************/
+
+void   initPBarVBarL(Longword pL_PBarFull[],
+                            Shortword pswPBar[],
+                            Shortword pswVBar[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  int    bound,
+         i;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Initialize the AFLAT recursion P and V 16 bit arrays for a 3-rd    */
+  /* order LPC filter corresponding to the 1-st reflection coefficient  */
+  /* VQ segment. The PBar and VBar arrays store the initial conditions  */
+  /* for the evaluating the residual error due to Rc vectors being      */
+  /* evaluated from the Rc-VQ codebook at the 1-st Rc-VQ segment.       */
+  /*--------------------------------------------------------------------*/
+  bound = 2;
+
+  for (i = 0; i <= bound; i++)
+  {
+    pswPBar[i] = round(pL_PBarFull[i]);
+  }
+  for (i = -bound; i < 0; i++)
+  {
+    pswVBar[i] = pswPBar[-i - 1];
+  }
+  for (i = 0; i < bound; i++)
+  {
+    pswVBar[i] = pswPBar[i + 1];
+  }
+  pswVBar[bound] = round(pL_PBarFull[bound + 1]);
+
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: maxCCOverGWithSign
+ *
+ *   PURPOSE:
+ *
+ *     Finds lag which maximizes C^2/G ( C is allowed to be negative ).
+ *
+ *   INPUTS:
+ *
+ *     pswCIn[0:swNum-1]
+ *
+ *                     Array of C values
+ *
+ *     pswGIn[0:swNum-1]
+ *
+ *                     Array of G values
+ *
+ *     pswCCmax
+ *
+ *                     Initial value of CCmax
+ *
+ *     pswGmax
+ *
+ *                     Initial value of Gmax
+ *
+ *     swNum
+ *
+ *                     Number of lags to be searched
+ *
+ *   OUTPUTS:
+ *
+ *     pswCCmax
+ *
+ *                     Value of CCmax after search
+ *
+ *     pswGmax
+ *
+ *                     Value of Gmax after search
+ *
+ *   RETURN VALUE:
+ *
+ *     maxCCGIndex - index for max C^2/G, defaults to zero if all G <= 0
+ *
+ *   DESCRIPTION:
+ *
+ *     This routine is called from bestDelta().  The routine is a simple
+ *     find the best in a list search.
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.3 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS: LTP correlation peak
+ *
+ *************************************************************************/
+
+Shortword maxCCOverGWithSign(Shortword pswCIn[],
+                                    Shortword pswGIn[],
+                                    Shortword *pswCCMax,
+                                    Shortword *pswGMax,
+                                    Shortword swNum)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword swCC,
+         i,
+         maxCCGIndex,
+         swCCMax,
+         swGMax;
+  Longword L_Temp;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* initialize max c^2/g to be the initial trajectory */
+  /*---------------------------------------------------*/
+
+  maxCCGIndex = 0;
+  swGMax = pswGIn[0];
+
+  if (pswCIn[0] < 0)
+    swCCMax = negate(mult_r(pswCIn[0], pswCIn[0]));
+  else
+    swCCMax = mult_r(pswCIn[0], pswCIn[0]);
+
+  for (i = 1; i < swNum; i++)
+  {
+
+    /* Imperfect interpolation can result in negative energies. */
+    /* Check for this                                             */
+    /*----------------------------------------------------------*/
+
+    if (pswGIn[i] > 0)
+    {
+
+      swCC = mult_r(pswCIn[i], pswCIn[i]);
+
+      if (pswCIn[i] < 0)
+        swCC = negate(swCC);
+
+      L_Temp = L_mult(swCC, swGMax);
+      L_Temp = L_msu(L_Temp, pswGIn[i], swCCMax);
+
+      /* Check if C^2*Gmax - G*Cmax^2 > 0 */
+      /* -------------------------------- */
+
+      if (L_Temp > 0)
+      {
+        swGMax = pswGIn[i];
+        swCCMax = swCC;
+        maxCCGIndex = i;
+      }
+    }
+  }
+  *pswGMax = swGMax;
+  *pswCCMax = swCCMax;
+
+  return (maxCCGIndex);
+}                                      /* end of maxCCOverGWithSign */
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: openLoopLagSearch
+ *
+ *   PURPOSE:
+ *
+ *     Determines voicing level for the frame.  If voiced, obtains list of
+ *     lags to be searched in closed-loop lag search; and value of smoothed
+ *     pitch and coefficient for harmonic-noise-weighting.
+ *
+ *   INPUTS:
+ *
+ *     pswWSpeech[-145:159] ( [-LSMAX:F_LEN-1] )
+ *
+ *                     W(z) filtered speech frame, with some history.
+ *
+ *     swPrevR0Index
+ *
+ *                     Index of R0 from the previous frame.
+ *
+ *     swCurrR0Index
+ *
+ *                     Index of R0 for the current frame.
+ *
+ *     psrLagTbl[0:255]
+ *
+ *                     Lag quantization table, in global ROM.
+ *
+ *     ppsrCGIntFilt[0:5][0:5] ( [tap][phase] )
+ *
+ *                     Interpolation smoothing filter for generating C(k)
+ *                     and G(k) terms, where k is fractional.  Global ROM.
+ *
+ *     swSP        
+ *                     speech flag, required for DTX mode
+ *
+ *   OUTPUTS:
+ *
+ *     psiUVCode
+ *
+ *                     (Pointer to) the coded voicing level.
+ *
+ *     pswLagList[0:?]
+ *
+ *                     Array of lags to use in the search of the adaptive
+ *                     codebook (long-term predictor).  Length determined
+ *                     by pswNumLagList[].
+ *
+ *     pswNumLagList[0:3] ( [0:N_SUB-1] )
+ *
+ *                     Array of number of lags to use in search of adaptive
+ *                     codebook (long-term predictor) for each subframe.
+ *
+ *     pswPitchBuf[0:3] ( [0:N_SUB-1] )
+ *
+ *                     Array of estimates of pitch, to be used in harmonic-
+ *                     noise-weighting.
+ *
+ *     pswHNWCoefBuf[0:3] ( [0:N_SUB-1] )
+ *
+ *                     Array of harmonic-noise-weighting coefficients.
+ *
+ *     psnsWSfrmEng[-4:3] ( [-N_SUB:N_SUB-1] )
+ *
+ *                     Array of energies of weighted speech (input speech
+ *                     sent through W(z) weighting filter), each stored as
+ *                     normalized fraction and shift count.  The zero index
+ *                     corresponds to the first subframe of the current
+ *                     frame, so there is some history represented.  The
+ *                     energies are used for scaling purposes only.
+ *
+ *     pswVadLags[4]
+ *
+ *                     An array of Shortwords containing the best open
+ *                     loop LTP lags for the four subframes.
+
+ *
+ *   DESCRIPTION:
+ *
+ *     Scaling is done on the input weighted speech, such that the C(k) and
+ *     G(k) terms will all be representable.  The amount of scaling is
+ *     determined by the maximum energy of any subframe of weighted speech
+ *     from the current frame or last frame.  These energies are maintained
+ *     in a buffer, and used for scaling when the excitation is determined
+ *     later in the analysis.
+ *
+ *     This function is the main calling program for the open loop lag
+ *     search.
+ *
+ *   REFERENCE:  Sub-clauses 4.1.8.1-4.1.8.4 of GSM Recommendation 06.20
+ *
+ *   Keywords: openlooplagsearch, openloop, lag, pitch
+ *
+ **************************************************************************/
+
+
+
+void   openLoopLagSearch(Shortword pswWSpeech[],
+                                Shortword swPrevR0Index,
+                                Shortword swCurrR0Index,
+                                Shortword *psiUVCode,
+                                Shortword pswLagList[],
+                                Shortword pswNumLagList[],
+                                Shortword pswPitchBuf[],
+                                Shortword pswHNWCoefBuf[],
+                                struct NormSw psnsWSfrmEng[],
+                                Shortword pswVadLags[],
+                                Shortword swSP)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Longword L_WSfrmEng,
+         L_G,
+         L_C,
+         L_Voicing;
+  Shortword swBestPG,
+         swCCMax,
+         swGMax,
+         swCCDivG;
+  Shortword swTotalCCDivG,
+         swCC,
+         swG,
+         swRG;
+  short  i,
+         j,
+         k,
+         siShift,
+         siIndex,
+         siTrajIndex,
+         siAnchorIndex;
+  short  siNumPeaks,
+         siNumTrajToDo,
+         siPeakIndex,
+         siFIndex;
+  short  siNumDelta,
+         siBIndex,
+         siBestTrajIndex = 0;
+  short  siLowestSoFar,
+         siLagsSoFar,
+         si1,
+         si2,
+         si3;
+  struct NormSw snsMax;
+
+  Shortword pswGFrame[G_FRAME_LEN];
+  Shortword *ppswGSfrm[N_SUB];
+  Shortword pswSfrmEng[N_SUB];
+  Shortword pswCFrame[C_FRAME_LEN];
+  Shortword *ppswCSfrm[N_SUB];
+  Shortword pswLIntBuf[N_SUB];
+  Shortword pswCCThresh[N_SUB];
+  Shortword pswScaledWSpeechBuffer[W_F_BUFF_LEN];
+  Shortword *pswScaledWSpeech;
+  Shortword ppswTrajLBuf[N_SUB * NUM_TRAJ_MAX][N_SUB];
+  Shortword ppswTrajCCBuf[N_SUB * NUM_TRAJ_MAX][N_SUB];
+  Shortword ppswTrajGBuf[N_SUB * NUM_TRAJ_MAX][N_SUB];
+  Shortword pswLPeaks[2 * LMAX / LMIN];
+  Shortword pswCPeaks[2 * LMAX / LMIN];
+  Shortword pswGPeaks[2 * LMAX / LMIN];
+  Shortword pswLArray[DELTA_LEVELS];
+
+  pswScaledWSpeech = pswScaledWSpeechBuffer + LSMAX;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Executable Code                              |
+ |_________________________________________________________________________|
+*/
+
+  /* Scale the weighted speech so that all correlations and energies */
+  /* will be less than 1.0 in magnitude.  The scale factor is        */
+  /* determined by the maximum energy of any subframe contained in   */
+  /* the weighted speech buffer                                      */
+  /*-----------------------------------------------------------------*/
+
+  /* Perform one frame of delay on the subframe energy array */
+  /*---------------------------------------------------------*/
+
+  for (i = 0; i < N_SUB; i++)
+    psnsWSfrmEng[i - N_SUB] = psnsWSfrmEng[i];
+
+  /* Calculate the subframe energies of the current weighted speech frame. */
+  /* Overflow protection is done based on the energy in the LPC analysis  */
+  /* window (previous or current) which is closest to the subframe.       */
+  /*----------------------------------------------------------------------*/
+
+  psnsWSfrmEng[0].sh = g_corr1s(&pswWSpeech[0],
+                                r0BasedEnergyShft(swPrevR0Index),
+                                &L_WSfrmEng);
+  psnsWSfrmEng[0].man = round(L_WSfrmEng);
+
+  psnsWSfrmEng[1].sh = g_corr1s(&pswWSpeech[S_LEN],
+                                r0BasedEnergyShft(swCurrR0Index),
+                                &L_WSfrmEng);
+  psnsWSfrmEng[1].man = round(L_WSfrmEng);
+
+  psnsWSfrmEng[2].sh = g_corr1s(&pswWSpeech[2 * S_LEN],
+                                r0BasedEnergyShft(swCurrR0Index),
+                                &L_WSfrmEng);
+  psnsWSfrmEng[2].man = round(L_WSfrmEng);
+
+  psnsWSfrmEng[3].sh = g_corr1s(&pswWSpeech[3 * S_LEN],
+                                r0BasedEnergyShft(swCurrR0Index),
+                                &L_WSfrmEng);
+  psnsWSfrmEng[3].man = round(L_WSfrmEng);
+
+  /* Find the maximum weighted speech subframe energy from all values */
+  /* in the array (the array includes the previous frame's subframes, */
+  /* and the current frame's subframes)                               */
+  /*------------------------------------------------------------------*/
+
+  snsMax.man = 0;
+  snsMax.sh = 0;
+  for (i = -N_SUB; i < N_SUB; i++)
+  {
+
+    if (psnsWSfrmEng[i].man > 0)
+    {
+
+      if (snsMax.man == 0)
+        snsMax = psnsWSfrmEng[i];
+
+      if (sub(psnsWSfrmEng[i].sh, snsMax.sh) < 0)
+        snsMax = psnsWSfrmEng[i];
+
+      if (sub(psnsWSfrmEng[i].sh, snsMax.sh) == 0 &&
+          sub(psnsWSfrmEng[i].man, snsMax.man) > 0)
+        snsMax = psnsWSfrmEng[i];
+    }
+  }
+
+  /* Now scale speech up or down, such that the maximum subframe */
+  /* energy value will be in range [0.125, 0.25).  This gives a  */
+  /* little room for other maxima, and interpolation filtering   */
+  /*-------------------------------------------------------------*/
+
+  siShift = sub(shr(snsMax.sh, 1), 1);
+
+  for (i = 0; i < W_F_BUFF_LEN; i++)
+    pswScaledWSpeech[i - LSMAX] = shl(pswWSpeech[i - LSMAX], siShift);
+
+  /* Calculate the G(k) (k an integer) terms for all subframes.  (A note */
+  /* on the organization of the G buffer: G(k) for a given subframe is   */
+  /* the energy in the weighted speech sequence of length S_LEN (40)     */
+  /* which begins k back from the beginning of the given subframe-- that */
+  /* is, it begins at a lag of k.  These sequences overlap from one      */
+  /* subframe to the next, so it is only necessary to compute and store  */
+  /* the unique energies.  The unique energies are computed and stored   */
+  /* in this buffer, and pointers are assigned for each subframe to make */
+  /* array indexing for each subframe easier.                            */
+  /* */
+  /* (Terms in the G buffer are in order of increasing k, so the energy  */
+  /* of the first sequence-- that is, the oldest sequence-- in the       */
+  /* weighted speech buffer appears at the end of the G buffer.          */
+  /* */
+  /* (The subframe pointers are assigned so that they point to the first */
+  /* k for their respective subframes, k = LSMIN.)                       */
+  /*---------------------------------------------------------------------*/
+
+  L_G = 0;
+  for (i = -LSMAX; i < -LSMAX + S_LEN; i++)
+    L_G = L_mac(L_G, pswScaledWSpeech[i], pswScaledWSpeech[i]);
+
+  pswGFrame[G_FRAME_LEN - 1] = extract_h(L_G);
+
+  for (i = -LSMAX; i < G_FRAME_LEN - LSMAX - 1; i++)
+  {
+
+    L_G = L_msu(L_G, pswScaledWSpeech[i], pswScaledWSpeech[i]);
+    L_G = L_mac(L_G, pswScaledWSpeech[i + S_LEN],
+                pswScaledWSpeech[i + S_LEN]);
+    pswGFrame[G_FRAME_LEN - LSMAX - 2 - i] = extract_h(L_G);
+  }
+
+  ppswGSfrm[0] = pswGFrame + 3 * S_LEN;
+  ppswGSfrm[1] = pswGFrame + 2 * S_LEN;
+  ppswGSfrm[2] = pswGFrame + S_LEN;
+  ppswGSfrm[3] = pswGFrame;
+
+  /* Copy the G(k) terms which also happen to be the subframe energies; */
+  /* calculate the 4th subframe energy, which is not a G(k)             */
+  /*--------------------------------------------------------------------*/
+
+  pswSfrmEng[0] = pswGFrame[G_FRAME_LEN - 1 - LSMAX];
+  pswSfrmEng[1] = pswGFrame[G_FRAME_LEN - 1 - LSMAX - S_LEN];
+  pswSfrmEng[2] = pswGFrame[G_FRAME_LEN - 1 - LSMAX - 2 * S_LEN];
+
+  L_WSfrmEng = 0;
+  for (i = F_LEN - S_LEN; i < F_LEN; i++)
+    L_WSfrmEng = L_mac(L_WSfrmEng, pswScaledWSpeech[i], pswScaledWSpeech[i]);
+
+  pswSfrmEng[3] = extract_h(L_WSfrmEng);
+
+  /* Calculate the C(k) (k an integer) terms for all subframes. */
+  /* (The C(k) terms are all unique, so there is no overlapping */
+  /* as in the G buffer.)                                       */
+  /*------------------------------------------------------------*/
+
+  for (i = 0; i < N_SUB; i++)
+  {
+
+    for (j = LSMIN; j <= LSMAX; j++)
+    {
+
+      L_C = 0;
+      for (k = 0; k < S_LEN; k++)
+      {
+
+        L_C = L_mac(L_C, pswScaledWSpeech[i * S_LEN + k],
+                    pswScaledWSpeech[i * S_LEN - j + k]);
+      }
+
+      pswCFrame[i * CG_TERMS + j - LSMIN] = extract_h(L_C);
+    }
+  }
+
+  ppswCSfrm[0] = pswCFrame;
+  ppswCSfrm[1] = pswCFrame + CG_TERMS;
+  ppswCSfrm[2] = pswCFrame + 2 * CG_TERMS;
+  ppswCSfrm[3] = pswCFrame + 3 * CG_TERMS;
+
+  /* For each subframe: find the max C(k)*C(k)/G(k) where C(k) > 0 and */
+  /* k is integer; save the corresponding k; calculate the             */
+  /* threshold against which other peaks in the interpolated CC/G      */
+  /* sequence will be checked.  Meanwhile, accumulate max CC/G over    */
+  /* the frame for the voiced/unvoiced determination.                  */
+  /*-------------------------------------------------------------------*/
+
+  swBestPG = 0;
+  for (i = 0; i < N_SUB; i++)
+  {
+
+    /* Find max CC/G (C > 0), store corresponding k */
+    /*----------------------------------------------*/
+
+    swCCMax = 0;
+    swGMax = 0x003f;
+    siIndex = fnBest_CG(&ppswCSfrm[i][LMIN - LSMIN],
+                        &ppswGSfrm[i][LMIN - LSMIN],
+                        &swCCMax, &swGMax,
+                        LMAX - LMIN + 1);
+
+    if (siIndex == -1)
+    {
+      pswLIntBuf[i] = 0;
+      pswVadLags[i] = LMIN;            /* store lag value for VAD algorithm */
+    }
+    else
+    {
+      pswLIntBuf[i] = add(LMIN, (Shortword) siIndex);
+      pswVadLags[i] = pswLIntBuf[i];   /* store lag value for VAD algorithm */
+    }
+
+    if (pswLIntBuf[i] > 0)
+    {
+
+      /* C > 0 was found: accumulate CC/G, get threshold */
+      /*-------------------------------------------------*/
+
+      if (sub(swCCMax, swGMax) < 0)
+        swCCDivG = divide_s(swCCMax, swGMax);
+      else
+        swCCDivG = SW_MAX;
+
+      swBestPG = add(swCCDivG, swBestPG);
+
+      pswCCThresh[i] = getCCThreshold(pswSfrmEng[i], swCCMax, swGMax);
+    }
+    else
+      pswCCThresh[i] = 0;
+  }
+
+  /* Make voiced/unvoiced decision */
+  /*-------------------------------*/
+
+  L_Voicing = 0;
+  for (i = 0; i < N_SUB; i++)
+    L_Voicing = L_mac(L_Voicing, pswSfrmEng[i], UV_SCALE0);
+
+  L_Voicing = L_add(L_Voicing, L_deposit_h(swBestPG));
+
+  if ( (L_Voicing <= 0) || (swSP == 0) )
+  {
+
+    /* Unvoiced: set return values to zero */
+    /*-------------------------------------*/
+
+    for (i = 0; i < N_SUB; i++)
+    {
+
+      pswNumLagList[i] = 0;
+      pswLagList[i] = 0;
+      pswPitchBuf[i] = 0;
+      pswHNWCoefBuf[i] = 0;
+    }
+
+    *psiUVCode = 0;
+  }
+  else
+  {
+
+    /* Voiced: get best delta-codeable lag trajectory; find pitch and */
+    /* harmonic-noise-weighting coefficients for each subframe        */
+    /*----------------------------------------------------------------*/
+
+    siTrajIndex = 0;
+    swBestPG = SW_MIN;
+    for (siAnchorIndex = 0; siAnchorIndex < N_SUB; siAnchorIndex++)
+    {
+
+      /* Call pitchLags: for the current subframe, find peaks in the */
+      /* C(k)**2/G(k) (k fractional) function which exceed the       */
+      /* threshold set by the maximum C(k)**2/G(k) (k integer)       */
+      /* (also get the smoothed pitch and harmonic-noise-weighting   */
+      /* coefficient).                                               */
+      /* */
+      /* If there is no C(k) > 0 (k integer), set the smoothed pitch */
+      /* to its minimum value and set the harmonic-noise-weighting   */
+      /* coefficient to zero.                                        */
+      /*-------------------------------------------------------------*/
+
+      if (pswLIntBuf[siAnchorIndex] != 0)
+      {
+
+        pitchLags(pswLIntBuf[siAnchorIndex],
+                  ppswCSfrm[siAnchorIndex],
+                  ppswGSfrm[siAnchorIndex],
+                  pswCCThresh[siAnchorIndex],
+                  pswLPeaks,
+                  pswCPeaks,
+                  pswGPeaks,
+                  &siNumPeaks,
+                  &pswPitchBuf[siAnchorIndex],
+                  &pswHNWCoefBuf[siAnchorIndex]);
+
+        siPeakIndex = 0;
+      }
+      else
+      {
+
+        /* No C(k) > 0 (k integer): set pitch to min, coef to zero, */
+        /* go to next subframe.                                     */
+        /*----------------------------------------------------------*/
+
+        pswPitchBuf[siAnchorIndex] = LMIN_FR;
+        pswHNWCoefBuf[siAnchorIndex] = 0;
+        continue;
+      }
+
+      /* It is possible that by interpolating, the only positive */
+      /* C(k) was made negative.  Check for this here            */
+      /*---------------------------------------------------------*/
+
+      if (siNumPeaks == 0)
+      {
+
+        pswPitchBuf[siAnchorIndex] = LMIN_FR;
+        pswHNWCoefBuf[siAnchorIndex] = 0;
+        continue;
+      }
+
+      /* Peak(s) found in C**2/G function: find the best delta-codeable */
+      /* trajectory through each peak (unless that peak has already     */
+      /* paritcipated in a trajectory) up to a total of NUM_TRAJ_MAX    */
+      /* peaks.  After each trajectory is found, check to see if that   */
+      /* trajectory is the best one so far.                             */
+      /*----------------------------------------------------------------*/
+
+      if (siNumPeaks > NUM_TRAJ_MAX)
+        siNumTrajToDo = NUM_TRAJ_MAX;
+      else
+        siNumTrajToDo = siNumPeaks;
+
+      while (siNumTrajToDo)
+      {
+
+        /* Check if this peak has already participated in a trajectory. */
+        /* If so, skip it, decrement the number of trajectories yet to  */
+        /* be evaluated, and go on to the next best peak                */
+        /*--------------------------------------------------------------*/
+
+        si1 = 0;
+        for (i = 0; i < siTrajIndex; i++)
+        {
+
+          if (sub(pswLPeaks[siPeakIndex],
+                  ppswTrajLBuf[i][siAnchorIndex]) == 0)
+            si1 = 1;
+        }
+
+        if (si1)
+        {
+
+          siNumTrajToDo--;
+          if (siNumTrajToDo)
+          {
+
+            siPeakIndex++;
+            continue;
+          }
+          else
+            break;
+        }
+
+        /* The current peak is not in a previous trajectory: find */
+        /* the best trajectory through it.                        */
+        /* */
+        /* First, store the lag, C**2, and G for the peak in the  */
+        /* trajectory storage buffer                              */
+        /*--------------------------------------------------------*/
+
+        ppswTrajLBuf[siTrajIndex][siAnchorIndex] = pswLPeaks[siPeakIndex];
+        ppswTrajGBuf[siTrajIndex][siAnchorIndex] = pswGPeaks[siPeakIndex];
+        ppswTrajCCBuf[siTrajIndex][siAnchorIndex] =
+                mult_r(pswCPeaks[siPeakIndex], pswCPeaks[siPeakIndex]);
+
+        /* Complete the part of the trajectory that extends forward */
+        /* from the anchor subframe                                 */
+        /*----------------------------------------------------------*/
+
+        for (siFIndex = siAnchorIndex + 1; siFIndex < N_SUB; siFIndex++)
+        {
+
+          /* Get array of lags which are delta-codeable */
+          /* */
+          /* First, get code for largest lag in array   */
+          /* (limit it)                                 */
+          /*--------------------------------------------*/
+
+          quantLag(ppswTrajLBuf[siTrajIndex][siFIndex - 1],
+                   &si1);
+          si2 = add(si1, (DELTA_LEVELS / 2 - 1) - (NUM_CLOSED - 1));
+          if (sub(si2, (1 << L_BITS) - 1) > 0)
+            si2 = (1 << L_BITS) - 1;
+
+          /* Get code for smallest lag in array (limit it) */
+          /*-----------------------------------------------*/
+
+          si3 = sub(si1, (DELTA_LEVELS / 2) - (NUM_CLOSED - 1));
+          if (si3 < 0)
+            si3 = 0;
+
+          /* Generate array of lags */
+          /*------------------------*/
+
+          for (i = si3, j = 0; i <= si2; i++, j++)
+            pswLArray[j] = psrLagTbl[i];
+
+          siNumDelta = add(sub(si2, si3), 1);
+
+          /* Search array of delta-codeable lags for one which maximizes */
+          /* C**2/G                                                      */
+          /*-------------------------------------------------------------*/
+
+          bestDelta(pswLArray, ppswCSfrm[siFIndex], ppswGSfrm[siFIndex],
+                    siNumDelta, siFIndex,
+                    ppswTrajLBuf[siTrajIndex], ppswTrajCCBuf[siTrajIndex],
+                    ppswTrajGBuf[siTrajIndex]);
+        }
+
+        /* Complete the part of the trajectory that extends backward */
+        /* from the anchor subframe                                  */
+        /*-----------------------------------------------------------*/
+
+        for (siBIndex = siAnchorIndex - 1; siBIndex >= 0; siBIndex--)
+        {
+
+          /* Get array of lags which are delta-codeable */
+          /* */
+          /* First, get code for largest lag in array   */
+          /* (limit it)                                 */
+          /*--------------------------------------------*/
+
+          quantLag(ppswTrajLBuf[siTrajIndex][siBIndex + 1],
+                   &si1);
+          si2 = add(si1, (DELTA_LEVELS / 2) - (NUM_CLOSED - 1));
+          if (sub(si2, (1 << L_BITS) - 1) > 0)
+            si2 = (1 << L_BITS) - 1;
+
+          /* Get code for smallest lag in array (limit it) */
+          /*-----------------------------------------------*/
+
+          si3 = sub(si1, (DELTA_LEVELS / 2 - 1) - (NUM_CLOSED - 1));
+          if (si3 < 0)
+            si3 = 0;
+
+          /* Generate array of lags */
+          /*------------------------*/
+
+          for (i = si3, j = 0; i <= si2; i++, j++)
+            pswLArray[j] = psrLagTbl[i];
+
+          siNumDelta = add(sub(si2, si3), 1);
+
+          /* Search array of delta-codeable lags for one which maximizes */
+          /* C**2/G                                                      */
+          /*-------------------------------------------------------------*/
+
+          bestDelta(pswLArray, ppswCSfrm[siBIndex], ppswGSfrm[siBIndex],
+                    siNumDelta, siBIndex,
+                    ppswTrajLBuf[siTrajIndex], ppswTrajCCBuf[siTrajIndex],
+                    ppswTrajGBuf[siTrajIndex]);
+        }
+
+        /* This trajectory done: check total C**2/G for this trajectory */
+        /* against current best trajectory                              */
+        /* */
+        /* Get total C**2/G for this trajectory                         */
+        /*--------------------------------------------------------------*/
+
+        swTotalCCDivG = 0;
+        for (i = 0; i < N_SUB; i++)
+        {
+
+          swCC = ppswTrajCCBuf[siTrajIndex][i];
+          swG = ppswTrajGBuf[siTrajIndex][i];
+
+          if (swG <= 0)
+          {
+
+            /* Negative G (imperfect interpolation): do not include in */
+            /* total                                                   */
+            /*---------------------------------------------------------*/
+
+            swCCDivG = 0;
+          }
+          else if (sub(abs_s(swCC), swG) > 0)
+          {
+
+            /* C**2/G > 0: limit quotient, add to total */
+            /*------------------------------------------*/
+
+            if (swCC > 0)
+              swCCDivG = SW_MAX;
+            else
+              swCCDivG = SW_MIN;
+
+            swTotalCCDivG = add(swTotalCCDivG, swCCDivG);
+          }
+          else
+          {
+
+            /* accumulate C**2/G */
+            /*-------------------*/
+
+            if (swCC < 0)
+            {
+
+              swCCDivG = divide_s(negate(swCC), swG);
+              swTotalCCDivG = sub(swTotalCCDivG, swCCDivG);
+            }
+            else
+            {
+
+              swCCDivG = divide_s(swCC, swG);
+              swTotalCCDivG = add(swTotalCCDivG, swCCDivG);
+            }
+          }
+        }
+
+        /* Compare this trajectory with current best, update if better */
+        /*-------------------------------------------------------------*/
+
+        if (sub(swTotalCCDivG, swBestPG) > 0)
+        {
+
+          swBestPG = swTotalCCDivG;
+          siBestTrajIndex = siTrajIndex;
+        }
+
+        /* Update trajectory index, peak index, decrement the number */
+        /* of trajectories left to do.                               */
+        /*-----------------------------------------------------------*/
+
+        siTrajIndex++;
+        siPeakIndex++;
+        siNumTrajToDo--;
+      }
+    }
+
+    if (siTrajIndex == 0)
+    {
+
+      /* No trajectories searched despite voiced designation: change */
+      /* designation to unvoiced.                                    */
+      /*-------------------------------------------------------------*/
+
+      for (i = 0; i < N_SUB; i++)
+      {
+
+        pswNumLagList[i] = 0;
+        pswLagList[i] = 0;
+        pswPitchBuf[i] = 0;
+        pswHNWCoefBuf[i] = 0;
+      }
+
+      *psiUVCode = 0;
+    }
+    else
+    {
+
+      /* Best trajectory determined: get voicing level, generate the */
+      /* constrained list of lags to search in the adaptive codebook */
+      /* for each subframe                                           */
+      /* */
+      /* First, get voicing level                                    */
+      /*-------------------------------------------------------------*/
+
+      *psiUVCode = 3;
+      siLowestSoFar = 2;
+      for (i = 0; i < N_SUB; i++)
+      {
+
+        /* Check this subframe against highest voicing threshold */
+        /*-------------------------------------------------------*/
+
+        swCC = ppswTrajCCBuf[siBestTrajIndex][i];
+        swG = ppswTrajGBuf[siBestTrajIndex][i];
+
+        swRG = mult_r(swG, pswSfrmEng[i]);
+        L_Voicing = L_deposit_h(swCC);
+        L_Voicing = L_mac(L_Voicing, swRG, UV_SCALE2);
+
+        if (L_Voicing < 0)
+        {
+
+          /* Voicing for this subframe failed to meet 2/3 threshold:  */
+          /* therefore, voicing level for entire frame can only be as */
+          /* high as 2                                                */
+          /*----------------------------------------------------------*/
+
+          *psiUVCode = siLowestSoFar;
+
+          L_Voicing = L_deposit_h(swCC);
+          L_Voicing = L_mac(L_Voicing, swRG, UV_SCALE1);
+
+          if (L_Voicing < 0)
+          {
+
+            /* Voicing for this subframe failed to meet 1/2 threshold: */
+            /* therefore, voicing level for entire frame can only be   */
+            /* as high as 1                                            */
+            /*---------------------------------------------------------*/
+
+            *psiUVCode = siLowestSoFar = 1;
+          }
+        }
+      }
+
+      /* Generate list of lags to be searched in closed-loop */
+      /*-----------------------------------------------------*/
+
+      siLagsSoFar = 0;
+      for (i = 0; i < N_SUB; i++)
+      {
+
+        quantLag(ppswTrajLBuf[siBestTrajIndex][i], &si1);
+
+        si2 = add(si1, NUM_CLOSED / 2);
+        if (sub(si2, (1 << L_BITS) - 1) > 0)
+          si2 = (1 << L_BITS) - 1;
+
+        si3 = sub(si1, NUM_CLOSED / 2);
+        if (si3 < 0)
+          si3 = 0;
+
+        pswNumLagList[i] = add(sub(si2, si3), 1);
+
+        for (j = siLagsSoFar; j < siLagsSoFar + pswNumLagList[i]; j++)
+          pswLagList[j] = psrLagTbl[si3++];
+
+        siLagsSoFar += pswNumLagList[i];
+      }
+    }
+  }
+}                                      /* end of openLoopLagSearch */
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: pitchLags
+ *
+ *   PURPOSE:
+ *
+ *     Locates peaks in the interpolated C(k)*C(k)/G(k) sequence for a
+ *     subframe which exceed a given threshold. Also determines the
+ *     fundamental pitch, and a harmonic-noise-weighting coefficient.
+ *
+ *   INPUTS:
+ *
+ *     swBestIntLag
+ *
+ *                     The integer lag for which CC/G is maximum.
+ *
+ *     pswIntCs[0:127]
+ *
+ *                     The C(k) sequence for the subframe, with k an integer.
+ *
+ *     pswIntGs[0:127]
+ *
+ *                     The G(k) sequence for the subframe, with k an integer.
+ *
+ *     swCCThreshold
+ *
+ *                     The CC/G threshold which peaks must exceed (G is
+ *                     understood to be 0.5).
+ *
+ *     psrLagTbl[0:255]
+ *
+ *                     The lag quantization table.
+ *
+ *
+ *   OUTPUTS:
+ *
+ *     pswLPeaksSorted[0:10(max)]
+ *
+ *                     List of fractional lags where CC/G peaks, highest
+ *                     peak first.
+ *
+ *     pswCPeaksSorted[0:10(max)]
+ *
+ *                     List of C's where CC/G peaks.
+ *
+ *     pswGPeaksSorted[0:10(max)]
+ *
+ *                     List of G's where CC/G peaks.
+ *
+ *     psiNumSorted
+ *
+ *                     Number of peaks found.
+ *
+ *     pswPitch
+ *
+ *                     The fundamental pitch for current subframe.
+ *
+ *     pswHNWCoef
+ *
+ *                     The harmonic-noise-weighting coefficient for the
+ *                     current subframe.
+ *
+ *   RETURN VALUE:
+ *
+ *     None
+ *
+ *   DESCRIPTION:
+ *
+ *
+ *   REFERENCE:  Sub-clauses 4.1.9, 4.1.8.2 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS: pitchLags, pitchlags, PITCH_LAGS
+ *
+ *************************************************************************/
+
+void   pitchLags(Shortword swBestIntLag,
+                        Shortword pswIntCs[],
+                        Shortword pswIntGs[],
+                        Shortword swCCThreshold,
+                        Shortword pswLPeaksSorted[],
+                        Shortword pswCPeaksSorted[],
+                        Shortword pswGPeaksSorted[],
+                        Shortword *psiNumSorted,
+                        Shortword *pswPitch,
+                        Shortword *pswHNWCoef)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword pswLBuf[2 * OS_FCTR - 1],
+         pswCBuf[2 * OS_FCTR - 1];
+  Shortword pswGBuf[2 * OS_FCTR - 1],
+         pswLPeaks[2 * LMAX / LMIN];
+  Shortword pswCPeaks[2 * LMAX / LMIN],
+         pswGPeaks[2 * LMAX / LMIN];
+  short  siLPeakIndex,
+         siCPeakIndex,
+         siGPeakIndex,
+         siPeakIndex;
+  short  siSortedIndex,
+         siLPeaksSortedInit,
+         swWorkingLag;
+  Shortword swSubMult,
+         swFullResPeak,
+         swCPitch,
+         swGPitch,
+         swMult;
+  Shortword swMultInt,
+         sw1,
+         sw2,
+         si1,
+         si2;
+  Longword L_1;
+  short  siNum,
+         siUpperBound,
+         siLowerBound,
+         siSMFIndex;
+  short  siNumPeaks,
+         siRepeat,
+         i,
+         j;
+
+  static ShortwordRom psrSubMultFactor[] = {0x0aab,     /* 1.0/12.0 */
+    0x071c,                            /* 1.0/18.0 */
+    0x0555,                            /* 1.0/24.0 */
+    0x0444,                            /* 1.0/30.0 */
+  0x038e};                             /* 1.0/36.0 */
+
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Get array of valid lags within one integer lag of the best open-loop */
+  /* integer lag; get the corresponding interpolated C and G arrays;      */
+  /* find the best among these; store the info corresponding to this peak */
+  /* in the interpolated CC/G sequence                                    */
+  /*----------------------------------------------------------------------*/
+
+  sw1 = shr(extract_l(L_mult(swBestIntLag, OS_FCTR)), 1);
+
+  siNum = CGInterpValid(sw1, pswIntCs, pswIntGs,
+                        pswLBuf, pswCBuf, pswGBuf);
+
+  sw1 = 0;
+  sw2 = 0x003f;
+  siPeakIndex = fnBest_CG(pswCBuf, pswGBuf, &sw1, &sw2, siNum);
+  if (siPeakIndex == -1)
+  {
+
+    /* It is possible, although rare, that the interpolated sequence */
+    /* will not have a peak where the original sequence did.         */
+    /* Indicate this on return                                       */
+    /*---------------------------------------------------------------*/
+
+    *psiNumSorted = 0;
+    return;
+  }
+
+  siLPeakIndex = 0;
+  siCPeakIndex = 0;
+  siGPeakIndex = 0;
+  siSortedIndex = 0;
+  pswCPeaks[siCPeakIndex] = pswCBuf[siPeakIndex];
+  siCPeakIndex = add(siCPeakIndex, 1);
+  pswLPeaks[siLPeakIndex] = pswLBuf[siPeakIndex];
+  siLPeakIndex = add(siLPeakIndex, 1);
+  pswGPeaks[siGPeakIndex] = pswGBuf[siPeakIndex];
+  siGPeakIndex = add(siGPeakIndex, 1);
+
+  /* Find all peaks at submultiples of the first peak */
+  /*--------------------------------------------------*/
+
+  siSMFIndex = 0;
+  swSubMult = mult_r(pswLPeaks[0], psrSubMultFactor[siSMFIndex++]);
+
+  while (sub(swSubMult, LMIN) >= 0 && siSMFIndex <= 5)
+  {
+
+    /* Check if there is peak in the integer CC/G sequence within */
+    /* PEAK_VICINITY of the submultiple                           */
+    /*------------------------------------------------------------*/
+
+    swFullResPeak = findPeak(swSubMult, pswIntCs, pswIntGs);
+
+    if (swFullResPeak)
+    {
+
+      /* Peak found at submultiple: interpolate to get C's and G's */
+      /* corresponding to valid lags within one of the new found   */
+      /* peak; get best C**2/G from these;  if it meets threshold, */
+      /* store the info corresponding to this peak                 */
+      /*-----------------------------------------------------------*/
+
+      siNum = CGInterpValid(swFullResPeak, pswIntCs, pswIntGs,
+                            pswLBuf, pswCBuf, pswGBuf);
+
+      sw1 = swCCThreshold;
+      sw2 = 0x4000;
+      siPeakIndex = fnBest_CG(pswCBuf, pswGBuf, &sw1, &sw2, siNum);
+      if (siPeakIndex != -1)
+      {
+
+        pswCPeaks[siCPeakIndex] = pswCBuf[siPeakIndex];
+        siCPeakIndex = add(siCPeakIndex, 1);
+        pswLPeaks[siLPeakIndex] = pswLBuf[siPeakIndex];
+        siLPeakIndex = add(siLPeakIndex, 1);
+        pswGPeaks[siGPeakIndex] = pswGBuf[siPeakIndex];
+        siGPeakIndex = add(siGPeakIndex, 1);
+
+      }
+    }
+
+
+    if (siSMFIndex < 5)
+    {
+
+      /* Get next submultiple */
+      /*----------------------*/
+      swSubMult = mult_r(pswLPeaks[0], psrSubMultFactor[siSMFIndex]);
+
+    }
+
+    siSMFIndex++;
+  }
+
+  /* Get pitch from fundamental peak: first, build array of fractional */
+  /* lags around which to search for peak.  Note that these lags are   */
+  /* NOT restricted to those in the lag table, but may take any value  */
+  /* in the range LMIN_FR to LMAX_FR                                   */
+  /*-------------------------------------------------------------------*/
+
+  siUpperBound = add(pswLPeaks[siLPeakIndex - 1], OS_FCTR);
+  siUpperBound = sub(siUpperBound, 1);
+  if (sub(siUpperBound, LMAX_FR) > 0)
+    siUpperBound = LMAX_FR;
+
+  siLowerBound = sub(pswLPeaks[siLPeakIndex - 1], OS_FCTR);
+  siLowerBound = add(siLowerBound, 1);
+  if (sub(siLowerBound, LMIN_FR) < 0)
+    siLowerBound = LMIN_FR;
+  for (i = siLowerBound, j = 0; i <= siUpperBound; i++, j++)
+    pswLBuf[j] = i;
+
+  /* Second, find peak in the interpolated CC/G sequence. */
+  /* The corresponding lag is the fundamental pitch.  The */
+  /* interpolated C(pitch) and G(pitch) values are stored */
+  /* for later use in calculating the Harmonic-Noise-     */
+  /* Weighting coefficient                                */
+  /*------------------------------------------------------*/
+
+  siNum = sub(siUpperBound, siLowerBound);
+  siNum = add(siNum, 1);
+  CGInterp(pswLBuf, siNum, pswIntCs, pswIntGs, LSMIN,
+           pswCBuf, pswGBuf);
+  sw1 = 0;
+  sw2 = 0x003f;
+  siPeakIndex = fnBest_CG(pswCBuf, pswGBuf, &sw1, &sw2, siNum);
+  if (siPeakIndex == -1)
+  {
+    swCPitch = 0;
+    *pswPitch = LMIN_FR;
+    swGPitch = 0x003f;
+  }
+  else
+  {
+    swCPitch = pswCBuf[siPeakIndex];
+    *pswPitch = pswLBuf[siPeakIndex];
+    swGPitch = pswGBuf[siPeakIndex];
+  }
+
+  /* Find all peaks which are multiples of fundamental pitch */
+  /*---------------------------------------------------------*/
+
+  swMult = add(*pswPitch, *pswPitch);
+  swMultInt = mult_r(swMult, INV_OS_FCTR);
+
+  while (sub(swMultInt, LMAX) <= 0)
+  {
+
+    /* Check if there is peak in the integer CC/G sequence within */
+    /* PEAK_VICINITY of the multiple                              */
+    /*------------------------------------------------------------*/
+
+    swFullResPeak = findPeak(swMultInt, pswIntCs, pswIntGs);
+
+    if (swFullResPeak)
+    {
+
+      /* Peak found at multiple: interpolate to get C's and G's    */
+      /* corresponding to valid lags within one of the new found   */
+      /* peak; get best C**2/G from these;  if it meets threshold, */
+      /* store the info corresponding to this peak                 */
+      /*-----------------------------------------------------------*/
+
+      siNum = CGInterpValid(swFullResPeak, pswIntCs, pswIntGs,
+                            pswLBuf, pswCBuf, pswGBuf);
+
+      sw1 = swCCThreshold;
+      sw2 = 0x4000;
+      siPeakIndex = fnBest_CG(pswCBuf, pswGBuf, &sw1, &sw2, siNum);
+      if (siPeakIndex != -1)
+      {
+
+        pswCPeaks[siCPeakIndex] = pswCBuf[siPeakIndex];
+        siCPeakIndex = add(siCPeakIndex, 1);
+        pswLPeaks[siLPeakIndex] = pswLBuf[siPeakIndex];
+        siLPeakIndex = add(siLPeakIndex, 1);
+        pswGPeaks[siGPeakIndex] = pswGBuf[siPeakIndex];
+        siGPeakIndex = add(siGPeakIndex, 1);
+
+      }
+    }
+
+    /* Get next multiple */
+    /*-------------------*/
+
+    swMult = add(*pswPitch, swMult);
+    swMultInt = mult_r(swMult, INV_OS_FCTR);
+  }
+
+  /* Get Harmonic-Noise-Weighting coefficient = 0.4 * C(pitch) / G(pitch) */
+  /* Note: a factor of 0.5 is applied the the HNW coeffcient              */
+  /*----------------------------------------------------------------------*/
+
+  si2 = norm_s(swCPitch);
+  sw1 = shl(swCPitch, si2);
+  L_1 = L_mult(sw1, PW_FRAC);
+
+  si1 = norm_s(swGPitch);
+  sw1 = shl(swGPitch, si1);
+
+  sw2 = round(L_shr(L_1, 1));
+  sw2 = divide_s(sw2, sw1);
+
+  if (sub(si1, si2) > 0)
+    sw2 = shl(sw2, sub(si1, si2));
+
+  if (sub(si1, si2) < 0)
+    sw2 = shift_r(sw2, sub(si1, si2));
+
+  *pswHNWCoef = sw2;
+
+  /* Sort peaks into output arrays, largest first */
+  /*----------------------------------------------*/
+
+  siLPeaksSortedInit = siSortedIndex;
+  *psiNumSorted = 0;
+  siNumPeaks = siLPeakIndex;
+  for (i = 0; i < siNumPeaks; i++)
+  {
+
+    sw1 = 0;
+    sw2 = 0x003f;
+    siPeakIndex = fnBest_CG(pswCPeaks, pswGPeaks, &sw1, &sw2, siNumPeaks);
+
+    siRepeat = 0;
+    swWorkingLag = pswLPeaks[siPeakIndex];
+    for (j = 0; j < *psiNumSorted; j++)
+    {
+
+      if (sub(swWorkingLag, pswLPeaksSorted[j + siLPeaksSortedInit]) == 0)
+        siRepeat = 1;
+    }
+
+    if (!siRepeat)
+    {
+
+      pswLPeaksSorted[siSortedIndex] = swWorkingLag;
+      pswCPeaksSorted[siSortedIndex] = pswCPeaks[siPeakIndex];
+      pswGPeaksSorted[siSortedIndex] = pswGPeaks[siPeakIndex];
+      siSortedIndex = add(siSortedIndex, 1);
+      *psiNumSorted = add(*psiNumSorted, 1);
+    }
+
+    pswCPeaks[siPeakIndex] = 0x0;
+  }
+}                                      /* end of pitchLags */
+
+
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: quantLag
+ *
+ *   PURPOSE:
+ *
+ *     Quantizes a given fractional lag according to the provided table
+ *     of allowable fractional lags.
+ *
+ *   INPUTS:
+ *
+ *     swRawLag
+ *
+ *                     Raw lag value: a fractional lag value*OS_FCTR.
+ *
+ *     psrLagTbl[0:255]
+ *
+ *                     Fractional lag table.
+ *
+ *   OUTPUTS:
+ *
+ *     pswCode
+ *
+ *                     Index in lag table of the quantized lag-- that is,
+ *                     the coded value of the lag.
+ *
+ *   RETURN VALUE:
+ *
+ *     Quantized lag value.
+ *
+ *
+ *   REFERENCE:  Sub-clause 4.1.8.3 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS: quantization, LTP, adaptive codebook
+ *
+ *************************************************************************/
+
+Shortword quantLag(Shortword swRawLag,
+                          Shortword *pswCode)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+  Shortword siOffset,
+         swIndex1,
+         swIndex2;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  swIndex1 = 0;
+  siOffset = shr(LAG_TABLE_LEN, 1);
+  swIndex2 = siOffset;
+  siOffset = shr(siOffset, 1);
+
+  while (sub(swIndex2, swIndex1) != 0)
+  {
+    if (sub(swRawLag, psrLagTbl[swIndex2]) >= 0)
+      swIndex1 = swIndex2;
+    swIndex2 = add(swIndex1, siOffset);
+    siOffset = shr(siOffset, 1);
+  }
+  *pswCode = swIndex2;
+
+  return (psrLagTbl[swIndex2]);
+
+}                                      /* end of quantLag */
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: r0Quant
+ *
+ *   PURPOSE:
+ *
+ *      Quantize the unquantized R(0).  Returns r0 codeword (index).
+ *
+ *   INPUTS:
+ *
+ *     L_UnqntzdR0
+ *                     The average frame energy R(0)
+ *
+ *   OUTPUTS: none
+ *
+ *   RETURN VALUE:
+ *
+ *                     A 16 bit number representing the codeword whose
+ *                     associated R(0) is closest to the input frame energy.
+ *
+ *   DESCRIPTION:
+ *
+ *     Returns r0 codeword (index) not the actual Rq(0).
+ *
+ *     Level compare input with boundary value (the boundary
+ *     above ,louder) of candidate r0Index i.e.
+ *     lowerBnd[i] <= inputR(0) < upperBnd[i+1]
+ *
+ *     The compare in the routine is:
+ *     inputR(0) < upperBnd[i+1] if false return i as codeword
+ *
+ *   REFERENCE:  Sub-clause 4.1.3 of GSM Recommendation 06.20
+ *
+ *
+ *************************************************************************/
+
+Shortword r0Quant(Longword L_UnqntzdR0)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword swR0Index,
+         swUnqntzdR0;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Executable Code                              |
+ |_________________________________________________________________________|
+*/
+
+  swUnqntzdR0 = round(L_UnqntzdR0);
+
+  for (swR0Index = 0; swR0Index < (1 << R0BITS) - 1; swR0Index++)
+  {
+    if (sub(swUnqntzdR0, psrR0DecTbl[2 * swR0Index + 1]) < 0)
+    {
+      return (swR0Index);
+    }
+  }
+  return ((1 << R0BITS) - 1);          /* return the maximum */
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: setupPreQ
+ *
+ *   PURPOSE:
+ *     The purpose of this function is to setup the internal pointers so that
+ *     getNextVec knows where to start.
+ *
+ *   INPUTS: iSeg, iVector
+ *
+ *   OUTPUTS: None
+ *
+ *   RETURN VALUE: none
+ *
+ *   DESCRIPTION:
+ *
+ *   REFERENCE:  Sub-clause  4.1.4.1 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS:  vector quantizer preQ
+ *
+ *************************************************************************/
+
+void   setupPreQ(int iSeg, int iVector)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  iLow = psvqIndex[iSeg - 1].l;
+  iThree = ((psvqIndex[iSeg - 1].h - iLow) == 2);
+
+  switch (iSeg)
+  {
+    case 1:
+      {
+        psrTable = psrPreQ1;
+        iWordPtr = (iVector * 3) >> 1;
+        if (odd(iVector))
+          iWordHalfPtr = LOW;
+        else
+          iWordHalfPtr = HIGH;
+        break;
+      }
+
+    case 2:
+      {
+        psrTable = psrPreQ2;
+        iWordPtr = (iVector * 3) >> 1;
+        if (odd(iVector))
+          iWordHalfPtr = LOW;
+        else
+          iWordHalfPtr = HIGH;
+        break;
+      }
+
+    case 3:
+      {
+        psrTable = psrPreQ3;
+        iWordPtr = iVector * 2;
+        iWordHalfPtr = HIGH;
+        break;
+      }
+  }
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: setupQuant
+ *
+ *   PURPOSE:
+ *     The purpose of this function is to setup the internal pointers so that
+ *     getNextVec knows where to start.
+ *
+ *
+ *   INPUTS: iSeg, iVector
+ *
+ *   OUTPUTS: None
+ *
+ *   RETURN VALUE: none
+ *
+ *   DESCRIPTION:
+ *
+ *   REFERENCE:  Sub-clause 4.1.4.1 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS:  vector quantizer Quant
+ *
+ *************************************************************************/
+
+void   setupQuant(int iSeg, int iVector)
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  iLow = psvqIndex[iSeg - 1].l;
+  iThree = ((psvqIndex[iSeg - 1].h - iLow) == 2);
+
+  switch (iSeg)
+  {
+    case 1:
+      {
+        psrTable = psrQuant1;
+        iWordPtr = (iVector * 3) >> 1;
+        if (odd(iVector))
+          iWordHalfPtr = LOW;
+        else
+          iWordHalfPtr = HIGH;
+        break;
+      }
+
+    case 2:
+      {
+        psrTable = psrQuant2;
+        iWordPtr = (iVector * 3) >> 1;
+        if (odd(iVector))
+          iWordHalfPtr = LOW;
+        else
+          iWordHalfPtr = HIGH;
+        break;
+      }
+
+    case 3:
+      {
+        psrTable = psrQuant3;
+        iWordPtr = iVector * 2;
+        iWordHalfPtr = HIGH;
+        break;
+      }
+  }
+}
+
+/***************************************************************************
+ *
+ *   FUNCTION NAME: weightSpeechFrame
+ *
+ *   PURPOSE:
+ *
+ *     The purpose of this function is to perform the spectral
+ *     weighting filter  (W(z)) of the input speech frame.
+ *
+ *   INPUTS:
+ *
+ *     pswSpeechFrm[0:F_LEN]
+ *
+ *                     high pass filtered input speech frame
+ *
+ *     pswWNumSpace[0:NP*N_SUB]
+ *
+ *                     W(z) numerator coefficients
+ *
+ *     pswWDenomSpace[0:NP*N_SUB]
+ *
+ *                     W(z) denominator coefficients
+ *
+ *     pswWSpeechBuffBase[0:F_LEN+LMAX+CG_INT_MACS/2]
+ *
+ *                     previous W(z) filtered speech
+ *
+ *   OUTPUTS:
+ *
+ *     pswWSpeechBuffBase[0:F_LEN+LMAX+CG_INT_MACS/2]
+ *
+ *                     W(z) filtered speech frame
+ *
+ *   RETURN VALUE:
+ *
+ *     none
+ *
+ *   DESCRIPTION:
+ *
+ *   REFERENCE:  Sub-clause 4.1.7 of GSM Recommendation 06.20
+ *
+ *   KEYWORDS:
+ *
+ *************************************************************************/
+
+void   weightSpeechFrame(Shortword pswSpeechFrm[],
+                                Shortword pswWNumSpace[],
+                                Shortword pswWDenomSpace[],
+                                Shortword pswWSpeechBuffBase[])
+{
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                            Automatic Variables                          |
+ |_________________________________________________________________________|
+*/
+
+  Shortword pswScratch0[W_F_BUFF_LEN],
+        *pswWSpeechFrm;
+  short int siI;
+
+/*_________________________________________________________________________
+ |                                                                         |
+ |                              Executable Code                            |
+ |_________________________________________________________________________|
+*/
+
+  /* Delay the weighted speech buffer by one frame */
+  /* --------------------------------------------- */
+
+  for (siI = 0; siI < LSMAX; siI++)
+  {
+    pswWSpeechBuffBase[siI] = pswWSpeechBuffBase[siI + F_LEN];
+  }
+
+  /* pass speech frame through W(z) */
+  /* ------------------------------ */
+
+  pswWSpeechFrm = pswWSpeechBuffBase + LSMAX;
+
+  for (siI = 0; siI < N_SUB; siI++)
+  {
+    lpcFir(&pswSpeechFrm[siI * S_LEN], &pswWNumSpace[siI * NP],
+           pswWStateNum, &pswScratch0[siI * S_LEN]);
+  }
+
+  for (siI = 0; siI < N_SUB; siI++)
+  {
+    lpcIir(&pswScratch0[siI * S_LEN], &pswWDenomSpace[siI * NP],
+           pswWStateDenom, &pswWSpeechFrm[siI * S_LEN]);
+  }
+}