示例#1
0
void WebRtcIlbcfix_EncodeImpl(
    WebRtc_UWord16 *bytes,     /* (o) encoded data bits iLBC */
    const WebRtc_Word16 *block, /* (i) speech vector to encode */
    iLBC_Enc_Inst_t *iLBCenc_inst /* (i/o) the general encoder
                                     state */
                          ){
  int n, meml_gotten, Nfor, Nback;
  WebRtc_Word16 diff, start_pos;
  int index;
  int subcount, subframe;
  WebRtc_Word16 start_count, end_count;
  WebRtc_Word16 *residual;
  WebRtc_Word32 en1, en2;
  WebRtc_Word16 scale, max;
  WebRtc_Word16 *syntdenum;
  WebRtc_Word16 *decresidual;
  WebRtc_Word16 *reverseResidual;
  WebRtc_Word16 *reverseDecresidual;
  /* Stack based */
  WebRtc_Word16 weightdenum[(LPC_FILTERORDER + 1)*NSUB_MAX];
  WebRtc_Word16 dataVec[BLOCKL_MAX + LPC_FILTERORDER];
  WebRtc_Word16 memVec[CB_MEML+CB_FILTERLEN];
  WebRtc_Word16 bitsMemory[sizeof(iLBC_bits)/sizeof(WebRtc_Word16)];
  iLBC_bits *iLBCbits_inst = (iLBC_bits*)bitsMemory;


#ifdef SPLIT_10MS
  WebRtc_Word16 *weightdenumbuf = iLBCenc_inst->weightdenumbuf;
  WebRtc_Word16 last_bit;
#endif

  WebRtc_Word16 *data = &dataVec[LPC_FILTERORDER];
  WebRtc_Word16 *mem = &memVec[CB_HALFFILTERLEN];

  /* Reuse som buffers to save stack memory */
  residual = &iLBCenc_inst->lpc_buffer[LPC_LOOKBACK+BLOCKL_MAX-iLBCenc_inst->blockl];
  syntdenum = mem;      /* syntdenum[(LPC_FILTERORDER + 1)*NSUB_MAX] and mem are used non overlapping in the code */
  decresidual = residual;     /* Already encoded residual is overwritten by the decoded version */
  reverseResidual = data;     /* data and reverseResidual are used non overlapping in the code */
  reverseDecresidual = reverseResidual; /* Already encoded residual is overwritten by the decoded version */

#ifdef SPLIT_10MS

  WebRtcSpl_MemSetW16 (  (WebRtc_Word16 *) iLBCbits_inst, 0,
                         (WebRtc_Word16) (sizeof(iLBC_bits) / sizeof(WebRtc_Word16))  );

  start_pos = iLBCenc_inst->start_pos;
  diff = iLBCenc_inst->diff;

  if (iLBCenc_inst->section != 0){
    WEBRTC_SPL_MEMCPY_W16 (weightdenum, weightdenumbuf,
                           SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM);
    /* Un-Packetize the frame into parameters */
    last_bit = WebRtcIlbcfix_UnpackBits (iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode);
    if (last_bit)
      return;
    /* adjust index */
    WebRtcIlbcfix_IndexConvDec (iLBCbits_inst->cb_index);

    if (iLBCenc_inst->section == 1){
      /* Save first 80 samples of a 160/240 sample frame for 20/30msec */
      WEBRTC_SPL_MEMCPY_W16 (iLBCenc_inst->past_samples, block, 80);
    }
    else{ // iLBCenc_inst->section == 2 AND mode = 30ms
      /* Save second 80 samples of a 240 sample frame for 30msec */
      WEBRTC_SPL_MEMCPY_W16 (iLBCenc_inst->past_samples + 80, block, 80);
    }
  }
  else{ // iLBCenc_inst->section == 0
    /* form a complete frame of 160/240 for 20msec/30msec mode */
    WEBRTC_SPL_MEMCPY_W16 (data + (iLBCenc_inst->mode * 8) - 80, block, 80);
    WEBRTC_SPL_MEMCPY_W16 (data, iLBCenc_inst->past_samples,
                           (iLBCenc_inst->mode * 8) - 80);
    iLBCenc_inst->Nfor_flag = 0;
    iLBCenc_inst->Nback_flag = 0;
#else
    /* copy input block to data*/
    WEBRTC_SPL_MEMCPY_W16(data,block,iLBCenc_inst->blockl);
#endif

    /* high pass filtering of input signal and scale down the residual (*0.5) */
    WebRtcIlbcfix_HpInput(data, (WebRtc_Word16*)WebRtcIlbcfix_kHpInCoefs,
                          iLBCenc_inst->hpimemy, iLBCenc_inst->hpimemx,
                          iLBCenc_inst->blockl);

    /* LPC of hp filtered input data */
    WebRtcIlbcfix_LpcEncode(syntdenum, weightdenum, iLBCbits_inst->lsf, data,
                            iLBCenc_inst);

    /* Set up state */
    WEBRTC_SPL_MEMCPY_W16(dataVec, iLBCenc_inst->anaMem, LPC_FILTERORDER);

    /* inverse filter to get residual */
    for (n=0; n<iLBCenc_inst->nsub; n++ ) {
      WebRtcSpl_FilterMAFastQ12(
          &data[n*SUBL], &residual[n*SUBL],
          &syntdenum[n*(LPC_FILTERORDER+1)],
          LPC_FILTERORDER+1, SUBL);
    }

    /* Copy the state for next frame */
    WEBRTC_SPL_MEMCPY_W16(iLBCenc_inst->anaMem, &data[iLBCenc_inst->blockl-LPC_FILTERORDER], LPC_FILTERORDER);

    /* find state location */

    iLBCbits_inst->startIdx = WebRtcIlbcfix_FrameClassify(iLBCenc_inst,residual);

    /* check if state should be in first or last part of the
       two subframes */

    index = (iLBCbits_inst->startIdx-1)*SUBL;
    max=WebRtcSpl_MaxAbsValueW16(&residual[index], 2*SUBL);
    scale=WebRtcSpl_GetSizeInBits(WEBRTC_SPL_MUL_16_16(max,max));

    /* Scale to maximum 25 bits so that the MAC won't cause overflow */
    scale = scale - 25;
    if(scale < 0) {
      scale = 0;
    }

    diff = STATE_LEN - iLBCenc_inst->state_short_len;
    en1=WebRtcSpl_DotProductWithScale(&residual[index], &residual[index],
                                      iLBCenc_inst->state_short_len, scale);
    index += diff;
    en2=WebRtcSpl_DotProductWithScale(&residual[index], &residual[index],
                                      iLBCenc_inst->state_short_len, scale);
    if (en1 > en2) {
      iLBCbits_inst->state_first = 1;
      start_pos = (iLBCbits_inst->startIdx-1)*SUBL;
    } else {
      iLBCbits_inst->state_first = 0;
      start_pos = (iLBCbits_inst->startIdx-1)*SUBL + diff;
    }

    /* scalar quantization of state */

    WebRtcIlbcfix_StateSearch(iLBCenc_inst, iLBCbits_inst, &residual[start_pos],
                              &syntdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)],
                              &weightdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)]);

    WebRtcIlbcfix_StateConstruct(iLBCbits_inst->idxForMax, iLBCbits_inst->idxVec,
                                 &syntdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)],
                                 &decresidual[start_pos], iLBCenc_inst->state_short_len
                                 );

    /* predictive quantization in state */

    if (iLBCbits_inst->state_first) { /* put adaptive part in the end */

      /* setup memory */

      WebRtcSpl_MemSetW16(mem, 0, (WebRtc_Word16)(CB_MEML-iLBCenc_inst->state_short_len));
      WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-iLBCenc_inst->state_short_len,
                            decresidual+start_pos, iLBCenc_inst->state_short_len);

      /* encode subframes */

      WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index, iLBCbits_inst->gain_index,
                             &residual[start_pos+iLBCenc_inst->state_short_len],
                             mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL, diff,
                             &weightdenum[iLBCbits_inst->startIdx*(LPC_FILTERORDER+1)], 0);

      /* construct decoded vector */

      WebRtcIlbcfix_CbConstruct(&decresidual[start_pos+iLBCenc_inst->state_short_len],
                                iLBCbits_inst->cb_index, iLBCbits_inst->gain_index,
                                mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL,
                                diff
                                );

    }
    else { /* put adaptive part in the beginning */

      /* create reversed vectors for prediction */

      WebRtcSpl_MemCpyReversedOrder(&reverseResidual[diff-1],
                                    &residual[(iLBCbits_inst->startIdx+1)*SUBL-STATE_LEN], diff);

      /* setup memory */

      meml_gotten = iLBCenc_inst->state_short_len;
      WebRtcSpl_MemCpyReversedOrder(&mem[CB_MEML-1], &decresidual[start_pos], meml_gotten);
      WebRtcSpl_MemSetW16(mem, 0, (WebRtc_Word16)(CB_MEML-iLBCenc_inst->state_short_len));

      /* encode subframes */
      WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index, iLBCbits_inst->gain_index,
                             reverseResidual, mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL, diff,
                             &weightdenum[(iLBCbits_inst->startIdx-1)*(LPC_FILTERORDER+1)],
                             0);

      /* construct decoded vector */

      WebRtcIlbcfix_CbConstruct(reverseDecresidual,
                                iLBCbits_inst->cb_index, iLBCbits_inst->gain_index,
                                mem+CB_MEML-ST_MEM_L_TBL, ST_MEM_L_TBL,
                                diff
                                );

      /* get decoded residual from reversed vector */

      WebRtcSpl_MemCpyReversedOrder(&decresidual[start_pos-1], reverseDecresidual, diff);
    }

