view libgsmhr1/dtx_enc.c @ 622:3ae5508f9a54 default tip

libgsmhr1/sp_sfrm.c: constify "ROM" static data
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 05 Mar 2026 21:56:18 +0000
parents e6e9d5104503
children
line wrap: on
line source

/***************************************************************************
 *
 *   File Name: dtx_enc.c
 *
 *   Derivation: this module is the subset of GSM 06.06 dtx.c
 *   reduced to those functions that are used only by the speech
 *   encoder.
 *
 **************************************************************************/

/*________________________________________________________________________
 |                                                                        |
 |                         Include Files                                  |
 |________________________________________________________________________|
*/

#include "typedefs.h"
#include "namespace.h"
#include "mathhalf.h"
#include "mathdp31.h"
#include "enc_state.h"
#include "dtx_const.h"
#include "dtx_enc.h"
#include "dtx_rxfe.h"
#include "sp_frm.h"

/*________________________________________________________________________
 |                                                                        |
 |                            Defines                                     |
 |________________________________________________________________________|
*/

#define OH_SHIFT 3                     /* shift corresponding to OVERHANG */

#define NP_AFLAT 4
#define LPC_VQ_SEG 3


/*************************************************************************
 *
 *   FUNCTION NAME: swComfortNoise
 *
 *   PURPOSE:
 *
 *   This routine perform the following tasks:
 *     - generation of the speech flag (swSP)
 *     - averaging and encoding of the comfort noise parameters
 *     - randomization of the codebook indices
 *
 *
 *   INPUTS:
 *
 *   swVadFrmCnt (global) - swVadFlag=0 frame counter.
 *   If swVadFlag=1 then this counter is 0, the first frame with
 *   swVadFlag=0 will set this counter to 1, with each additional
 *   swVadFlag=0 frame the counter is incremented.
 *
 *   swVadFlag - voise activity flag. swVadFlag=0 frame with
 *   no voice activity, swVadFlag=0 frame with voice activity
 *
 *   L_UnqntzdR0 - unquantized R(0), 32 bit value, output of
 *   FLAT.
 *
 *   pL_UnqntzdCorr[NP+1] - unquantized correlation sequence,
 *   also an output of FLAT.
 *
 *
 *   OUTPUTS:
 *
 *   swCNR0 - global variable, the output quantized R0 index
 *
 *   pswCNLpc[3]  - global variable, the output quantized LPC to the
 *   transmitted in the SID frame
 *
 *   pswCNGsp0Code[N_SUB] - global variable, the output quantized GSP0 indices
 *
 *   pswCNVSCode1[N_SUB] - global variable, the output quantized codevector 1
 *   indices.
 *
 *   pswCNVSCode2[N_SUB] - global variable, the output quantized codevector 2
 *   indices.
 *
 *
 *   RETURN VALUE:
 *
 *   swSP - speech flag, swSP=1 speech frames are generated, swSP=0
 *   SID frames are generated.
 *
 *************************************************************************/

