/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

/*
 * encode.c
 *
 * This file contains definition of funtions for encoding.
 * Decoding of upper-band, including 8-12 kHz, when the bandwidth is
 * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz.
 *
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "structs.h"
#include "codec.h"
#include "pitch_estimator.h"
#include "entropy_coding.h"
#include "arith_routines.h"
#include "pitch_gain_tables.h"
#include "pitch_lag_tables.h"
#include "spectrum_ar_model_tables.h"
#include "lpc_tables.h"
#include "lpc_analysis.h"
#include "bandwidth_estimator.h"
#include "lpc_shape_swb12_tables.h"
#include "lpc_shape_swb16_tables.h"
#include "lpc_gain_swb_tables.h"


#define UB_LOOKAHEAD 24


/*
  Rate allocation tables of lower and upper-band bottleneck for
  12kHz & 16kHz bandwidth.

  12 kHz bandwidth
  -----------------
  The overall bottleneck of the coder is between 38 kbps and 45 kbps. We have
  considered 7 enteries, uniformly distributed in this interval, i.e. 38,
  39.17, 40.33, 41.5, 42.67, 43.83 and 45. For every entery, the lower-band
  and the upper-band bottlenecks are specified in
  'kLowerBandBitRate12' and 'kUpperBandBitRate12'
  tables, respectively. E.g. the overall rate of 41.5 kbps corresponts to a
  bottleneck of 31 kbps for lower-band and 27 kbps for upper-band. Given an
  overall bottleneck of the codec, we use linear interpolation to get
  lower-band and upper-band bottlenecks.

  16 kHz bandwidth
  -----------------
  The overall bottleneck of the coder is between 50 kbps and 56 kbps. We have
  considered 7 enteries, uniformly distributed in this interval, i.e. 50, 51.2,
  52.4, 53.6, 54.8 and 56. For every entery, the lower-band and the upper-band
  bottlenecks are specified in 'kLowerBandBitRate16' and
  'kUpperBandBitRate16' tables, respectively. E.g. the overall rate
  of 53.6 kbps corresponts to a bottleneck of 32 kbps for lower-band and 30
  kbps for upper-band. Given an overall bottleneck of the codec, we use linear
  interpolation to get lower-band and upper-band bottlenecks.

 */

/*     38  39.17  40.33   41.5  42.67  43.83     45 */
static const int16_t kLowerBandBitRate12[7] = {
    29000, 30000, 30000, 31000, 31000, 32000, 32000 };
static const int16_t kUpperBandBitRate12[7] = {
    25000, 25000, 27000, 27000, 29000, 29000, 32000 };

/*    50     51.2  52.4   53.6   54.8    56 */
static const int16_t kLowerBandBitRate16[6] = {
    31000, 31000, 32000, 32000, 32000, 32000 };
static const int16_t kUpperBandBitRate16[6] = {
    28000, 29000, 29000, 30000, 31000, 32000 };

/******************************************************************************
 * WebRtcIsac_RateAllocation()
 * Internal function to perform a rate-allocation for upper and lower-band,
 * given a total rate.
 *
 * Input:
 *   - inRateBitPerSec           : a total bottleneck in bits/sec.
 *
 * Output:
 *   - rateLBBitPerSec           : a bottleneck allocated to the lower-band
 *                                 in bits/sec.
 *   - rateUBBitPerSec           : a bottleneck allocated to the upper-band
 *                                 in bits/sec.
 *
 * Return value                  : 0 if rate allocation has been successful.
 *                                -1 if failed to allocate rates.
 */

int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec,
                                        double* rateLBBitPerSec,
                                        double* rateUBBitPerSec,
                                        enum ISACBandwidth* bandwidthKHz) {
  int16_t idx;
  double idxD;
  double idxErr;
  if (inRateBitPerSec < 38000) {
    /* If the given overall bottleneck is less than 38000 then
     * then codec has to operate in wideband mode, i.e. 8 kHz
     * bandwidth. */
    *rateLBBitPerSec = (int16_t)((inRateBitPerSec > 32000) ?
        32000 : inRateBitPerSec);
    *rateUBBitPerSec = 0;
    *bandwidthKHz = isac8kHz;
  } else if ((inRateBitPerSec >= 38000) && (inRateBitPerSec < 50000)) {
    /* At a bottleneck between 38 and 50 kbps the codec is operating
     * at 12 kHz bandwidth. Using xxxBandBitRate12[] to calculates
     * upper/lower bottleneck */

    /* Find the bottlenecks by linear interpolation,
     * step is (45000 - 38000)/6.0 we use the inverse of it. */
    const double stepSizeInv = 8.5714286e-4;
    idxD = (inRateBitPerSec - 38000) * stepSizeInv;
    idx = (idxD >= 6) ? 6 : ((int16_t)idxD);
    idxErr = idxD - idx;
    *rateLBBitPerSec = kLowerBandBitRate12[idx];
    *rateUBBitPerSec = kUpperBandBitRate12[idx];

    if (idx < 6) {
      *rateLBBitPerSec += (int16_t)(
          idxErr * (kLowerBandBitRate12[idx + 1] - kLowerBandBitRate12[idx]));
      *rateUBBitPerSec += (int16_t)(
          idxErr * (kUpperBandBitRate12[idx + 1] - kUpperBandBitRate12[idx]));
    }
    *bandwidthKHz = isac12kHz;
  } else if ((inRateBitPerSec >= 50000) && (inRateBitPerSec <= 56000)) {
    /* A bottleneck between 50 and 56 kbps corresponds to bandwidth
     * of 16 kHz. Using xxxBandBitRate16[] to calculates
     * upper/lower bottleneck. */

    /* Find the bottlenecks by linear interpolation
     * step is (56000 - 50000)/5 we use the inverse of it. */
    const double stepSizeInv = 8.3333333e-4;
    idxD = (inRateBitPerSec - 50000) * stepSizeInv;
    idx = (idxD >= 5) ? 5 : ((int16_t)idxD);
    idxErr = idxD - idx;
    *rateLBBitPerSec = kLowerBandBitRate16[idx];
    *rateUBBitPerSec  = kUpperBandBitRate16[idx];

    if (idx < 5) {
      *rateLBBitPerSec += (int16_t)(idxErr *
          (kLowerBandBitRate16[idx + 1] -
              kLowerBandBitRate16[idx]));

      *rateUBBitPerSec += (int16_t)(idxErr *
          (kUpperBandBitRate16[idx + 1] -
              kUpperBandBitRate16[idx]));
    }
    *bandwidthKHz = isac16kHz;
  } else {
    /* Out-of-range botlteneck value. */
    return -1;
  }

  /* limit the values. */
  *rateLBBitPerSec = (*rateLBBitPerSec > 32000) ? 32000 : *rateLBBitPerSec;
  *rateUBBitPerSec = (*rateUBBitPerSec > 32000) ? 32000 : *rateUBBitPerSec;
  return 0;
}