#ifdef SPLIT_10MS
    iLBCenc_inst->start_pos = start_pos;
    iLBCenc_inst->diff = diff;
    iLBCenc_inst->section++;
    /* adjust index */
    WebRtcIlbcfix_IndexConvEnc (iLBCbits_inst->cb_index);
    /* Packetize the parameters into the frame */
    WebRtcIlbcfix_PackBits (iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode);
    WEBRTC_SPL_MEMCPY_W16 (weightdenumbuf, weightdenum,
                           SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM);
    return;
  }
#endif

  /* forward prediction of subframes */

  Nfor = iLBCenc_inst->nsub-iLBCbits_inst->startIdx-1;

  /* counter for predicted subframes */
#ifdef SPLIT_10MS
  if (iLBCenc_inst->mode == 20)
  {
    subcount = 1;
  }
  if (iLBCenc_inst->mode == 30)
  {
    if (iLBCenc_inst->section == 1)
    {
      subcount = 1;
    }
    if (iLBCenc_inst->section == 2)
    {
      subcount = 3;
    }
  }
#else
  subcount=1;
#endif

  if( Nfor > 0 ){

    /* setup memory */

    WebRtcSpl_MemSetW16(mem, 0, CB_MEML-STATE_LEN);
    WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-STATE_LEN,
                          decresidual+(iLBCbits_inst->startIdx-1)*SUBL, STATE_LEN);