Shortword swComfortNoise(struct gsmhr_encoder_state *st, Shortword swVadFlag,
			 Longword L_UnqntzdR0, Longword *pL_UnqntzdCorr)
{

/*_________________________________________________________________________
 |                                                                         |
 |                            Automatic Variables                          |
 |_________________________________________________________________________|
*/

  struct cn_state *cn_st = &st->cn_state;
  Shortword swSP;
  Shortword pswFinalRc[NP];

  /* unquantized reference parameters */
  Longword L_RefR0;
  Longword pL_RefCorr[NP + 1];
  Longword L_RefGs;

  int    i;


/*_________________________________________________________________________
 |                                                                         |
 |                              Executable Code                            |
 |_________________________________________________________________________|
*/

  swSP = 1;

  /* VadFrmCnt will indicate the number of sequential frames where */
  /* swVadFlag == 0                                                */
  /* ------------------------------------------------------------- */

  if (swVadFlag)
    st->swVadFrmCnt = 0;                       /* Voice acitvity present */
  else
    st->swVadFrmCnt = add(st->swVadFrmCnt, 1); /* no voice activity */


  /* swNElapsed will indicate the number of frames that have elapsed */
  /* since the last SID frame with updated comfort noise parameters  */
  /* was generated                                                   */
  /* --------------------------------------------------------------- */

  st->swNElapsed = add(st->swNElapsed, 1);


  /* If no voice activity was detected.  */
  /* ----------------------------------- */

  if (st->swVadFrmCnt)
  {

    /* Short speech burst ? */
    /* -------------------- */

    if (st->swVadFrmCnt == 1)
    {
      if (sub(st->swNElapsed, 24) < 0)
        cn_st->swShortBurst = 1;       /* short speech burst detected */
      else
        cn_st->swShortBurst = 0;       /* long speech burst detected */
    }


    /* Update history, with this frames data */
    /* ------------------------------------- */

    updateCNHist(st, L_UnqntzdR0, pL_UnqntzdCorr,
                 cn_st->pL_R0Hist, cn_st->ppL_CorrHist);


    /* first SID frame */
    /* --------------- */

    if (((cn_st->swShortBurst == 0) && (st->swVadFrmCnt == OVERHANG)) ||
        ((cn_st->swShortBurst == 1) && (st->swVadFrmCnt == 1)))
    {

      /* init. random generator */
      /* ---------------------- */
      cn_st->L_TxPNSeed = PN_INIT_SEED;


      /* average GS */
      /* ---------- */
      avgGsHistQntz(st->pL_GsHist, &L_RefGs);


      /* GS quantization */
      /* --------------- */
      cn_st->swRefGsIndex = gsQuant(L_RefGs, 0);

    }


    /* No Overhang in case of short speech bursts,                */
    /* generate SID frames with repeated comfort noise parameters */
    /* ---------------------------------------------------------- */

    if ((cn_st->swShortBurst == 1) && (st->swVadFrmCnt < OVERHANG))
    {

      /* generate a SID frame with repeated parameters */
      /* --------------------------------------------- */

      swSP = 0;


      /* repeat data: r0, LPC, GS */
      /* ------------------------ */

      st->swCNR0 = cn_st->swQntRefR0;

      for (i = 0; i < 3; i++)
        st->pswCNLpc[i] = cn_st->piRefVqCodewds[i];

      for (i = 0; i < N_SUB; i++)
        st->pswCNGsp0Code[i] = cn_st->swRefGsIndex;

    }


    /* generate SID frames with updated comfort noise parameters */
    /* --------------------------------------------------------- */

    if (st->swVadFrmCnt >= OVERHANG)
    {

      /* A SID frame with updated parameters */
      /* ----------------------------------- */

      swSP = 0;
      st->swNElapsed = 0;


      /* average R0 and correlation values */
      /* --------------------------------- */

      avgCNHist(cn_st->pL_R0Hist, cn_st->ppL_CorrHist, &L_RefR0,
                pL_RefCorr);


      /* now quantize the averaged R(0) */
      /* ------------------------------ */

      cn_st->swQntRefR0 = r0Quant(L_RefR0);


      /* Quantize the averaged correlation */
      /* --------------------------------- */

      lpcCorrQntz(st, pL_RefCorr,
                  pswFinalRc,
                  cn_st->piRefVqCodewds);


      /* update frame data: r0, LPC */
      /* -------------------------- */

      st->swCNR0 = cn_st->swQntRefR0;
      for (i = 0; i < 3; i++)
        st->pswCNLpc[i] = cn_st->piRefVqCodewds[i];


      /* update subframe data (unvoiced mode): GSP0 */
      /* ------------------------------------------ */

      for (i = 0; i < N_SUB; i++)
        st->pswCNGsp0Code[i] = cn_st->swRefGsIndex;

    }


    /* random codevectors */
    /* ------------------ */

    if (swSP == 0)
    {
      for (i = 0; i < N_SUB; i++)
      {
        st->pswCNVSCode1[i] = getPnBits(7, &cn_st->L_TxPNSeed);
        st->pswCNVSCode2[i] = getPnBits(7, &cn_st->L_TxPNSeed);
      }
    }


  }

  return (swSP);
}


/*************************************************************************
 *
 *   FUNCTION NAME:  updateCNHist
 *
 *   PURPOSE:
 *
 *     Add current frame's unquantized R(0) and LPC information to the
 *     comfort noise history, so that it will be available for
 *     averaging.
 *
 *   INPUTS:
 *
 *     Unquantized values from the coder:
 *
 *
 *     L_UnqntzdR0 - unquantized frame energy R(0), an output of FLAT
 *
 *     pL_UnqntzdCorr[NP+1] - unquantized correlation coefficient
 *     array.  Also an output of FLAT.
 *
 *     siUpdPointer (global) - A modulo counter which counts up from
 *     0 to OVERHANG-1.
 *
 *   OUTPUTS:
 *
 *     pL_R0History[OVERHANG] - history of the OVERHANG frames worth of
 *     R(0).
 *
 *     ppL_CorrHistory[OVERHANG][NP+1] - - history of the OVERHANG
 *     frames worth of pL_UnqntzdCorr[].
 *
 *   RETURN VALUE:
 *
 *     none
 *
 *************************************************************************/