void WebRtcIsac_ResetBitstream(Bitstr* bit_stream) {
  bit_stream->W_upper = 0xFFFFFFFF;
  bit_stream->stream_index = 0;
  bit_stream->streamval = 0;
}

int WebRtcIsac_EncodeLb(float* in, ISACLBEncStruct* ISACencLB_obj,
                        int16_t codingMode,
                        int16_t bottleneckIndex) {
  int stream_length = 0;
  int err;
  int k;
  int iterCntr;

  double lofilt_coef[(ORDERLO + 1)*SUBFRAMES];
  double hifilt_coef[(ORDERHI + 1)*SUBFRAMES];
  float LP[FRAMESAMPLES_HALF];
  float HP[FRAMESAMPLES_HALF];

  double LP_lookahead[FRAMESAMPLES_HALF];
  double HP_lookahead[FRAMESAMPLES_HALF];
  double LP_lookahead_pf[FRAMESAMPLES_HALF + QLOOKAHEAD];
  double LPw[FRAMESAMPLES_HALF];

  double HPw[FRAMESAMPLES_HALF];
  double LPw_pf[FRAMESAMPLES_HALF];
  int16_t fre[FRAMESAMPLES_HALF];   /* Q7 */
  int16_t fim[FRAMESAMPLES_HALF];   /* Q7 */

  double PitchLags[4];
  double PitchGains[4];
  int16_t PitchGains_Q12[4];
  int16_t AvgPitchGain_Q12;

  int frame_mode; /* 0 for 30ms, 1 for 60ms */
  int status = 0;
  int my_index;
  transcode_obj transcodingParam;
  double bytesLeftSpecCoding;
  uint16_t payloadLimitBytes;

  /* Copy new frame-length and bottleneck rate only for the first 10 ms data */
  if (ISACencLB_obj->buffer_index == 0) {
    /* Set the framelength for the next packet. */
    ISACencLB_obj->current_framesamples = ISACencLB_obj->new_framelength;
  }
  /* 'frame_mode' is 0 (30 ms) or 1 (60 ms). */
  frame_mode = ISACencLB_obj->current_framesamples / MAX_FRAMESAMPLES;

  /* buffer speech samples (by 10ms packet) until the frame-length */
  /* is reached (30 or 60 ms).                                     */
  /*****************************************************************/

  /* fill the buffer with 10ms input data */
  for (k = 0; k < FRAMESAMPLES_10ms; k++) {
    ISACencLB_obj->data_buffer_float[k + ISACencLB_obj->buffer_index] = in[k];
  }

  /* If buffersize is not equal to current framesize then increase index
   * and return. We do no encoding untill we have enough audio.  */
  if (ISACencLB_obj->buffer_index + FRAMESAMPLES_10ms != FRAMESAMPLES) {
    ISACencLB_obj->buffer_index += FRAMESAMPLES_10ms;
    return 0;
  }
  /* If buffer reached the right size, reset index and continue with
   * encoding the frame. */
  ISACencLB_obj->buffer_index = 0;

  /* End of buffer function. */
  /**************************/

  /* Encoding */
  /************/

  if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0) {
    /* This is to avoid Linux warnings until we change 'int' to 'Word32'
     * at all places. */
    int intVar;
    /* reset bitstream */
    WebRtcIsac_ResetBitstream(&(ISACencLB_obj->bitstr_obj));

    if ((codingMode == 0) && (frame_mode == 0) &&
        (ISACencLB_obj->enforceFrameSize == 0)) {
      ISACencLB_obj->new_framelength = WebRtcIsac_GetNewFrameLength(
          ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples);
    }

    ISACencLB_obj->s2nr = WebRtcIsac_GetSnr(
        ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples);

    /* Encode frame length. */
    status = WebRtcIsac_EncodeFrameLen(
        ISACencLB_obj->current_framesamples, &ISACencLB_obj->bitstr_obj);
    if (status < 0) {
      /* Wrong frame size. */
      return status;
    }
    /* Save framelength for multiple packets memory. */
    ISACencLB_obj->SaveEnc_obj.framelength =
        ISACencLB_obj->current_framesamples;

    /* To be used for Redundant Coding. */
    ISACencLB_obj->lastBWIdx = bottleneckIndex;
    intVar = (int)bottleneckIndex;
    WebRtcIsac_EncodeReceiveBw(&intVar, &ISACencLB_obj->bitstr_obj);
  }

  /* Split signal in two bands. */
  WebRtcIsac_SplitAndFilterFloat(ISACencLB_obj->data_buffer_float, LP, HP,
                                 LP_lookahead, HP_lookahead,
                                 &ISACencLB_obj->prefiltbankstr_obj);

  /* estimate pitch parameters and pitch-filter lookahead signal */
  WebRtcIsac_PitchAnalysis(LP_lookahead, LP_lookahead_pf,
                           &ISACencLB_obj->pitchanalysisstr_obj, PitchLags,
                           PitchGains);

  /* Encode in FIX Q12. */

  /* Convert PitchGain to Fixed point. */
  for (k = 0; k < PITCH_SUBFRAMES; k++) {
    PitchGains_Q12[k] = (int16_t)(PitchGains[k] * 4096.0);
  }

  /* Set where to store data in multiple packets memory. */
  if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0) {
    ISACencLB_obj->SaveEnc_obj.startIdx = 0;
  } else {
    ISACencLB_obj->SaveEnc_obj.startIdx = 1;
  }

  /* Quantize & encode pitch parameters. */
  WebRtcIsac_EncodePitchGain(PitchGains_Q12, &ISACencLB_obj->bitstr_obj,
                             &ISACencLB_obj->SaveEnc_obj);
  WebRtcIsac_EncodePitchLag(PitchLags, PitchGains_Q12,
                            &ISACencLB_obj->bitstr_obj,
                            &ISACencLB_obj->SaveEnc_obj);

  AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] +
      PitchGains_Q12[2] + PitchGains_Q12[3]) >> 2;

  /* Find coefficients for perceptual pre-filters. */
  WebRtcIsac_GetLpcCoefLb(LP_lookahead_pf, HP_lookahead,
                          &ISACencLB_obj->maskfiltstr_obj, ISACencLB_obj->s2nr,
                          PitchGains_Q12, lofilt_coef, hifilt_coef);

  /* Code LPC model and shape - gains not quantized yet. */
  WebRtcIsac_EncodeLpcLb(lofilt_coef, hifilt_coef, &ISACencLB_obj->bitstr_obj,
                         &ISACencLB_obj->SaveEnc_obj);

  /* Convert PitchGains back to FLOAT for pitchfilter_pre. */
  for (k = 0; k < 4; k++) {
    PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096;
  }

  /* Store the state of arithmetic coder before coding LPC gains. */
  transcodingParam.W_upper = ISACencLB_obj->bitstr_obj.W_upper;
  transcodingParam.stream_index = ISACencLB_obj->bitstr_obj.stream_index;
  transcodingParam.streamval = ISACencLB_obj->bitstr_obj.streamval;
  transcodingParam.stream[0] =
      ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index -
                                       2];
  transcodingParam.stream[1] =
      ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index -
                                       1];
  transcodingParam.stream[2] =
      ISACencLB_obj->bitstr_obj.stream[ISACencLB_obj->bitstr_obj.stream_index];

  /* Store LPC Gains before encoding them. */
  for (k = 0; k < SUBFRAMES; k++) {
    transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER + 1) * k];
    transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER + 1) * k];
  }

  /* Code gains */
  WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef,
                             &ISACencLB_obj->bitstr_obj,
                             &ISACencLB_obj->SaveEnc_obj);

  /* Get the correct value for the payload limit and calculate the
   * number of bytes left for coding the spectrum. */
  if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
    /* It is a 60ms and we are in the first 30ms then the limit at
     * this point should be half of the assigned value. */
    payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 >> 1;
  } else if (frame_mode == 0) {
    /* It is a 30ms frame */
    /* Subract 3 because termination process may add 3 bytes. */
    payloadLimitBytes = ISACencLB_obj->payloadLimitBytes30 - 3;
  } else {
    /* This is the second half of a 60ms frame. */
    /* Subract 3 because termination process may add 3 bytes. */
    payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 - 3;
  }
  bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index;

  /* Perceptual pre-filtering (using normalized lattice filter). */
  /* Low-band filtering. */
  WebRtcIsac_NormLatticeFilterMa(ORDERLO,
                                 ISACencLB_obj->maskfiltstr_obj.PreStateLoF,
                                 ISACencLB_obj->maskfiltstr_obj.PreStateLoG,
                                 LP, lofilt_coef, LPw);
  /* High-band filtering. */
  WebRtcIsac_NormLatticeFilterMa(ORDERHI,
                                 ISACencLB_obj->maskfiltstr_obj.PreStateHiF,
                                 ISACencLB_obj->maskfiltstr_obj.PreStateHiG,
                                 HP, hifilt_coef, HPw);
  /* Pitch filter. */
  WebRtcIsac_PitchfilterPre(LPw, LPw_pf, &ISACencLB_obj->pitchfiltstr_obj,
                            PitchLags, PitchGains);
  /* Transform */
  WebRtcIsac_Time2Spec(LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj);

  /* Save data for multiple packets memory. */
  my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF;
  memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre));
  memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim));

  ISACencLB_obj->SaveEnc_obj.AvgPitchGain[ISACencLB_obj->SaveEnc_obj.startIdx] =
      AvgPitchGain_Q12;

  /* Quantization and loss-less coding. */
  err = WebRtcIsac_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand,
                              &ISACencLB_obj->bitstr_obj);
  if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
    /* There has been an error but it was not too large payload
       (we can cure too large payload). */
    if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
      /* If this is the second 30ms of a 60ms frame reset
         this such that in the next call encoder starts fresh. */
      ISACencLB_obj->frame_nb = 0;
    }
    return err;
  }
  iterCntr = 0;
  while ((ISACencLB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
      (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
    double bytesSpecCoderUsed;
    double transcodeScale;

    if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
      /* We were not able to limit the payload size */
      if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
        /* This was the first 30ms of a 60ms frame. Although
           the payload is larger than it should be but we let
           the second 30ms be encoded. Maybe together we
           won't exceed the limit. */
        ISACencLB_obj->frame_nb = 1;
        return 0;
      } else if ((frame_mode == 1) && (ISACencLB_obj->frame_nb == 1)) {
        ISACencLB_obj->frame_nb = 0;
      }

      if (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
        return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
      } else {
        return status;
      }
    }

    if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
      bytesSpecCoderUsed = STREAM_SIZE_MAX;
      /* Being conservative */
      transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
    } else {
      bytesSpecCoderUsed = ISACencLB_obj->bitstr_obj.stream_index -
          transcodingParam.stream_index;
      transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
    }

    /* To be safe, we reduce the scale depending on
       the number of iterations. */
    transcodeScale *= (1.0 - (0.9 * (double)iterCntr /
        (double)MAX_PAYLOAD_LIMIT_ITERATION));

    /* Scale the LPC Gains. */
    for (k = 0; k < SUBFRAMES; k++) {
      lofilt_coef[(LPC_LOBAND_ORDER + 1) * k] =
          transcodingParam.loFiltGain[k] * transcodeScale;
      hifilt_coef[(LPC_HIBAND_ORDER + 1) * k] =
          transcodingParam.hiFiltGain[k] * transcodeScale;
      transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER + 1) * k];
      transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER + 1) * k];
    }

    /* Scale DFT coefficients. */
    for (k = 0; k < FRAMESAMPLES_HALF; k++) {
      fre[k] = (int16_t)(fre[k] * transcodeScale);
      fim[k] = (int16_t)(fim[k] * transcodeScale);
    }

    /* Save data for multiple packets memory. */
    my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF;
    memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre));
    memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim));

    /* Re-store the state of arithmetic coder before coding LPC gains. */
    ISACencLB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
    ISACencLB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
    ISACencLB_obj->bitstr_obj.streamval = transcodingParam.streamval;
    ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
        transcodingParam.stream[0];
    ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
        transcodingParam.stream[1];
    ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
        transcodingParam.stream[2];

    /* Code gains. */
    WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef,
                               &ISACencLB_obj->bitstr_obj,
                               &ISACencLB_obj->SaveEnc_obj);

    /* Update the number of bytes left for encoding the spectrum. */
    bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index;

    /* Encode the spectrum. */
    err = WebRtcIsac_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand,
                                &ISACencLB_obj->bitstr_obj);

    if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      /* There has been an error but it was not too large
         payload (we can cure too large payload). */
      if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
        /* If this is the second 30 ms of a 60 ms frame reset
           this such that in the next call encoder starts fresh. */
        ISACencLB_obj->frame_nb = 0;
      }
      return err;
    }
    iterCntr++;
  }

  /* If 60 ms frame-size and just processed the first 30 ms, */
  /* go back to main function to buffer the other 30 ms speech frame. */
  if (frame_mode == 1) {
    if (ISACencLB_obj->frame_nb == 0) {
      ISACencLB_obj->frame_nb = 1;
      return 0;
    } else if (ISACencLB_obj->frame_nb == 1) {
      ISACencLB_obj->frame_nb = 0;
      /* Also update the frame-length for next packet,
         in Adaptive mode only. */
      if (codingMode == 0 && (ISACencLB_obj->enforceFrameSize == 0)) {
        ISACencLB_obj->new_framelength =
            WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck,
                                         ISACencLB_obj->current_framesamples);
      }
    }
  } else {
    ISACencLB_obj->frame_nb = 0;
  }

  /* Complete arithmetic coding. */
  stream_length = WebRtcIsac_EncTerminate(&ISACencLB_obj->bitstr_obj);
  return stream_length;
}



