text: /*
   ** Copyright 2003-2010, VisualOn, Inc.
   **
   ** Licensed under the Apache License, Version 2.0 (the "License");
   ** you may not use this file except in compliance with the License.
   ** You may obtain a copy of the License at
   **
   **     http://www.apache.org/licenses/LICENSE-2.0
   **
   ** Unless required by applicable law or agreed to in writing, software
   ** distributed under the License is distributed on an "AS IS" BASIS,
   ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ** See the License for the specific language governing permissions and
   ** limitations under the License.
   */
  /*******************************************************************************
  	File:		tns.c
  
  	Content:	Definition TNS tools functions
  
  *******************************************************************************/
  
  #include "../basic_op/basic_op.h"
  #include "../basic_op/oper_32b.h"
  #include "assert.h"
  #include "aac_rom.h"
  #include "psy_const.h"
  #include "tns.h"
  #include "tns_param.h"
  #include "psy_configuration.h"
  #include "tns_func.h"
  
  #define UNUSED(x) (void)(x)
  
  #define TNS_MODIFY_BEGIN         2600  /* Hz */
  #define RATIO_PATCH_LOWER_BORDER 380   /* Hz */
  #define TNS_GAIN_THRESH			 141   /* 1.41*100 */
  #define NORM_COEF				 0x028f5c28
  
  static const Word32 TNS_PARCOR_THRESH = 0x0ccccccd; /* 0.1*(1 << 31) */
  /* Limit bands to > 2.0 kHz */
  static unsigned short tnsMinBandNumberLong[12] =
  { 11, 12, 15, 16, 17, 20, 25, 26, 24, 28, 30, 31 };
  static unsigned short tnsMinBandNumberShort[12] =
  { 2, 2, 2, 3, 3, 4, 6, 6, 8, 10, 10, 12 };
  
  /**************************************/
  /* Main/Low Profile TNS Parameters    */
  /**************************************/
  static unsigned short tnsMaxBandsLongMainLow[12] =
  { 31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39 };
  
  static unsigned short tnsMaxBandsShortMainLow[12] =
  { 9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14 };
  
  
  static void CalcWeightedSpectrum(const Word32 spectrum[],
                                   Word16 weightedSpectrum[],
                                   Word32* sfbEnergy,
                                   const Word16* sfbOffset, Word16 lpcStartLine,
                                   Word16 lpcStopLine, Word16 lpcStartBand,Word16 lpcStopBand,
                                   Word32 *pWork32);
  
  
  
  void AutoCorrelation(const Word16 input[], Word32 corr[],
                              Word16 samples, Word16 corrCoeff);
  static Word16 AutoToParcor(Word32 workBuffer[], Word32 reflCoeff[], Word16 numOfCoeff);
  
  static Word16 CalcTnsFilter(const Word16* signal, const Word32 window[], Word16 numOfLines,
                                                Word16 tnsOrder, Word32 parcor[]);
  
  
  static void Parcor2Index(const Word32 parcor[], Word16 index[], Word16 order,
                           Word16 bitsPerCoeff);
  
  static void Index2Parcor(const Word16 index[], Word32 parcor[], Word16 order,
                           Word16 bitsPerCoeff);
  
  
  
  static void AnalysisFilterLattice(const Word32 signal[], Word16 numOfLines,
                                    const Word32 parCoeff[], Word16 order,
                                    Word32 output[]);
  
  
  /**
  *
  * function name: FreqToBandWithRounding
  * description:  Retrieve index of nearest band border
  * returnt:		index
  *
  */
  static Word16 FreqToBandWithRounding(Word32 freq,                   /*!< frequency in Hertz */
                                       Word32 fs,                     /*!< Sampling frequency in Hertz */
                                       Word16 numOfBands,             /*!< total number of bands */
                                       const Word16 *bandStartOffset) /*!< table of band borders */
  {
    Word32 lineNumber, band;
    Word32 temp, shift;
  
    /*  assert(freq >= 0);  */
    shift = norm_l(fs);
    lineNumber = (extract_l(fixmul((bandStartOffset[numOfBands] << 2),Div_32(freq << shift,fs << shift))) + 1) >> 1;
  
    /* freq > fs/2 */
    temp = lineNumber - bandStartOffset[numOfBands] ;
    if (temp >= 0)
      return numOfBands;
  
    /* find band the line number lies in */
    for (band=0; band<numOfBands; band++) {
      temp = bandStartOffset[band + 1] - lineNumber;
      if (temp > 0) break;
    }
  
    temp = (lineNumber - bandStartOffset[band]);
    temp = (temp - (bandStartOffset[band + 1] - lineNumber));
    if ( temp > 0 )
    {
      band = band + 1;
    }
  
    return extract_l(band);
  }
  
  
  /**
  *
  * function name: InitTnsConfigurationLong
  * description:  Fill TNS_CONFIG structure with sensible content for long blocks
  * returns:		0 if success
  *
  */
  Word16 InitTnsConfigurationLong(Word32 bitRate,          /*!< bitrate */
                                  Word32 sampleRate,          /*!< Sampling frequency */
                                  Word16 channels,            /*!< number of channels */
                                  TNS_CONFIG *tC,             /*!< TNS Config struct (modified) */
                                  PSY_CONFIGURATION_LONG *pC, /*!< psy config struct */
                                  Word16 active)              /*!< tns active flag */
  {
  
    //Word32 bitratePerChannel __unused;
    tC->maxOrder     = TNS_MAX_ORDER;
    tC->tnsStartFreq = 1275;
    tC->coefRes      = 4;
  
    /* to avoid integer division */
    //if ( sub(channels,2) == 0 ) {
    //  bitratePerChannel = bitRate >> 1;
    //}
    //else {
    //  bitratePerChannel = bitRate;
    //}
  
    tC->tnsMaxSfb = tnsMaxBandsLongMainLow[pC->sampRateIdx];
  
    tC->tnsActive = active;
  
    /* now calc band and line borders */
    tC->tnsStopBand = min(pC->sfbCnt, tC->tnsMaxSfb);
    tC->tnsStopLine = pC->sfbOffset[tC->tnsStopBand];
  
    tC->tnsStartBand = FreqToBandWithRounding(tC->tnsStartFreq, sampleRate,
                                              pC->sfbCnt, (const Word16*)pC->sfbOffset);
  
    tC->tnsModifyBeginCb = FreqToBandWithRounding(TNS_MODIFY_BEGIN,
                                                  sampleRate,
                                                  pC->sfbCnt,
                                                  (const Word16*)pC->sfbOffset);
  
    tC->tnsRatioPatchLowestCb = FreqToBandWithRounding(RATIO_PATCH_LOWER_BORDER,
                                                       sampleRate,
                                                       pC->sfbCnt,
                                                       (const Word16*)pC->sfbOffset);
  
  
    tC->tnsStartLine = pC->sfbOffset[tC->tnsStartBand];
  
    tC->lpcStopBand = tnsMaxBandsLongMainLow[pC->sampRateIdx];
    tC->lpcStopBand = min(tC->lpcStopBand, pC->sfbActive);
  
    tC->lpcStopLine = pC->sfbOffset[tC->lpcStopBand];
  
    tC->lpcStartBand = tnsMinBandNumberLong[pC->sampRateIdx];
  
    tC->lpcStartLine = pC->sfbOffset[tC->lpcStartBand];
  
    tC->threshold = TNS_GAIN_THRESH;
  
  
    return(0);
  }
  
  /**
  *
  * function name: InitTnsConfigurationShort
  * description:  Fill TNS_CONFIG structure with sensible content for short blocks
  * returns:		0 if success
  *
  */
  Word16 InitTnsConfigurationShort(Word32 bitRate,              /*!< bitrate */
                                   Word32 sampleRate,           /*!< Sampling frequency */
                                   Word16 channels,             /*!< number of channels */
                                   TNS_CONFIG *tC,              /*!< TNS Config struct (modified) */
                                   PSY_CONFIGURATION_SHORT *pC, /*!< psy config struct */
                                   Word16 active)               /*!< tns active flag */
  {
    //Word32 bitratePerChannel __unused;
    tC->maxOrder     = TNS_MAX_ORDER_SHORT;
    tC->tnsStartFreq = 2750;
    tC->coefRes      = 3;
  
    /* to avoid integer division */
    //if ( sub(channels,2) == 0 ) {
    //  bitratePerChannel = L_shr(bitRate,1);
    //}
    //else {
    //  bitratePerChannel = bitRate;
    //}
  
    tC->tnsMaxSfb = tnsMaxBandsShortMainLow[pC->sampRateIdx];
  
    tC->tnsActive = active;
  
    /* now calc band and line borders */
    tC->tnsStopBand = min(pC->sfbCnt, tC->tnsMaxSfb);
    tC->tnsStopLine = pC->sfbOffset[tC->tnsStopBand];
  
    tC->tnsStartBand=FreqToBandWithRounding(tC->tnsStartFreq, sampleRate,
                                            pC->sfbCnt, (const Word16*)pC->sfbOffset);
  
    tC->tnsModifyBeginCb = FreqToBandWithRounding(TNS_MODIFY_BEGIN,
                                                  sampleRate,
                                                  pC->sfbCnt,
                                                  (const Word16*)pC->sfbOffset);
  
    tC->tnsRatioPatchLowestCb = FreqToBandWithRounding(RATIO_PATCH_LOWER_BORDER,
                                                       sampleRate,
                                                       pC->sfbCnt,
                                                       (const Word16*)pC->sfbOffset);
  
  
    tC->tnsStartLine = pC->sfbOffset[tC->tnsStartBand];
  
    tC->lpcStopBand = tnsMaxBandsShortMainLow[pC->sampRateIdx];
  
    tC->lpcStopBand = min(tC->lpcStopBand, pC->sfbActive);
  
    tC->lpcStopLine = pC->sfbOffset[tC->lpcStopBand];
  
    tC->lpcStartBand = tnsMinBandNumberShort[pC->sampRateIdx];
  
    tC->lpcStartLine = pC->sfbOffset[tC->lpcStartBand];
  
    tC->threshold = TNS_GAIN_THRESH;
  
    return(0);
  }
  
  /**
  *
  * function name: TnsDetect
  * description:  Calculate TNS filter and decide on TNS usage
  * returns:		0 if success
  *
  */
  Word32 TnsDetect(TNS_DATA* tnsData,        /*!< tns data structure (modified) */
                   TNS_CONFIG tC,            /*!< tns config structure */
                   Word32* pScratchTns,      /*!< pointer to scratch space */
                   const Word16 sfbOffset[], /*!< scalefactor size and table */
                   Word32* spectrum,         /*!< spectral data */
                   Word16 subBlockNumber,    /*!< subblock num */
                   Word16 blockType,         /*!< blocktype (long or short) */
                   Word32 * sfbEnergy)       /*!< sfb-wise energy */
  {
  
    Word32  predictionGain;
    Word32  temp;
    Word32* pWork32 = &pScratchTns[subBlockNumber >> 8];
    Word16* pWeightedSpectrum = (Word16 *)&pScratchTns[subBlockNumber >> 8];
  
  
    if (tC.tnsActive) {
      CalcWeightedSpectrum(spectrum,
                           pWeightedSpectrum,
                           sfbEnergy,
                           sfbOffset,
                           tC.lpcStartLine,
                           tC.lpcStopLine,
                           tC.lpcStartBand,
                           tC.lpcStopBand,
                           pWork32);
  
      temp = blockType - SHORT_WINDOW;
      if ( temp != 0 ) {
          predictionGain = CalcTnsFilter( &pWeightedSpectrum[tC.lpcStartLine],
                                          tC.acfWindow,
                                          tC.lpcStopLine - tC.lpcStartLine,
                                          tC.maxOrder,
                                          tnsData->dataRaw.tnsLong.subBlockInfo.parcor);
  
  
          temp = predictionGain - tC.threshold;
          if ( temp > 0 ) {
            tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive = 1;
          }
          else {
            tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive = 0;
          }
  
          tnsData->dataRaw.tnsLong.subBlockInfo.predictionGain = predictionGain;
      }
      else{
  
          predictionGain = CalcTnsFilter( &pWeightedSpectrum[tC.lpcStartLine],
                                          tC.acfWindow,
                                          tC.lpcStopLine - tC.lpcStartLine,
                                          tC.maxOrder,
                                          tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].parcor);
  
          temp = predictionGain - tC.threshold;
          if ( temp > 0 ) {
            tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].tnsActive = 1;
          }
          else {
            tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].tnsActive = 0;
          }
  
          tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].predictionGain = predictionGain;
      }
  
    }
    else{
  
      temp = blockType - SHORT_WINDOW;
      if ( temp != 0 ) {
          tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive = 0;
          tnsData->dataRaw.tnsLong.subBlockInfo.predictionGain = 0;
      }
      else {
          tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].tnsActive = 0;
          tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber].predictionGain = 0;
      }
    }
  
    return(0);
  }
  
  
  /*****************************************************************************
  *
  * function name: TnsSync
  * description: update tns parameter
  *
  *****************************************************************************/
  void TnsSync(TNS_DATA *tnsDataDest,
               const TNS_DATA *tnsDataSrc,
               const TNS_CONFIG tC,
               const Word16 subBlockNumber,
               const Word16 blockType)
  {
     TNS_SUBBLOCK_INFO *sbInfoDest;
     const TNS_SUBBLOCK_INFO *sbInfoSrc;
     Word32 i, temp;
  
     temp =  blockType - SHORT_WINDOW;
     if ( temp != 0 ) {
        sbInfoDest = &tnsDataDest->dataRaw.tnsLong.subBlockInfo;
        sbInfoSrc  = &tnsDataSrc->dataRaw.tnsLong.subBlockInfo;
     }
     else {
        sbInfoDest = &tnsDataDest->dataRaw.tnsShort.subBlockInfo[subBlockNumber];
        sbInfoSrc  = &tnsDataSrc->dataRaw.tnsShort.subBlockInfo[subBlockNumber];
     }
  
     if (100*abs_s(sbInfoDest->predictionGain - sbInfoSrc->predictionGain) <
         (3 * sbInfoDest->predictionGain)) {
        sbInfoDest->tnsActive = sbInfoSrc->tnsActive;
        for ( i=0; i< tC.maxOrder; i++) {
          sbInfoDest->parcor[i] = sbInfoSrc->parcor[i];
        }
     }
  }
  
  /*****************************************************************************
  *
  * function name: TnsEncode
  * description: do TNS filtering
  * returns:     0 if success
  *
  *****************************************************************************/
  Word16 TnsEncode(TNS_INFO* tnsInfo,     /*!< tns info structure (modified) */
                   TNS_DATA* tnsData,     /*!< tns data structure (modified) */
                   Word16 numOfSfb,       /*!< number of scale factor bands */
                   TNS_CONFIG tC,         /*!< tns config structure */
                   Word16 lowPassLine,    /*!< lowpass line */
                   Word32* spectrum,      /*!< spectral data (modified) */
                   Word16 subBlockNumber, /*!< subblock num */
                   Word16 blockType)      /*!< blocktype (long or short) */
  {
    Word32 i;
    Word32 temp_s;
    Word32 temp;
    TNS_SUBBLOCK_INFO *psubBlockInfo;
  
    temp_s = blockType - SHORT_WINDOW;
    if ( temp_s != 0) {
      psubBlockInfo = &tnsData->dataRaw.tnsLong.subBlockInfo;
  	if (psubBlockInfo->tnsActive == 0) {
        tnsInfo->tnsActive[subBlockNumber] = 0;
        return(0);
      }
      else {
  
        Parcor2Index(psubBlockInfo->parcor,
                     tnsInfo->coef,
                     tC.maxOrder,
                     tC.coefRes);
  
        Index2Parcor(tnsInfo->coef,
                     psubBlockInfo->parcor,
                     tC.maxOrder,
                     tC.coefRes);
  
        for (i=tC.maxOrder - 1; i>=0; i--)  {
          temp = psubBlockInfo->parcor[i] - TNS_PARCOR_THRESH;
          if ( temp > 0 )
            break;
          temp = psubBlockInfo->parcor[i] + TNS_PARCOR_THRESH;
          if ( temp < 0 )
            break;
        }
        tnsInfo->order[subBlockNumber] = i + 1;
  
  
        tnsInfo->tnsActive[subBlockNumber] = 1;
        for (i=subBlockNumber+1; i<TRANS_FAC; i++) {
          tnsInfo->tnsActive[i] = 0;
        }
        tnsInfo->coefRes[subBlockNumber] = tC.coefRes;
        tnsInfo->length[subBlockNumber] = numOfSfb - tC.tnsStartBand;
  
  
        AnalysisFilterLattice(&(spectrum[tC.tnsStartLine]),
                              (min(tC.tnsStopLine,lowPassLine) - tC.tnsStartLine),
                              psubBlockInfo->parcor,
                              tnsInfo->order[subBlockNumber],
                              &(spectrum[tC.tnsStartLine]));
  
      }
    }     /* if (blockType!=SHORT_WINDOW) */
    else /*short block*/ {
      psubBlockInfo = &tnsData->dataRaw.tnsShort.subBlockInfo[subBlockNumber];
  	if (psubBlockInfo->tnsActive == 0) {
        tnsInfo->tnsActive[subBlockNumber] = 0;
        return(0);
      }
      else {
  
        Parcor2Index(psubBlockInfo->parcor,
                     &tnsInfo->coef[subBlockNumber*TNS_MAX_ORDER_SHORT],
                     tC.maxOrder,
                     tC.coefRes);
  
        Index2Parcor(&tnsInfo->coef[subBlockNumber*TNS_MAX_ORDER_SHORT],
                     psubBlockInfo->parcor,
                     tC.maxOrder,
                     tC.coefRes);
        for (i=(tC.maxOrder - 1); i>=0; i--)  {
          temp = psubBlockInfo->parcor[i] - TNS_PARCOR_THRESH;
           if ( temp > 0 )
            break;
  
          temp = psubBlockInfo->parcor[i] + TNS_PARCOR_THRESH;
          if ( temp < 0 )
            break;
        }
        tnsInfo->order[subBlockNumber] = i + 1;
  
        tnsInfo->tnsActive[subBlockNumber] = 1;
        tnsInfo->coefRes[subBlockNumber] = tC.coefRes;
        tnsInfo->length[subBlockNumber] = numOfSfb - tC.tnsStartBand;
  
  
        AnalysisFilterLattice(&(spectrum[tC.tnsStartLine]), (tC.tnsStopLine - tC.tnsStartLine),
                   psubBlockInfo->parcor,
                   tnsInfo->order[subBlockNumber],
                   &(spectrum[tC.tnsStartLine]));
  
      }
    }
  
    return(0);
  }
  
  
  /*****************************************************************************
  *
  * function name: CalcWeightedSpectrum
  * description: Calculate weighted spectrum for LPC calculation
  *
  *****************************************************************************/
  static void CalcWeightedSpectrum(const Word32  spectrum[],         /*!< input spectrum */
                                   Word16        weightedSpectrum[],
                                   Word32       *sfbEnergy,          /*!< sfb energies */
                                   const Word16 *sfbOffset,
                                   Word16        lpcStartLine,
                                   Word16        lpcStopLine,
                                   Word16        lpcStartBand,
                                   Word16        lpcStopBand,
                                   Word32       *pWork32)
  {
      #define INT_BITS_SCAL 1<<(INT_BITS/2)
  
      Word32 i, sfb, shift;
      Word32 maxShift;
      Word32 tmp_s, tmp2_s;
      Word32 tmp, tmp2;
      Word32 maxWS;
      Word32 tnsSfbMean[MAX_SFB];    /* length [lpcStopBand-lpcStartBand] should be sufficient here */
  
      maxWS = 0;
  
      /* calc 1.0*2^-INT_BITS/2/sqrt(en) */
      for( sfb = lpcStartBand; sfb < lpcStopBand; sfb++) {
  
        tmp2 = sfbEnergy[sfb] - 2;
        if( tmp2 > 0) {
          tmp = rsqrt(sfbEnergy[sfb], INT_BITS);
  		if(tmp > INT_BITS_SCAL)
  		{
  			shift =  norm_l(tmp);
  			tmp = Div_32( INT_BITS_SCAL << shift, tmp << shift );
  		}
  		else
  		{
  			tmp = 0x7fffffff;
  		}
        }
        else {
          tmp = 0x7fffffff;
        }
        tnsSfbMean[sfb] = tmp;
      }
  
      /* spread normalized values from sfbs to lines */
      sfb = lpcStartBand;
      tmp = tnsSfbMean[sfb];
      for ( i=lpcStartLine; i<lpcStopLine; i++){
        tmp_s = sfbOffset[sfb + 1] - i;
        if ( tmp_s == 0 ) {
          sfb = sfb + 1;
          tmp2_s = sfb + 1 - lpcStopBand;
          if (tmp2_s <= 0) {
            tmp = tnsSfbMean[sfb];
          }
        }
        pWork32[i] = tmp;
      }
      /*filter down*/
      for (i=(lpcStopLine - 2); i>=lpcStartLine; i--){
          pWork32[i] = (pWork32[i] + pWork32[i + 1]) >> 1;
      }
      /* filter up */
      for (i=(lpcStartLine + 1); i<lpcStopLine; i++){
         pWork32[i] = (pWork32[i] + pWork32[i - 1]) >> 1;
      }
  
      /* weight and normalize */
      for (i=lpcStartLine; i<lpcStopLine; i++){
        pWork32[i] = MULHIGH(pWork32[i], spectrum[i]);
        maxWS |= L_abs(pWork32[i]);
      }
      maxShift = norm_l(maxWS);
  
  	maxShift = 16 - maxShift;
      if(maxShift >= 0)
  	{
  		for (i=lpcStartLine; i<lpcStopLine; i++){
  			weightedSpectrum[i] = pWork32[i] >> maxShift;
  		}
      }
  	else
  	{
  		maxShift = -maxShift;
  		for (i=lpcStartLine; i<lpcStopLine; i++){
  			weightedSpectrum[i] = saturate(pWork32[i] << maxShift);
  		}
  	}
  }
  
  
  
  
  /*****************************************************************************
  *
  * function name: CalcTnsFilter
  * description:  LPC calculation for one TNS filter
  * returns:      prediction gain
  * input:        signal spectrum, acf window, no. of spectral lines,
  *                max. TNS order, ptr. to reflection ocefficients
  * output:       reflection coefficients
  *(half) window size must be larger than tnsOrder !!*
  ******************************************************************************/
  
  static Word16 CalcTnsFilter(const Word16 *signal,
                              const Word32 window[],
                              Word16 numOfLines,
                              Word16 tnsOrder,
                              Word32 parcor[])
  {
    Word32 parcorWorkBuffer[2*TNS_MAX_ORDER+1];
    Word32 predictionGain;
    Word32 i;
    Word32 tnsOrderPlus1 = tnsOrder + 1;
  
    UNUSED(window);
  
    assert(tnsOrder <= TNS_MAX_ORDER);      /* remove asserts later? (btg) */
  
    for(i=0;i<tnsOrder;i++) {
      parcor[i] = 0;
    }
  
    AutoCorrelation(signal, parcorWorkBuffer, numOfLines, tnsOrderPlus1);
  
    /* early return if signal is very low: signal prediction off, with zero parcor coeffs */
    if (parcorWorkBuffer[0] == 0)
      return 0;
  
    predictionGain = AutoToParcor(parcorWorkBuffer, parcor, tnsOrder);
  
    return(predictionGain);
  }
  
  /*****************************************************************************
  *
  * function name: AutoCorrelation
  * description:  calc. autocorrelation (acf)
  * returns:      -
  * input:        input values, no. of input values, no. of acf values
  * output:       acf values
  *
  *****************************************************************************/
  #ifndef ARMV5E
  void AutoCorrelation(const Word16		 input[],
                              Word32       corr[],
                              Word16       samples,
                              Word16       corrCoeff) {
    Word32 i, j, isamples;
    Word32 accu;
    Word32 scf;
  
    scf = 10 - 1;
  
    isamples = samples;
    /* calc first corrCoef:  R[0] = sum { t[i] * t[i] } ; i = 0..N-1 */
    accu = 0;
    for(j=0; j<isamples; j++) {
      accu = L_add(accu, ((input[j] * input[j]) >> scf));
    }
    corr[0] = accu;
  
    /* early termination if all corr coeffs are likely going to be zero */
    if(corr[0] == 0) return ;
  
    /* calc all other corrCoef:  R[j] = sum { t[i] * t[i+j] } ; i = 0..(N-j-1), j=1..p */
    for(i=1; i<corrCoeff; i++) {
      isamples = isamples - 1;
      accu = 0;
      for(j=0; j<isamples; j++) {
        accu = L_add(accu, ((input[j] * input[j+i]) >> scf));
      }
      corr[i] = accu;
    }
  }
  #endif
  
  /*****************************************************************************
  *
  * function name: AutoToParcor
  * description:  conversion autocorrelation to reflection coefficients
  * returns:      prediction gain
  * input:        <order+1> input values, no. of output values (=order),
  *               ptr. to workbuffer (required size: 2*order)
  * output:       <order> reflection coefficients
  *
  *****************************************************************************/
  static Word16 AutoToParcor(Word32 workBuffer[], Word32 reflCoeff[], Word16 numOfCoeff) {
  
    Word32 i, j, shift;
    Word32 *pWorkBuffer; /* temp pointer */
    Word32 predictionGain = 0;
    Word32 num, denom;
    Word32 temp, workBuffer0;
  
  
    num = workBuffer[0];
    temp = workBuffer[numOfCoeff];
  
    for(i=0; i<numOfCoeff-1; i++) {
      workBuffer[i + numOfCoeff] = workBuffer[i + 1];
    }
    workBuffer[i + numOfCoeff] = temp;
  
    for(i=0; i<numOfCoeff; i++) {
      Word32 refc;
  
  
      if (workBuffer[0] < L_abs(workBuffer[i + numOfCoeff])) {
        return 0 ;
      }
  	shift = norm_l(workBuffer[0]);
  	workBuffer0 = Div_32(1 << shift, workBuffer[0] << shift);
      /* calculate refc = -workBuffer[numOfCoeff+i] / workBuffer[0]; -1 <= refc < 1 */
  	refc = L_negate(fixmul(workBuffer[numOfCoeff + i], workBuffer0));
  
      reflCoeff[i] = refc;
  
      pWorkBuffer = &(workBuffer[numOfCoeff]);
  
      for(j=i; j<numOfCoeff; j++) {
        Word32 accu1, accu2;
        accu1 = L_add(pWorkBuffer[j], fixmul(refc, workBuffer[j - i]));
        accu2 = L_add(workBuffer[j - i], fixmul(refc, pWorkBuffer[j]));
        pWorkBuffer[j] = accu1;
        workBuffer[j - i] = accu2;
      }
    }
  
    denom = MULHIGH(workBuffer[0], NORM_COEF);
  
    if (denom != 0) {
      Word32 temp;
  	shift = norm_l(denom);
  	temp = Div_32(1 << shift, denom << shift);
      predictionGain = fixmul(num, temp);
    }
  
    return extract_l(predictionGain);
  }
  
  
  
  static Word16 Search3(Word32 parcor)
  {
    Word32 index = 0;
    Word32 i;
    Word32 temp;
  
    for (i=0;i<8;i++) {
      temp = L_sub( parcor, tnsCoeff3Borders[i]);
      if (temp > 0)
        index=i;
    }
    return extract_l(index - 4);
  }
  
  static Word16 Search4(Word32 parcor)
  {
    Word32 index = 0;
    Word32 i;
    Word32 temp;
  
  
    for (i=0;i<16;i++) {
      temp = L_sub(parcor, tnsCoeff4Borders[i]);
      if (temp > 0)
        index=i;
    }
    return extract_l(index - 8);
  }
  
  
  
  /*****************************************************************************
  *
  * functionname: Parcor2Index
  * description:  quantization index for reflection coefficients
  *
  *****************************************************************************/
  static void Parcor2Index(const Word32 parcor[],   /*!< parcor coefficients */
                           Word16 index[],          /*!< quantized coeff indices */
                           Word16 order,            /*!< filter order */
                           Word16 bitsPerCoeff) {   /*!< quantizer resolution */
    Word32 i;
    Word32 temp;
  
    for(i=0; i<order; i++) {
      temp = bitsPerCoeff - 3;
      if (temp == 0) {
        index[i] = Search3(parcor[i]);
      }
      else {
        index[i] = Search4(parcor[i]);
      }
    }
  }
  
  /*****************************************************************************
  *
  * functionname: Index2Parcor
  * description:  Inverse quantization for reflection coefficients
  *
  *****************************************************************************/
  static void Index2Parcor(const Word16 index[],  /*!< quantized values */
                           Word32 parcor[],       /*!< ptr. to reflection coefficients (output) */
                           Word16 order,          /*!< no. of coefficients */
                           Word16 bitsPerCoeff)   /*!< quantizer resolution */
  {
    Word32 i;
    Word32 temp;
  
    for (i=0; i<order; i++) {
      temp = bitsPerCoeff - 4;
      if ( temp == 0 ) {
          parcor[i] = tnsCoeff4[index[i] + 8];
      }
      else {
          parcor[i] = tnsCoeff3[index[i] + 4];
      }
    }
  }
  
  /*****************************************************************************
  *
  * functionname: FIRLattice
  * description:  in place lattice filtering of spectral data
  * returns:		pointer to modified data
  *
  *****************************************************************************/
  static Word32 FIRLattice(Word16 order,           /*!< filter order */
                           Word32 x,               /*!< spectral data */
                           Word32 *state_par,      /*!< filter states */
                           const Word32 *coef_par) /*!< filter coefficients */
  {
     Word32 i;
     Word32 accu,tmp,tmpSave;
  
     x = x >> 1;
     tmpSave = x;
  
     for (i=0; i<(order - 1); i++) {
  
       tmp = L_add(fixmul(coef_par[i], x), state_par[i]);
       x   = L_add(fixmul(coef_par[i], state_par[i]), x);
  
       state_par[i] = tmpSave;
       tmpSave = tmp;
    }
  
    /* last stage: only need half operations */
    accu = fixmul(state_par[order - 1], coef_par[(order - 1)]);
    state_par[(order - 1)] = tmpSave;
  
    x = L_add(accu, x);
    x = L_add(x, x);
  
    return x;
  }
  
  /*****************************************************************************
  *
  * functionname: AnalysisFilterLattice
  * description:  filters spectral lines with TNS filter
  *
  *****************************************************************************/
  static void AnalysisFilterLattice(const  Word32 signal[],  /*!< input spectrum */
                                    Word16 numOfLines,       /*!< no. of lines */
                                    const  Word32 parCoeff[],/*!< PARC coefficients */
                                    Word16 order,            /*!< filter order */
                                    Word32 output[])         /*!< filtered signal values */
  {
  
    Word32 state_par[TNS_MAX_ORDER];
    Word32 j;
  
    for ( j=0; j<TNS_MAX_ORDER; j++ ) {
      state_par[j] = 0;
    }
  
    for(j=0; j<numOfLines; j++) {
      output[j] = FIRLattice(order,signal[j],state_par,parCoeff);
    }
  }
  
  /*****************************************************************************
  *
  * functionname: ApplyTnsMultTableToRatios
  * description:  Change thresholds according to tns
  *
  *****************************************************************************/
  void ApplyTnsMultTableToRatios(Word16 startCb,
                                 Word16 stopCb,
                                 TNS_SUBBLOCK_INFO subInfo, /*!< TNS subblock info */
                                 Word32 *thresholds)        /*!< thresholds (modified) */
  {
    Word32 i;
    if (subInfo.tnsActive) {
      for(i=startCb; i<stopCb; i++) {
        /* thresholds[i] * 0.25 */
        thresholds[i] = (thresholds[i] >> 2);
      }
    }
  }
  