#ifdef SPLIT_10MS
    if (iLBCenc_inst->Nfor_flag > 0)
    {
      for (subframe = 0; subframe < WEBRTC_SPL_MIN (Nfor, 2); subframe++)
      {
        /* update memory */
        WEBRTC_SPL_MEMCPY_W16 (mem, mem + SUBL, (CB_MEML - SUBL));
        WEBRTC_SPL_MEMCPY_W16 (mem + CB_MEML - SUBL,
                               &decresidual[(iLBCbits_inst->startIdx + 1 +
                                             subframe) * SUBL], SUBL);
      }
    }

    iLBCenc_inst->Nfor_flag++;

    if (iLBCenc_inst->mode == 20)
    {
      start_count = 0;
      end_count = Nfor;
    }
    if (iLBCenc_inst->mode == 30)
    {
      if (iLBCenc_inst->section == 1)
      {
        start_count = 0;
        end_count = WEBRTC_SPL_MIN (Nfor, 2);
      }
      if (iLBCenc_inst->section == 2)
      {
        start_count = WEBRTC_SPL_MIN (Nfor, 2);
        end_count = Nfor;
      }
    }
#else
    start_count = 0;
    end_count = (WebRtc_Word16)Nfor;
#endif

    /* loop over subframes to encode */

    for (subframe = start_count; subframe < end_count; subframe++){

      /* encode subframe */

      WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index+subcount*CB_NSTAGES,
                             iLBCbits_inst->gain_index+subcount*CB_NSTAGES,
                             &residual[(iLBCbits_inst->startIdx+1+subframe)*SUBL],
                             mem, MEM_LF_TBL, SUBL,
                             &weightdenum[(iLBCbits_inst->startIdx+1+subframe)*(LPC_FILTERORDER+1)],
                             (WebRtc_Word16)subcount);

      /* construct decoded vector */

      WebRtcIlbcfix_CbConstruct(&decresidual[(iLBCbits_inst->startIdx+1+subframe)*SUBL],
                                iLBCbits_inst->cb_index+subcount*CB_NSTAGES,
                                iLBCbits_inst->gain_index+subcount*CB_NSTAGES,
                                mem, MEM_LF_TBL,
                                SUBL
                                );

      /* update memory */

      WEBRTC_SPL_MEMMOVE_W16(mem, mem+SUBL, (CB_MEML-SUBL));
      WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-SUBL,
                            &decresidual[(iLBCbits_inst->startIdx+1+subframe)*SUBL], SUBL);

      subcount++;
    }
  }