static int LimitPayloadUb(ISACUBEncStruct* ISACencUB_obj,
                          uint16_t payloadLimitBytes,
                          double bytesLeftSpecCoding,
                          transcode_obj* transcodingParam,
                          int16_t* fre, int16_t* fim,
                          double* lpcGains, enum ISACBand band, int status) {

  int iterCntr = 0;
  int k;
  double bytesSpecCoderUsed;
  double transcodeScale;
  const int16_t kAveragePitchGain = 0.0;

  do {
    if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
      /* We were not able to limit the payload size. */
      return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
    }

    if (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
      bytesSpecCoderUsed = STREAM_SIZE_MAX;
      /* Being conservative. */
      transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
    } else {
      bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index -
          transcodingParam->stream_index;
      transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
    }

    /* To be safe, we reduce the scale depending on the
       number of iterations. */
    transcodeScale *= (1.0 - (0.9 * (double)iterCntr /
        (double)MAX_PAYLOAD_LIMIT_ITERATION));

    /* Scale the LPC Gains. */
    if (band == kIsacUpperBand16) {
      /* Two sets of coefficients if 16 kHz. */
      for (k = 0; k < SUBFRAMES; k++) {
        transcodingParam->loFiltGain[k] *= transcodeScale;
        transcodingParam->hiFiltGain[k] *= transcodeScale;
      }
    } else {
      /* One sets of coefficients if 12 kHz. */
      for (k = 0; k < SUBFRAMES; k++) {
        transcodingParam->loFiltGain[k] *= transcodeScale;
      }
    }

    /* Scale DFT coefficients. */
    for (k = 0; k < FRAMESAMPLES_HALF; k++) {
      fre[k] = (int16_t)(fre[k] * transcodeScale + 0.5);
      fim[k] = (int16_t)(fim[k] * transcodeScale + 0.5);
    }
    /* Store FFT coefficients for multiple encoding. */
    memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre,
          sizeof(ISACencUB_obj->SaveEnc_obj.realFFT));
    memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
           sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT));

    /* Store the state of arithmetic coder before coding LPC gains */
    ISACencUB_obj->bitstr_obj.W_upper = transcodingParam->W_upper;
    ISACencUB_obj->bitstr_obj.stream_index = transcodingParam->stream_index;
    ISACencUB_obj->bitstr_obj.streamval = transcodingParam->streamval;
    ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index - 2] =
        transcodingParam->stream[0];
    ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index - 1] =
        transcodingParam->stream[1];
    ISACencUB_obj->bitstr_obj.stream[transcodingParam->stream_index] =
        transcodingParam->stream[2];

    /* Store the gains for multiple encoding. */
    memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains,
           SUBFRAMES * sizeof(double));
    /* Entropy Code lpc-gains, indices are stored for a later use.*/
    WebRtcIsac_EncodeLpcGainUb(transcodingParam->loFiltGain,
                               &ISACencUB_obj->bitstr_obj,
                               ISACencUB_obj->SaveEnc_obj.lpcGainIndex);

    /* If 16kHz should do one more set. */
    if (band == kIsacUpperBand16) {
      /* Store the gains for multiple encoding. */
      memcpy(&ISACencUB_obj->SaveEnc_obj.lpcGain[SUBFRAMES],
             &lpcGains[SUBFRAMES], SUBFRAMES * sizeof(double));
      /* Entropy Code lpc-gains, indices are stored for a later use.*/
      WebRtcIsac_EncodeLpcGainUb(
          transcodingParam->hiFiltGain, &ISACencUB_obj->bitstr_obj,
          &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);
    }

    /* Update the number of bytes left for encoding the spectrum. */
    bytesLeftSpecCoding = payloadLimitBytes -
        ISACencUB_obj->bitstr_obj.stream_index;

    /* Save the bit-stream object at this point for FEC. */
    memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
           &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));

    /* Encode the spectrum. */
    status = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain,
                                   band, &ISACencUB_obj->bitstr_obj);
    if ((status < 0) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      /* There has been an error but it was not too large payload
         (we can cure too large payload). */
      return status;
    }
    iterCntr++;
  } while ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
      (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH));
  return 0;
}