void updateCNHist(struct gsmhr_encoder_state *st, Longword L_UnqntzdR0,
		  Longword *pL_UnqntzdCorr, Longword pL_R0Hist[],
		  Longword ppL_CorrHist[OVERHANG][NP + 1])
{

/*_________________________________________________________________________
 |                                                                         |
 |                            Automatic Variables                          |
 |_________________________________________________________________________|
*/

  int    i;


/*_________________________________________________________________________
 |                                                                         |
 |                              Executable Code                            |
 |_________________________________________________________________________|
*/

  /* update */
  pL_R0Hist[st->siUpdPointer] = L_UnqntzdR0;

  for (i = 0; i < NP + 1; i++)
    ppL_CorrHist[st->siUpdPointer][i] = pL_UnqntzdCorr[i];

  st->siUpdPointer = (st->siUpdPointer + 1) % OVERHANG;
}


/*************************************************************************
 *
 *   FUNCTION NAME: avgCNHist
 *
 *   PURPOSE:
 *
 *     Average the unquantized R0 and LPC data stored at the encoder
 *     to arrive at an average R0 and LPC frame for use in a SID
 *     frame.
 *
 *   INPUTS:
 *
 *   pL_R0History[OVERHANG] - contains unquantized R(0) data from the
 *   most recent OVERHANG frame (including this one).
 *
 *   ppL_CorrHistory[OVERHANG][NP+1] - Unquantized correlation
 *   coefficients from the most recent OVERHANG frame (including this
 *   one).  The data stored here is an output of FLAT.
 *
 *   OUTPUTS:
 *
 *   *pL_AvgdR0 - the average of pL_R0History[]
 *
 *   pL_AvgdCorrSeq[NP+1] - the average of ppL_CorrHistory[][].
 *
 *
 *   RETURN VALUE:
 *
 *     none
 *
 *************************************************************************/

void avgCNHist(Longword pL_R0History[],
		Longword ppL_CorrHistory[OVERHANG][NP + 1],
		Longword *pL_AvgdR0, Longword pL_AvgdCorrSeq[])
{

/*_________________________________________________________________________
 |                                                                         |
 |                            Automatic Variables                          |
 |_________________________________________________________________________|
*/

  int    i,
         j;
  Longword L_avg;

/*_________________________________________________________________________
 |                                                                         |
 |                              Executable Code                            |
 |_________________________________________________________________________|
*/

  /* R0 Averaging */
  /* ------------ */

  for (L_avg = 0, i = 0; i < OVERHANG; i++)
    L_avg = L_add(L_shr(pL_R0History[i], OH_SHIFT), L_avg);

  *pL_AvgdR0 = L_avg;


  /* LPC: average the last OVERHANG frames */
  /* ------------------------------------- */

  for (j = 0; j < NP + 1; j++)
  {
    for (L_avg = 0, i = 0; i < OVERHANG; i++)
    {
      L_avg = L_add(L_shift_r(ppL_CorrHistory[i][j], -OH_SHIFT), L_avg);
    }

    pL_AvgdCorrSeq[j] = L_avg;
  }

}


/***************************************************************************
 *
 *    FUNCTION NAME: lpcCorrQntz
 *
 *    PURPOSE:  Quantize a correlation sequence
 *
 *
 *    INPUT:
 *
 *         pL_CorrelSeq[NP+1]
 *                     Correlation sequence to quantize.
 *
 *    OUTPUTS:
 *
 *        pswFinalRc[0:NP-1]
 *                     A quantized set of NP reflection coefficients.
 *
 *        piVQCodewds[0:2]
 *                     An array containing the indices of the 3 reflection
 *                     coefficient vectors selected from the three segment
 *                     Rc-VQ.
 *
 *    RETURN:
 *        None.
 *
 *    KEYWORDS: AFLAT,aflat,flat,vectorquantization, reflectioncoefficients
 *
 *************************************************************************/