#ifdef SPLIT_10MS
  if ((iLBCenc_inst->section == 1) &&
      (iLBCenc_inst->mode == 30) && (Nfor > 0) && (end_count == 2))
  {
    iLBCenc_inst->section++;
    /* adjust index */
    WebRtcIlbcfix_IndexConvEnc (iLBCbits_inst->cb_index);
    /* Packetize the parameters into the frame */
    WebRtcIlbcfix_PackBits (iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode);
    WEBRTC_SPL_MEMCPY_W16 (weightdenumbuf, weightdenum,
                           SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM);
    return;
  }
#endif

  /* backward prediction of subframes */

  Nback = iLBCbits_inst->startIdx-1;

  if( Nback > 0 ){

    /* create reverse order vectors
       (The decresidual does not need to be copied since it is
       contained in the same vector as the residual)
    */

    WebRtcSpl_MemCpyReversedOrder(&reverseResidual[Nback*SUBL-1], residual, Nback*SUBL);

    /* setup memory */

    meml_gotten = SUBL*(iLBCenc_inst->nsub+1-iLBCbits_inst->startIdx);
    if( meml_gotten > CB_MEML ) {
      meml_gotten=CB_MEML;
    }

    WebRtcSpl_MemCpyReversedOrder(&mem[CB_MEML-1], &decresidual[Nback*SUBL], meml_gotten);
    WebRtcSpl_MemSetW16(mem, 0, (WebRtc_Word16)(CB_MEML-meml_gotten));

#ifdef SPLIT_10MS
    if (iLBCenc_inst->Nback_flag > 0)
    {
      for (subframe = 0; subframe < WEBRTC_SPL_MAX (2 - Nfor, 0); subframe++)
      {
        /* update memory */
        WEBRTC_SPL_MEMCPY_W16 (mem, mem + SUBL, (CB_MEML - SUBL));
        WEBRTC_SPL_MEMCPY_W16 (mem + CB_MEML - SUBL,
                               &reverseDecresidual[subframe * SUBL], SUBL);
      }
    }

    iLBCenc_inst->Nback_flag++;


    if (iLBCenc_inst->mode == 20)
    {
      start_count = 0;
      end_count = Nback;
    }
    if (iLBCenc_inst->mode == 30)
    {
      if (iLBCenc_inst->section == 1)
      {
        start_count = 0;
        end_count = WEBRTC_SPL_MAX (2 - Nfor, 0);
      }
      if (iLBCenc_inst->section == 2)
      {
        start_count = WEBRTC_SPL_MAX (2 - Nfor, 0);
        end_count = Nback;
      }
    }
#else
    start_count = 0;
    end_count = (WebRtc_Word16)Nback;
#endif

    /* loop over subframes to encode */

    for (subframe = start_count; subframe < end_count; subframe++){

      /* encode subframe */

      WebRtcIlbcfix_CbSearch(iLBCenc_inst, iLBCbits_inst->cb_index+subcount*CB_NSTAGES,
                             iLBCbits_inst->gain_index+subcount*CB_NSTAGES, &reverseResidual[subframe*SUBL],
                             mem, MEM_LF_TBL, SUBL,
                             &weightdenum[(iLBCbits_inst->startIdx-2-subframe)*(LPC_FILTERORDER+1)],
                             (WebRtc_Word16)subcount);

      /* construct decoded vector */

      WebRtcIlbcfix_CbConstruct(&reverseDecresidual[subframe*SUBL],
                                iLBCbits_inst->cb_index+subcount*CB_NSTAGES,
                                iLBCbits_inst->gain_index+subcount*CB_NSTAGES,
                                mem, MEM_LF_TBL, SUBL
                                );

      /* update memory */

      WEBRTC_SPL_MEMMOVE_W16(mem, mem+SUBL, (CB_MEML-SUBL));
      WEBRTC_SPL_MEMCPY_W16(mem+CB_MEML-SUBL,
                            &reverseDecresidual[subframe*SUBL], SUBL);

      subcount++;

    }

    /* get decoded residual from reversed vector */

    WebRtcSpl_MemCpyReversedOrder(&decresidual[SUBL*Nback-1], reverseDecresidual, SUBL*Nback);
  }
  /* end encoding part */

  /* adjust index */

  WebRtcIlbcfix_IndexConvEnc(iLBCbits_inst->cb_index);

  /* Packetize the parameters into the frame */