int WebRtcIsac_EncodeUb16(float* in, ISACUBEncStruct* ISACencUB_obj,
                          int32_t jitterInfo) {
  int err;
  int k;

  double lpcVecs[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
  double percepFilterParams[(1 + UB_LPC_ORDER) * (SUBFRAMES << 1) +
                            (1 + UB_LPC_ORDER)];

  double LP_lookahead[FRAMESAMPLES];
  int16_t fre[FRAMESAMPLES_HALF];   /* Q7 */
  int16_t fim[FRAMESAMPLES_HALF];   /* Q7 */

  int status = 0;

  double varscale[2];
  double corr[SUBFRAMES << 1][UB_LPC_ORDER + 1];
  double lpcGains[SUBFRAMES << 1];
  transcode_obj transcodingParam;
  uint16_t payloadLimitBytes;
  double s2nr;
  const int16_t kAveragePitchGain = 0.0;
  int bytesLeftSpecCoding;

  /* Buffer speech samples (by 10ms packet) until the frame-length is   */
  /* reached (30 ms).                                                   */
  /*********************************************************************/

  /* fill the buffer with 10ms input data */
  memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in,
         FRAMESAMPLES_10ms * sizeof(float));

  /* If buffer size is not equal to current frame-size, and end of file is
   * not reached yet, we don't do encoding unless we have the whole frame. */
  if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
    ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
    return 0;
  }

  /* End of buffer function. */
  /**************************/

  /* Encoding */
  /************/

  /* Reset bit-stream */
  WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj));

  /* Encoding of bandwidth information. */
  WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);

  status = WebRtcIsac_EncodeBandwidth(isac16kHz, &ISACencUB_obj->bitstr_obj);
  if (status < 0) {
    return status;
  }

  s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, FRAMESAMPLES);

  memcpy(lpcVecs, ISACencUB_obj->lastLPCVec, UB_LPC_ORDER * sizeof(double));

  for (k = 0; k < FRAMESAMPLES; k++) {
    LP_lookahead[k] = ISACencUB_obj->data_buffer_float[UB_LOOKAHEAD + k];
  }

  /* Find coefficients for perceptual pre-filters. */
  WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
                          &lpcVecs[UB_LPC_ORDER], corr, varscale, isac16kHz);

  memcpy(ISACencUB_obj->lastLPCVec,
         &lpcVecs[(UB16_LPC_VEC_PER_FRAME - 1) * (UB_LPC_ORDER)],
         sizeof(double) * UB_LPC_ORDER);

  /* Code LPC model and shape - gains not quantized yet. */
  WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
                         percepFilterParams, isac16kHz,
                         &ISACencUB_obj->SaveEnc_obj);

  /* the first set of lpc parameters are from the last sub-frame of
   * the previous frame. so we don't care about them. */
  WebRtcIsac_GetLpcGain(s2nr, &percepFilterParams[UB_LPC_ORDER + 1],
                        (SUBFRAMES << 1), lpcGains, corr, varscale);

  /* Store the state of arithmetic coder before coding LPC gains */
  transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
  transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper;
  transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval;
  transcodingParam.stream[0] =
      ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
                                       2];
  transcodingParam.stream[1] =
      ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
                                       1];
  transcodingParam.stream[2] =
      ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index];

  /* Store LPC Gains before encoding them. */
  for (k = 0; k < SUBFRAMES; k++) {
    transcodingParam.loFiltGain[k] = lpcGains[k];
    transcodingParam.hiFiltGain[k] = lpcGains[SUBFRAMES + k];
  }

  /* Store the gains for multiple encoding. */
  memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains,
         (SUBFRAMES << 1) * sizeof(double));

  WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
                             ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
  WebRtcIsac_EncodeLpcGainUb(
      &lpcGains[SUBFRAMES], &ISACencUB_obj->bitstr_obj,
      &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);

  /* Get the correct value for the payload limit and calculate the number of
     bytes left for coding the spectrum. It is a 30ms frame
     Subract 3 because termination process may add 3 bytes */
  payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
      ISACencUB_obj->numBytesUsed - 3;
  bytesLeftSpecCoding = payloadLimitBytes -
        ISACencUB_obj->bitstr_obj.stream_index;

  for (k = 0; k < (SUBFRAMES << 1); k++) {
    percepFilterParams[k * (UB_LPC_ORDER + 1) + (UB_LPC_ORDER + 1)] =
        lpcGains[k];
  }

  /* LPC filtering (using normalized lattice filter), */
  /* first half-frame. */
  WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
                                 ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
                                 ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
                                 &ISACencUB_obj->data_buffer_float[0],
                                 &percepFilterParams[UB_LPC_ORDER + 1],
                                 &LP_lookahead[0]);

  /* Second half-frame filtering. */
  WebRtcIsac_NormLatticeFilterMa(
      UB_LPC_ORDER, ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
      ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
      &ISACencUB_obj->data_buffer_float[FRAMESAMPLES_HALF],
      &percepFilterParams[(UB_LPC_ORDER + 1) + SUBFRAMES * (UB_LPC_ORDER + 1)],
      &LP_lookahead[FRAMESAMPLES_HALF]);

  WebRtcIsac_Time2Spec(&LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF],
                       fre, fim, &ISACencUB_obj->fftstr_obj);

  /* Store FFT coefficients for multiple encoding. */
  memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre, sizeof(fre));
  memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, sizeof(fim));

  /* Prepare the audio buffer for the next packet
   * move the last 3 ms to the beginning of the buffer. */
  memcpy(ISACencUB_obj->data_buffer_float,
         &ISACencUB_obj->data_buffer_float[FRAMESAMPLES],
         LB_TOTAL_DELAY_SAMPLES * sizeof(float));
  /* start writing with 3 ms delay to compensate for the delay
   * of the lower-band. */
  ISACencUB_obj->buffer_index = LB_TOTAL_DELAY_SAMPLES;

  /* Save the bit-stream object at this point for FEC. */
  memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, &ISACencUB_obj->bitstr_obj,
         sizeof(Bitstr));

  /* Qantization and lossless coding */
  /* Note that there is no pitch-gain for this band so kAveragePitchGain = 0
   * is passed to the function. In fact, the function ignores the 3rd parameter
   * for this band. */
  err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand16,
                              &ISACencUB_obj->bitstr_obj);
  if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
    return err;
  }

  if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
      (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
    err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding,
                         &transcodingParam, fre, fim, lpcGains,
                         kIsacUpperBand16, err);
  }
  if (err < 0) {
    return err;
  }
  /* Complete arithmetic coding. */
  return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
}