void lpcCorrQntz(struct gsmhr_encoder_state *st, Longword pL_CorrelSeq[],
		 Shortword pswFinalRc[], int piVQCodewds[])
{

/*_________________________________________________________________________
 |                                                                         |
 |                            Automatic Variables                          |
 |_________________________________________________________________________|
*/

  Shortword pswPOldSpace[NP_AFLAT],
         pswPNewSpace[NP_AFLAT],
         pswVOldSpace[2 * NP_AFLAT - 1],
         pswVNewSpace[2 * NP_AFLAT - 1],
        *ppswPAddrs[2],
        *ppswVAddrs[2],
        *pswVBar,
         pswPBar[NP_AFLAT],
         pswVBarSpace[2 * NP_AFLAT - 1],
         pswFlatsRc[NP],               /* Unquantized Rc's computed by FLAT */
         pswRc[NP + 1];                /* Temp list for the converted RC's */
  Longword *pL_VBarFull,
         pL_PBarFull[NP],
         pL_VBarFullSpace[2 * NP - 1];

  int    i,
         iVec,
         iSeg,
         iCnt;                         /* Loop counter */
  struct QuantList quantList,          /* A list of vectors */
         bestPql[4];                   /* The four best vectors from
                                        * the PreQ */
  struct QuantList bestQl[LPC_VQ_SEG + 1];      /* Best vectors for each of
                                                 * the three segments */

/*_________________________________________________________________________
 |                                                                         |
 |                              Executable Code                            |
 |_________________________________________________________________________|
*/

  /* Setup pointers temporary space */
  /*--------------------------------*/

  pswVBar = pswVBarSpace + NP_AFLAT - 1;
  pL_VBarFull = pL_VBarFullSpace + NP - 1;
  ppswPAddrs[0] = pswPOldSpace;
  ppswPAddrs[1] = pswPNewSpace;
  ppswVAddrs[0] = pswVOldSpace + NP_AFLAT - 1;
  ppswVAddrs[1] = pswVNewSpace + NP_AFLAT - 1;


  /* Set up pL_PBarFull and pL_VBarFull initial conditions, using the   */
  /* autocorrelation sequence derived from the optimal reflection       */
  /* coefficients computed by FLAT. The initial conditions are shifted  */
  /* right by RSHIFT bits. These initial conditions, stored as          */
  /* Longwords, are used to initialize PBar and VBar arrays for the     */
  /* next VQ segment.                                                   */
  /*--------------------------------------------------------------------*/

  initPBarFullVBarFullL(pL_CorrelSeq, pL_PBarFull, pL_VBarFull);

  /* Set up initial PBar and VBar initial conditions, using pL_PBarFull */
  /* and pL_VBarFull arrays initialized above. These are the initial    */
  /* PBar and VBar conditions to be used by the AFLAT recursion at the  */
  /* 1-st Rc-VQ segment.                                                */
  /*--------------------------------------------------------------------*/

  initPBarVBarL(pL_PBarFull, pswPBar, pswVBar);

  for (iSeg = 1; iSeg <= LPC_VQ_SEG; iSeg++)
  {
    /* initialize candidate list */
    /*---------------------------*/

    quantList.iNum = psrPreQSz[iSeg - 1];
    quantList.iRCIndex = 0;

    /* do aflat for all vectors in the list */
    /*--------------------------------------*/

    setupPreQ(st, iSeg, quantList.iRCIndex);    /* set up vector ptrs */

    for (iCnt = 0; iCnt < quantList.iNum; iCnt++)
    {
      /* get a vector */
      /*--------------*/

      getNextVec(st, pswRc);

      /* clear the limiter flag */
      /*------------------------*/

      st->iLimit = 0;

      /* find the error values for each vector */
      /*---------------------------------------*/

      quantList.pswPredErr[iCnt] =
              aflatRecursion(st, &pswRc[psvqIndex[iSeg - 1].l],
                             pswPBar, pswVBar,
                             ppswPAddrs, ppswVAddrs,
                             psvqIndex[iSeg - 1].len);

      /* check the limiter flag */
      /*------------------------*/

      if (st->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(st, 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(st, pswRc);

        /* clear the limiter flag */
        /*------------------------*/

        st->iLimit = 0;

        /* find the error values for each vector */
        /*---------------------------------------*/

        quantList.pswPredErr[iCnt] =
                aflatRecursion(st, &pswRc[psvqIndex[iSeg - 1].l],
                               pswPBar, pswVBar,
                               ppswPAddrs, ppswVAddrs,
                               psvqIndex[iSeg - 1].len);

        /* check the limiter flag */
        /*------------------------*/

        if (st->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(st, iSeg, bestQl[iSeg].iRCIndex);    /* set up vector ptrs */
    getNextVec(st, (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;

}