#ifdef SPLIT_10MS
  if( (iLBCenc_inst->mode==30) && (iLBCenc_inst->section==1) ){
    WebRtcIlbcfix_PackBits(iLBCenc_inst->bytes, iLBCbits_inst, iLBCenc_inst->mode);
  }
  else{
    WebRtcIlbcfix_PackBits(bytes, iLBCbits_inst, iLBCenc_inst->mode);
  }
#else
  WebRtcIlbcfix_PackBits(bytes, iLBCbits_inst, iLBCenc_inst->mode);
#endif

#ifndef WEBRTC_BIG_ENDIAN
  /* Swap bytes for LITTLE ENDIAN since the packbits()
     function assumes BIG_ENDIAN machine */
#ifdef SPLIT_10MS
  if (( (iLBCenc_inst->section == 1) && (iLBCenc_inst->mode == 20) ) ||
      ( (iLBCenc_inst->section == 2) && (iLBCenc_inst->mode == 30) )){
    WebRtcIlbcfix_SwapBytes(bytes, iLBCenc_inst->no_of_words, bytes);
  }
#else
  WebRtcIlbcfix_SwapBytes(bytes, iLBCenc_inst->no_of_words, bytes);
#endif
#endif

#ifdef SPLIT_10MS
  if (subcount == (iLBCenc_inst->nsub - 1))
  {
    iLBCenc_inst->section = 0;
  }
  else
  {
    iLBCenc_inst->section++;
    WEBRTC_SPL_MEMCPY_W16 (weightdenumbuf, weightdenum,
                           SCRATCH_ENCODE_DATAVEC - SCRATCH_ENCODE_WEIGHTDENUM);
  }