int WebRtcIsac_EncodeUb12(float* in, ISACUBEncStruct* ISACencUB_obj,
                          int32_t jitterInfo) {
  int err;
  int k;

  double lpcVecs[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];

  double percepFilterParams[(1 + UB_LPC_ORDER) * SUBFRAMES];
  float LP[FRAMESAMPLES_HALF];
  float HP[FRAMESAMPLES_HALF];

  double LP_lookahead[FRAMESAMPLES_HALF];
  double HP_lookahead[FRAMESAMPLES_HALF];
  double LPw[FRAMESAMPLES_HALF];

  double HPw[FRAMESAMPLES_HALF];
  int16_t fre[FRAMESAMPLES_HALF];   /* Q7 */
  int16_t fim[FRAMESAMPLES_HALF];   /* Q7 */

  int status = 0;

  double varscale[1];

  double corr[UB_LPC_GAIN_DIM][UB_LPC_ORDER + 1];
  double lpcGains[SUBFRAMES];
  transcode_obj transcodingParam;
  uint16_t payloadLimitBytes;
  double s2nr;
  const int16_t kAveragePitchGain = 0.0;
  double bytesLeftSpecCoding;

  /* Buffer speech samples (by 10ms packet) until the framelength is  */
  /* reached (30 ms).                                                 */
  /********************************************************************/

  /* Fill the buffer with 10ms input data. */
  memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in,
         FRAMESAMPLES_10ms * sizeof(float));

  /* if buffer-size is not equal to current frame-size then increase the
     index and return. We do the encoding when we have enough audio.     */
  if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
    ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
    return 0;
  }
  /* If buffer reached the right size, reset index and continue
     with encoding the frame */
  ISACencUB_obj->buffer_index = 0;

  /* End of buffer function */
  /**************************/

  /* Encoding */
  /************/

  /* Reset bit-stream. */
  WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj));

  /* Encoding bandwidth information. */
  WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);
  status = WebRtcIsac_EncodeBandwidth(isac12kHz, &ISACencUB_obj->bitstr_obj);
  if (status < 0) {
    return status;
  }

  s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, FRAMESAMPLES);

  /* Split signal in two bands. */
  WebRtcIsac_SplitAndFilterFloat(ISACencUB_obj->data_buffer_float, HP, LP,
                                 HP_lookahead, LP_lookahead,
                                 &ISACencUB_obj->prefiltbankstr_obj);

  /* Find coefficients for perceptual pre-filters. */
  WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
                          lpcVecs, corr, varscale, isac12kHz);

  /* Code LPC model and shape - gains not quantized yet. */
  WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
                         percepFilterParams, isac12kHz,
                         &ISACencUB_obj->SaveEnc_obj);

  WebRtcIsac_GetLpcGain(s2nr, percepFilterParams, SUBFRAMES, lpcGains, corr,
                        varscale);

  /* Store the state of arithmetic coder before coding LPC gains. */
  transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper;
  transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
  transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval;
  transcodingParam.stream[0] =
      ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
                                       2];
  transcodingParam.stream[1] =
      ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index -
                                       1];
  transcodingParam.stream[2] =
      ISACencUB_obj->bitstr_obj.stream[ISACencUB_obj->bitstr_obj.stream_index];

  /* Store LPC Gains before encoding them. */
  for (k = 0; k < SUBFRAMES; k++) {
    transcodingParam.loFiltGain[k] = lpcGains[k];
  }

  /* Store the gains for multiple encoding. */
  memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES *
         sizeof(double));

  WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
                             ISACencUB_obj->SaveEnc_obj.lpcGainIndex);

  for (k = 0; k < SUBFRAMES; k++) {
    percepFilterParams[k * (UB_LPC_ORDER + 1)] = lpcGains[k];
  }

  /* perceptual pre-filtering (using normalized lattice filter) */
  /* low-band filtering */
  WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
                                 ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
                                 ISACencUB_obj->maskfiltstr_obj.PreStateLoG, LP,
                                 percepFilterParams, LPw);

  /* Get the correct value for the payload limit and calculate the number
     of bytes left for coding the spectrum. It is a 30ms frame Subract 3
     because termination process may add 3 bytes */
  payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
      ISACencUB_obj->numBytesUsed - 3;
  bytesLeftSpecCoding = payloadLimitBytes -
      ISACencUB_obj->bitstr_obj.stream_index;

  memset(HPw, 0, sizeof(HPw));

  /* Transform */
  WebRtcIsac_Time2Spec(LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj);

  /* Store FFT coefficients for multiple encoding. */
  memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre,
         sizeof(ISACencUB_obj->SaveEnc_obj.realFFT));
  memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
         sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT));

  /* Save the bit-stream object at this point for FEC. */
  memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
         &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));

  /* Quantization and loss-less coding */
  /* The 4th parameter to this function is pitch-gain, which is only used
   * when encoding 0-8 kHz band, and irrelevant in this function, therefore,
   * we insert zero here. */
  err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand12,
                              &ISACencUB_obj->bitstr_obj);
  if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
    /* There has been an error but it was not too large
       payload (we can cure too large payload) */
    return err;
  }

  if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
      (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
    err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding,
                         &transcodingParam, fre, fim, lpcGains,
                         kIsacUpperBand12, err);
  }
  if (err < 0) {
    return err;
  }
  /* Complete arithmetic coding. */
  return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
}






/* This function is used to create a new bit-stream with new BWE.
   The same data as previously encoded with the function WebRtcIsac_Encoder().
   The data needed is taken from the structure, where it was stored
   when calling the encoder. */

int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj,
                                  Bitstr* ISACBitStr_obj, int BWnumber,
                                  float scale) {
  int ii;
  int status;
  int BWno = BWnumber;

  const uint16_t* WebRtcIsac_kQPitchGainCdf_ptr[1];
  const uint16_t** cdf;

  double tmpLPCcoeffs_lo[(ORDERLO + 1)*SUBFRAMES * 2];
  double tmpLPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * 2];
  int tmpLPCindex_g[12 * 2];
  int16_t tmp_fre[FRAMESAMPLES], tmp_fim[FRAMESAMPLES];
  const int kModel = 0;

  /* Sanity Check - possible values for BWnumber is 0 - 23. */
  if ((BWnumber < 0) || (BWnumber > 23)) {
    return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
  }

  /* Reset bit-stream. */
  WebRtcIsac_ResetBitstream(ISACBitStr_obj);

  /* Encode frame length */
  status = WebRtcIsac_EncodeFrameLen(ISACSavedEnc_obj->framelength,
                                     ISACBitStr_obj);
  if (status < 0) {
    /* Wrong frame size. */
    return status;
  }

  /* Transcoding */
  if ((scale > 0.0) && (scale < 1.0)) {
    /* Compensate LPC gain. */
    for (ii = 0;
        ii < ((ORDERLO + 1)* SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx));
        ii++) {
      tmpLPCcoeffs_lo[ii] = scale *  ISACSavedEnc_obj->LPCcoeffs_lo[ii];
    }
    for (ii = 0;
        ii < ((ORDERHI + 1) * SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx));
        ii++) {
      tmpLPCcoeffs_hi[ii] = scale *  ISACSavedEnc_obj->LPCcoeffs_hi[ii];
    }
    /* Scale DFT. */
    for (ii = 0;
        ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
        ii++) {
      tmp_fre[ii] = (int16_t)((scale) * (float)ISACSavedEnc_obj->fre[ii]);
      tmp_fim[ii] = (int16_t)((scale) * (float)ISACSavedEnc_obj->fim[ii]);
    }
  } else {
    for (ii = 0;
        ii < (KLT_ORDER_GAIN * (1 + ISACSavedEnc_obj->startIdx));
        ii++) {
      tmpLPCindex_g[ii] =  ISACSavedEnc_obj->LPCindex_g[ii];
    }
    for (ii = 0;
        ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
        ii++) {
      tmp_fre[ii] = ISACSavedEnc_obj->fre[ii];
      tmp_fim[ii] = ISACSavedEnc_obj->fim[ii];
    }
  }

  /* Encode bandwidth estimate. */
  WebRtcIsac_EncodeReceiveBw(&BWno, ISACBitStr_obj);

  /* Loop over number of 30 msec */
  for (ii = 0; ii <= ISACSavedEnc_obj->startIdx; ii++) {
    /* Encode pitch gains. */
    *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf;
    WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                            &ISACSavedEnc_obj->pitchGain_index[ii],
                            WebRtcIsac_kQPitchGainCdf_ptr, 1);

    /* Entropy coding of quantization pitch lags */
    /* Voicing classification. */
    if (ISACSavedEnc_obj->meanGain[ii] < 0.2) {
      cdf = WebRtcIsac_kQPitchLagCdfPtrLo;
    } else if (ISACSavedEnc_obj->meanGain[ii] < 0.4) {
      cdf = WebRtcIsac_kQPitchLagCdfPtrMid;
    } else {
      cdf = WebRtcIsac_kQPitchLagCdfPtrHi;
    }
    WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                            &ISACSavedEnc_obj->pitchIndex[PITCH_SUBFRAMES * ii],
                            cdf, PITCH_SUBFRAMES);

    /* LPC */
    /* Only one model exists. The entropy coding is done only for backward
     * compatibility. */
    WebRtcIsac_EncHistMulti(ISACBitStr_obj, &kModel,
                            WebRtcIsac_kQKltModelCdfPtr, 1);
    /* Entropy coding of quantization indices - LPC shape only. */
    WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                            &ISACSavedEnc_obj->LPCindex_s[KLT_ORDER_SHAPE * ii],
                            WebRtcIsac_kQKltCdfPtrShape,
                            KLT_ORDER_SHAPE);

    /* If transcoding, get new LPC gain indices */
    if (scale < 1.0) {
      WebRtcIsac_TranscodeLPCCoef(
          &tmpLPCcoeffs_lo[(ORDERLO + 1) * SUBFRAMES * ii],
          &tmpLPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * ii],
          &tmpLPCindex_g[KLT_ORDER_GAIN * ii]);
    }

    /* Entropy coding of quantization indices - LPC gain. */
    WebRtcIsac_EncHistMulti(ISACBitStr_obj, &tmpLPCindex_g[KLT_ORDER_GAIN * ii],
                            WebRtcIsac_kQKltCdfPtrGain, KLT_ORDER_GAIN);

    /* Quantization and loss-less coding. */
    status = WebRtcIsac_EncodeSpec(&tmp_fre[ii * FRAMESAMPLES_HALF],
                                   &tmp_fim[ii * FRAMESAMPLES_HALF],
                                   ISACSavedEnc_obj->AvgPitchGain[ii],
                                   kIsacLowerBand, ISACBitStr_obj);
    if (status < 0) {
      return status;
    }
  }
  /* Complete arithmetic coding. */
  return WebRtcIsac_EncTerminate(ISACBitStr_obj);
}