#endif

}
示例#2
0
void WebRtcIlbcfix_DecodeImpl(
    int16_t *decblock,    /* (o) decoded signal block */
    const uint16_t *bytes, /* (i) encoded signal bits */
    iLBC_Dec_Inst_t *iLBCdec_inst, /* (i/o) the decoder state
                                           structure */
    int16_t mode      /* (i) 0: bad packet, PLC,
                                                                   1: normal */
                           ) {
  int i;
  int16_t order_plus_one;

  int16_t last_bit;
  int16_t *data;
  /* Stack based */
  int16_t decresidual[BLOCKL_MAX];
  int16_t PLCresidual[BLOCKL_MAX + LPC_FILTERORDER];
  int16_t syntdenum[NSUB_MAX*(LPC_FILTERORDER+1)];
  int16_t PLClpc[LPC_FILTERORDER + 1];
#ifndef WEBRTC_ARCH_BIG_ENDIAN
  uint16_t swapped[NO_OF_WORDS_30MS];
#endif
  iLBC_bits *iLBCbits_inst = (iLBC_bits*)PLCresidual;

  /* Reuse some buffers that are non overlapping in order to save stack memory */
  data = &PLCresidual[LPC_FILTERORDER];

  if (mode) { /* the data are good */

    /* decode data */

    /* Unpacketize bits into parameters */

#ifndef WEBRTC_ARCH_BIG_ENDIAN
    WebRtcIlbcfix_SwapBytes(bytes, iLBCdec_inst->no_of_words, swapped);
    last_bit = WebRtcIlbcfix_UnpackBits(swapped, iLBCbits_inst, iLBCdec_inst->mode);
#else
    last_bit = WebRtcIlbcfix_UnpackBits(bytes, iLBCbits_inst, iLBCdec_inst->mode);
#endif

    /* Check for bit errors */
    if (iLBCbits_inst->startIdx<1)
      mode = 0;
    if ((iLBCdec_inst->mode==20) && (iLBCbits_inst->startIdx>3))
      mode = 0;
    if ((iLBCdec_inst->mode==30) && (iLBCbits_inst->startIdx>5))
      mode = 0;
    if (last_bit==1)
      mode = 0;

    if (mode) { /* No bit errors was detected, continue decoding */
      /* Stack based */
      int16_t lsfdeq[LPC_FILTERORDER*LPC_N_MAX];
      int16_t weightdenum[(LPC_FILTERORDER + 1)*NSUB_MAX];

      /* adjust index */
      WebRtcIlbcfix_IndexConvDec(iLBCbits_inst->cb_index);

      /* decode the lsf */
      WebRtcIlbcfix_SimpleLsfDeQ(lsfdeq, (int16_t*)(iLBCbits_inst->lsf), iLBCdec_inst->lpc_n);
      WebRtcIlbcfix_LsfCheck(lsfdeq, LPC_FILTERORDER, iLBCdec_inst->lpc_n);
      WebRtcIlbcfix_DecoderInterpolateLsp(syntdenum, weightdenum,
                                          lsfdeq, LPC_FILTERORDER, iLBCdec_inst);

      /* Decode the residual using the cb and gain indexes */
      WebRtcIlbcfix_DecodeResidual(iLBCdec_inst, iLBCbits_inst, decresidual, syntdenum);

      /* preparing the plc for a future loss! */
      WebRtcIlbcfix_DoThePlc( PLCresidual, PLClpc, 0,
                              decresidual, syntdenum + (LPC_FILTERORDER + 1)*(iLBCdec_inst->nsub - 1),
                              (int16_t)(iLBCdec_inst->last_lag), iLBCdec_inst);

      /* Use the output from doThePLC */
      WEBRTC_SPL_MEMCPY_W16(decresidual, PLCresidual, iLBCdec_inst->blockl);
    }

  }

  if (mode == 0) {
    /* the data is bad (either a PLC call
     * was made or a bit error was detected)
     */

    /* packet loss conceal */

    WebRtcIlbcfix_DoThePlc( PLCresidual, PLClpc, 1,
                            decresidual, syntdenum, (int16_t)(iLBCdec_inst->last_lag), iLBCdec_inst);

    WEBRTC_SPL_MEMCPY_W16(decresidual, PLCresidual, iLBCdec_inst->blockl);

    order_plus_one = LPC_FILTERORDER + 1;

    for (i = 0; i < iLBCdec_inst->nsub; i++) {
      WEBRTC_SPL_MEMCPY_W16(syntdenum+(i*order_plus_one),
                            PLClpc, order_plus_one);
    }
  }

  if ((*iLBCdec_inst).use_enhancer == 1) { /* Enhancer activated */

    /* Update the filter and filter coefficients if there was a packet loss */
    if (iLBCdec_inst->prev_enh_pl==2) {
      for (i=0;i<iLBCdec_inst->nsub;i++) {
        WEBRTC_SPL_MEMCPY_W16(&(iLBCdec_inst->old_syntdenum[i*(LPC_FILTERORDER+1)]),
                              syntdenum, (LPC_FILTERORDER+1));
      }
    }

    /* post filtering */
    (*iLBCdec_inst).last_lag =
        WebRtcIlbcfix_EnhancerInterface(data, decresidual, iLBCdec_inst);

    /* synthesis filtering */

    /* Set up the filter state */
    WEBRTC_SPL_MEMCPY_W16(&data[-LPC_FILTERORDER], iLBCdec_inst->syntMem, LPC_FILTERORDER);

    if (iLBCdec_inst->mode==20) {
      /* Enhancer has 40 samples delay */
      i=0;
      WebRtcSpl_FilterARFastQ12(
          data, data,
          iLBCdec_inst->old_syntdenum + (i+iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1),
          LPC_FILTERORDER+1, SUBL);

      for (i=1; i < iLBCdec_inst->nsub; i++) {
        WebRtcSpl_FilterARFastQ12(
            data+i*SUBL, data+i*SUBL,
            syntdenum+(i-1)*(LPC_FILTERORDER+1),
            LPC_FILTERORDER+1, SUBL);
      }

    } else if (iLBCdec_inst->mode==30) {
      /* Enhancer has 80 samples delay */
      for (i=0; i < 2; i++) {
        WebRtcSpl_FilterARFastQ12(
            data+i*SUBL, data+i*SUBL,
            iLBCdec_inst->old_syntdenum + (i+4)*(LPC_FILTERORDER+1),
            LPC_FILTERORDER+1, SUBL);
      }
      for (i=2; i < iLBCdec_inst->nsub; i++) {
        WebRtcSpl_FilterARFastQ12(
            data+i*SUBL, data+i*SUBL,
            syntdenum+(i-2)*(LPC_FILTERORDER+1),
            LPC_FILTERORDER+1, SUBL);
      }
    }

    /* Save the filter state */
    WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &data[iLBCdec_inst->blockl-LPC_FILTERORDER], LPC_FILTERORDER);

  } else { /* Enhancer not activated */
    int16_t lag;

    /* Find last lag (since the enhancer is not called to give this info) */
    lag = 20;
    if (iLBCdec_inst->mode==20) {
      lag = (int16_t)WebRtcIlbcfix_XcorrCoef(
          &decresidual[iLBCdec_inst->blockl-60],
          &decresidual[iLBCdec_inst->blockl-60-lag],
          60,
          80, lag, -1);
    } else {
      lag = (int16_t)WebRtcIlbcfix_XcorrCoef(
          &decresidual[iLBCdec_inst->blockl-ENH_BLOCKL],
          &decresidual[iLBCdec_inst->blockl-ENH_BLOCKL-lag],
          ENH_BLOCKL,
          100, lag, -1);
    }

    /* Store lag (it is needed if next packet is lost) */
    (*iLBCdec_inst).last_lag = (int)lag;

    /* copy data and run synthesis filter */
    WEBRTC_SPL_MEMCPY_W16(data, decresidual, iLBCdec_inst->blockl);

    /* Set up the filter state */
    WEBRTC_SPL_MEMCPY_W16(&data[-LPC_FILTERORDER], iLBCdec_inst->syntMem, LPC_FILTERORDER);

    for (i=0; i < iLBCdec_inst->nsub; i++) {
      WebRtcSpl_FilterARFastQ12(
          data+i*SUBL, data+i*SUBL,
          syntdenum + i*(LPC_FILTERORDER+1),
          LPC_FILTERORDER+1, SUBL);
    }

    /* Save the filter state */
    WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &data[iLBCdec_inst->blockl-LPC_FILTERORDER], LPC_FILTERORDER);
  }

  WEBRTC_SPL_MEMCPY_W16(decblock,data,iLBCdec_inst->blockl);

  /* High pass filter the signal (with upscaling a factor 2 and saturation) */
  WebRtcIlbcfix_HpOutput(decblock, (int16_t*)WebRtcIlbcfix_kHpOutCoefs,
                         iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx,
                         iLBCdec_inst->blockl);

  WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->old_syntdenum,
                        syntdenum, iLBCdec_inst->nsub*(LPC_FILTERORDER+1));

  iLBCdec_inst->prev_enh_pl=0;

  if (mode==0) { /* PLC was used */
    iLBCdec_inst->prev_enh_pl=1;
  }
}