int WebRtcIsac_EncodeStoredDataUb(
    const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
    Bitstr* bitStream,
    int32_t jitterInfo,
    float scale,
    enum ISACBandwidth bandwidth) {
  int n;
  int err;
  double lpcGain[SUBFRAMES];
  int16_t realFFT[FRAMESAMPLES_HALF];
  int16_t imagFFT[FRAMESAMPLES_HALF];
  const uint16_t** shape_cdf;
  int shape_len;
  const int16_t kAveragePitchGain = 0.0;
  enum ISACBand band;
  /* Reset bitstream. */
  WebRtcIsac_ResetBitstream(bitStream);

  /* Encode jitter index. */
  WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream);

  err = WebRtcIsac_EncodeBandwidth(bandwidth, bitStream);
  if (err < 0) {
    return err;
  }

  /* Encode LPC-shape. */
  if (bandwidth == isac12kHz) {
    shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb12;
    shape_len = UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME;
    band = kIsacUpperBand12;
  } else {
    shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb16;
    shape_len = UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME;
    band = kIsacUpperBand16;
  }
  WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape,
                          shape_cdf, shape_len);

  if ((scale <= 0.0) || (scale >= 1.0)) {
    /* We only consider scales between zero and one. */
    WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex,
                            WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
    if (bandwidth == isac16kHz) {
      /* Store gain indices of the second half. */
      WebRtcIsac_EncHistMulti(bitStream,
                              &ISACSavedEnc_obj->lpcGainIndex[SUBFRAMES],
                              WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
    }
    /* Store FFT coefficients. */
    err = WebRtcIsac_EncodeSpec(ISACSavedEnc_obj->realFFT,
                                ISACSavedEnc_obj->imagFFT, kAveragePitchGain,
                                band, bitStream);
  } else {
    /* Scale LPC gain and FFT coefficients. */
    for (n = 0; n < SUBFRAMES; n++) {
      lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n];
    }
    /* Store LPC gains. */
    WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);

    if (bandwidth == isac16kHz) {
      /* Scale and code the gains of the second half of the frame, if 16kHz. */
      for (n = 0; n < SUBFRAMES; n++) {
        lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n + SUBFRAMES];
      }
      WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);
    }

    for (n = 0; n < FRAMESAMPLES_HALF; n++) {
      realFFT[n] = (int16_t)(scale * (float)ISACSavedEnc_obj->realFFT[n] +
          0.5f);
      imagFFT[n] = (int16_t)(scale * (float)ISACSavedEnc_obj->imagFFT[n] +
          0.5f);
    }
    /* Store FFT coefficients. */
    err = WebRtcIsac_EncodeSpec(realFFT, imagFFT, kAveragePitchGain,
                                band, bitStream);
  }
  if (err < 0) {
    /* Error happened while encoding FFT coefficients. */
    return err;
  }

  /* Complete arithmetic coding. */
  return WebRtcIsac_EncTerminate(bitStream);
}

int16_t WebRtcIsac_GetRedPayloadUb(
    const ISACUBSaveEncDataStruct* ISACSavedEncObj,
    Bitstr*                        bitStreamObj,
    enum ISACBandwidth             bandwidth) {
  int n;
  int16_t status;
  int16_t realFFT[FRAMESAMPLES_HALF];
  int16_t imagFFT[FRAMESAMPLES_HALF];
  enum ISACBand band;
  const int16_t kAveragePitchGain = 0.0;
  /* Store bit-stream object. */
  memcpy(bitStreamObj, &ISACSavedEncObj->bitStreamObj, sizeof(Bitstr));

  /* Scale FFT coefficients. */
  for (n = 0; n < FRAMESAMPLES_HALF; n++) {
    realFFT[n] = (int16_t)((float)ISACSavedEncObj->realFFT[n] *
        RCU_TRANSCODING_SCALE_UB + 0.5);
    imagFFT[n] = (int16_t)((float)ISACSavedEncObj->imagFFT[n] *
        RCU_TRANSCODING_SCALE_UB + 0.5);
  }

  band = (bandwidth == isac12kHz) ? kIsacUpperBand12 : kIsacUpperBand16;
  status = WebRtcIsac_EncodeSpec(realFFT, imagFFT, kAveragePitchGain, band,
                                 bitStreamObj);
  if (status < 0) {
    return status;
  } else {
    /* Terminate entropy coding */
    return WebRtcIsac_EncTerminate(bitStreamObj);
  }
}
