/******************************************************************************
 *                                                                            *
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
#include <string.h>
#include <math.h>
#include "ixheaacd_sbr_common.h"
#include <ixheaacd_type_def.h>

#include "ixheaacd_constants.h"
#include <ixheaacd_basic_ops32.h>
#include <ixheaacd_basic_ops16.h>
#include <ixheaacd_basic_ops40.h>
#include "ixheaacd_basic_ops.h"
#include "ixheaacd_defines.h"

#include "ixheaacd_intrinsics.h"
#include "ixheaacd_sbr_const.h"
#include <ixheaacd_basic_op.h>
#include "ixheaacd_defines.h"
#include "ixheaacd_bitbuffer.h"
#include "ixheaacd_pns.h"

#include <ixheaacd_aac_rom.h>
#include "ixheaacd_pulsedata.h"

#include "ixheaacd_drc_data_struct.h"
#include "ixheaacd_lt_predict.h"
#include "ixheaacd_channelinfo.h"
#include "ixheaacd_drc_dec.h"

#include "ixheaacd_sbrdecoder.h"

#include "ixheaacd_sbrdecsettings.h"
#include "ixheaacd_sbr_scale.h"
#include "ixheaacd_lpp_tran.h"
#include "ixheaacd_env_extr_part.h"
#include <ixheaacd_sbr_rom.h>
#include "ixheaacd_hybrid.h"
#include "ixheaacd_ps_dec.h"
#include "ixheaacd_ps_bitdec.h"
#include "ixheaacd_env_extr.h"
#include "ixheaacd_common_rom.h"
#include "ixheaacd_freq_sca.h"

#include "ixheaacd_qmf_dec.h"

#include "ixheaacd_env_calc.h"

#include "ixheaacd_pvc_dec.h"
#include "ixheaacd_sbr_dec.h"
#include "ixheaacd_env_dec.h"
#include "ixheaacd_basic_funcs.h"
#include "ixheaacd_sbr_crc.h"
#include "ixheaacd_function_selector.h"

#include "ixheaacd_audioobjtypes.h"

#define ALIGN_SIZE64(x) ((((x) + 7) >> 3) << 3)

static FLOAT32 ixheaacd_new_bw_table[4][4] = {{0.00f, 0.60f, 0.90f, 0.98f},
                                              {0.60f, 0.75f, 0.90f, 0.98f},
                                              {0.00f, 0.75f, 0.90f, 0.98f},
                                              {0.00f, 0.75f, 0.90f, 0.98f}};
static WORD32 ixheaacd_inew_bw_table[4][4] = {
    {0x00000000, 0x4ccccccd, 0x73333333, 0x7d70a3d7},
    {0x4ccccccd, 0x60000000, 0x73333333, 0x7d70a3d7},
    {0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7},
    {0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7}};

VOID ixheaacd_reset_sbrenvelope_calc(ia_sbr_calc_env_struct *h_cal_env) {
  h_cal_env->ph_index = 0;
  h_cal_env->filt_buf_noise_e = 0;
  h_cal_env->start_up = 1;
}

WORD32 ixheaacd_derive_lim_band_tbl(
    ia_sbr_header_data_struct *ptr_header_data,
    const ia_patch_param_struct *p_str_patch_param, WORD16 num_patches,
    ixheaacd_misc_tables *pstr_common_tables) {
  WORD32 i, k, k_1;
  WORD32 nr_lim, patch_border_k, patch_border_k_1, temp_nr_lim;

  WORD16 lim_table[MAX_FREQ_COEFFS / 2 + MAX_NUM_PATCHES + 1];
  WORD16 patch_borders[MAX_NUM_PATCHES + 1];
  WORD16 kx, k2;
  WORD16 temp, lim_bands, num_octaves;

  WORD16 *f_lim_tbl = ptr_header_data->pstr_freq_band_data->freq_band_tbl_lim;
  WORD16 *num_lf_bands = &ptr_header_data->pstr_freq_band_data->num_lf_bands;
  WORD16 *f_low_tbl =
      ptr_header_data->pstr_freq_band_data->freq_band_table[LOW];
  WORD16 num_low_bnd = ptr_header_data->pstr_freq_band_data->num_sf_bands[LOW];
  WORD16 limiter_bands = ptr_header_data->limiter_bands;

  WORD16 sub_band_start = f_low_tbl[0];
  WORD16 sub_band_end = f_low_tbl[num_low_bnd];
  WORD16 limbnd_per_oct[4] = {(WORD16)0x2000, (WORD16)0x2666, (WORD16)0x4000,
                              (WORD16)0x6000};

  if (limiter_bands == 0) {
    f_lim_tbl[0] = 0;
    f_lim_tbl[1] = sub_band_end - sub_band_start;
    nr_lim = 1;
  } else {
    for (k = 0; k < num_patches; k++) {
      patch_borders[k] = p_str_patch_param[k].guard_start_band - sub_band_start;
    }
    patch_borders[k] = sub_band_end - sub_band_start;

    for (k = 0; k <= num_low_bnd; k++) {
      lim_table[k] = f_low_tbl[k] - sub_band_start;
    }
    for (k = 1; k < num_patches; k++) {
      lim_table[num_low_bnd + k] = patch_borders[k];
    }

    temp_nr_lim = nr_lim = (num_low_bnd + num_patches) - 1;
    ixheaacd_aac_shellsort(lim_table, (temp_nr_lim + 1));

    k = 1;
    k_1 = 0;

    lim_bands = limbnd_per_oct[limiter_bands];

    while ((k - temp_nr_lim) <= 0) {
      k2 = lim_table[k] + sub_band_start;
      kx = lim_table[k_1] + sub_band_start;

      num_octaves = pstr_common_tables->log_dual_is_table[k2];
      num_octaves -= pstr_common_tables->log_dual_is_table[kx];

      temp = (WORD16)(((WORD32)lim_bands * (WORD32)num_octaves) >> 15);

      if (temp < 0x01f6) {
        if (lim_table[k_1] == lim_table[k]) {
          lim_table[k] = sub_band_end;
          nr_lim = nr_lim - 1;
          k = (k + 1);
          continue;
        }
        patch_border_k_1 = patch_border_k = 0;

        for (i = 0; i <= num_patches; i++) {
          if (lim_table[k] == patch_borders[i]) {
            patch_border_k = 1;
          }
          if (lim_table[k_1] == patch_borders[i]) {
            patch_border_k_1 = 1;
          }
        }
        if (!patch_border_k) {
          lim_table[k] = sub_band_end;
          nr_lim = nr_lim - 1;
          k = (k + 1);
          continue;
        }

        if (!patch_border_k_1) {
          lim_table[k_1] = sub_band_end;
          nr_lim = nr_lim - 1;
        }
      }
      k_1 = k;
      k = (k + 1);
    }
    ixheaacd_aac_shellsort(lim_table, (temp_nr_lim + 1));

    memcpy(f_lim_tbl, lim_table, sizeof(WORD16) * (nr_lim + 1));
  }
  *num_lf_bands = nr_lim;

  return 0;
}

VOID ixheaacd_lean_sbrconcealment(
    ia_sbr_header_data_struct *ptr_header_data,
    ia_sbr_frame_info_data_struct *ptr_sbr_data,
    ia_sbr_prev_frame_data_struct *ptr_prev_data) {
  WORD32 target;
  WORD32 step;
  WORD32 i;

  WORD16 cur_start_pos;
  WORD16 cur_stop_pos;

  ptr_sbr_data->amp_res = ptr_prev_data->amp_res;
  ptr_sbr_data->coupling_mode = ptr_prev_data->coupling_mode;
  ptr_sbr_data->max_qmf_subband_aac = ptr_prev_data->max_qmf_subband_aac;

  memcpy(ptr_sbr_data->sbr_invf_mode, ptr_prev_data->sbr_invf_mode,
         sizeof(WORD32) * MAX_INVF_BANDS);

  ptr_sbr_data->str_frame_info_details.num_env = 1;

  cur_start_pos = ptr_prev_data->end_position - ptr_header_data->num_time_slots;
  cur_stop_pos = ptr_header_data->num_time_slots;

  ptr_sbr_data->str_frame_info_details.border_vec[0] = cur_start_pos;
  ptr_sbr_data->str_frame_info_details.border_vec[1] = cur_stop_pos;

  ptr_sbr_data->str_frame_info_details.noise_border_vec[0] = cur_start_pos;
  ptr_sbr_data->str_frame_info_details.noise_border_vec[1] = cur_stop_pos;
  ;

  ptr_sbr_data->str_frame_info_details.freq_res[0] = 1;
  ptr_sbr_data->str_frame_info_details.transient_env = -1;
  ptr_sbr_data->str_frame_info_details.num_noise_env = 1;

  ptr_sbr_data->num_env_sfac =
      ptr_header_data->pstr_freq_band_data->num_sf_bands[1];

  ptr_sbr_data->del_cod_dir_arr[0] = DTDF_DIR_TIME;

  if (ptr_sbr_data->coupling_mode == COUPLING_BAL) {
    target = SBR_ENERGY_PAN_OFFSET;
  } else {
    target = 0;
  }

  step = 1;

  if (ptr_sbr_data->amp_res - SBR_AMPLITUDE_RESOLUTION_1_5 == 0) {
    target = (target << 1);
    step = (step << 1);
  }

  for (i = 0; i < ptr_sbr_data->num_env_sfac; i++) {
    if (ptr_prev_data->sfb_nrg_prev[i] > target)
      ptr_sbr_data->int_env_sf_arr[i] = -(step);
    else
      ptr_sbr_data->int_env_sf_arr[i] = step;
  }

  ptr_sbr_data->del_cod_dir_noise_arr[0] = DTDF_DIR_TIME;

  memset(ptr_sbr_data->int_noise_floor, 0,
         sizeof(WORD16) * ptr_header_data->pstr_freq_band_data->num_nf_bands);

  memset(ptr_sbr_data->add_harmonics, 0, sizeof(FLAG) * MAX_FREQ_COEFFS);
}

static WORD16 ixheaacd_find_closest_entry(WORD32 goal_sb, WORD16 *f_master_tbl,
                                          WORD16 num_mf_bands,
                                          WORD16 direction) {
  WORD32 index;

  if (goal_sb <= f_master_tbl[0]) return f_master_tbl[0];

  if (goal_sb >= f_master_tbl[num_mf_bands]) return f_master_tbl[num_mf_bands];

  if (direction) {
    index = 0;
    while (f_master_tbl[index] < goal_sb) {
      index++;
    }
  } else {
    index = num_mf_bands;
    while (f_master_tbl[index] > goal_sb) {
      index--;
    }
  }

  return f_master_tbl[index];
}

WORD32 ixheaacd_reset_hf_generator(ia_sbr_hf_generator_struct *ptr_hf_gen_str,
                                   ia_sbr_header_data_struct *ptr_header_data,
                                   WORD audio_object_type) {
  WORD32 patch, sb;
  WORD32 temp;
  WORD16 *ptr_noise_freq_tbl;
  WORD32 num_nf_bands;

  ia_transposer_settings_struct *pstr_transposer_settings =
      ptr_hf_gen_str->pstr_settings;
  ia_patch_param_struct *p_str_patch_param =
      pstr_transposer_settings->str_patch_param;

  WORD32 sub_band_start = ptr_header_data->pstr_freq_band_data->sub_band_start;
  WORD16 *f_master_tbl = ptr_header_data->pstr_freq_band_data->f_master_tbl;
  WORD16 num_mf_bands = ptr_header_data->pstr_freq_band_data->num_mf_bands;
  WORD16 usb = ptr_header_data->pstr_freq_band_data->sub_band_end;

  WORD32 src_start_band;
  WORD32 patch_stride;
  WORD32 num_bands_in_patch;

  WORD32 lsb = f_master_tbl[0];
  WORD16 xover_offset = sub_band_start - lsb;

  WORD16 goal_sb;
  WORD32 fs = ptr_header_data->out_sampling_freq;

  if (lsb < (SHIFT_START_SB + 4)) {
    return (1);
  }
  switch (fs) {
    case 16000:
    case 22050:
    case 24000:
    case 32000:
      goal_sb = 64;
      break;
    case 44100:
      goal_sb = 46;
      break;
    case 48000:
      goal_sb = 43;
      break;
    case 64000:
      goal_sb = 32;
      break;
    case 88200:
      goal_sb = 23;
      break;
    case 96000:
      goal_sb = 21;
      break;
    default:
      return (0);
  }

  goal_sb = ixheaacd_find_closest_entry(goal_sb, f_master_tbl, num_mf_bands, 1);
  if (audio_object_type != AOT_ER_AAC_ELD &&
      audio_object_type != AOT_ER_AAC_LD) {
    if (ixheaacd_abs16_sat((WORD16)(goal_sb - usb)) < 4) {
      goal_sb = usb;
    }
  }

  src_start_band = SHIFT_START_SB + xover_offset;
  sb = (lsb + xover_offset);

  patch = 0;

  while (((sb - usb) < 0) && (patch < MAX_NUM_PATCHES)) {
    ia_patch_param_struct *ptr_loc_patch_param = &p_str_patch_param[patch];

    ptr_loc_patch_param->guard_start_band = sb;
    sb = (sb + GUARDBANDS);
    ptr_loc_patch_param->dst_start_band = sb;

    num_bands_in_patch = (goal_sb - sb);

    if ((num_bands_in_patch - (lsb - src_start_band)) >= 0) {
      patch_stride = sb - src_start_band;
      patch_stride = (WORD16)(patch_stride & ~1);
      num_bands_in_patch = (lsb - (sb - patch_stride));
      num_bands_in_patch = ixheaacd_find_closest_entry(
          sb + num_bands_in_patch, f_master_tbl, num_mf_bands, 0);
      num_bands_in_patch -= sb;
    }

    patch_stride = ((num_bands_in_patch + sb) - lsb);
    patch_stride = (WORD16)((patch_stride + 1) & ~1);

    if (num_bands_in_patch > 0) {
      ptr_loc_patch_param->src_start_band = (sb - patch_stride);
      ptr_loc_patch_param->dst_end_band = patch_stride;
      ptr_loc_patch_param->num_bands_in_patch = num_bands_in_patch;
      ptr_loc_patch_param->src_end_band =
          (ptr_loc_patch_param->src_start_band + num_bands_in_patch);

      sb = (sb + ptr_loc_patch_param->num_bands_in_patch);
      patch++;
    }

    src_start_band = SHIFT_START_SB;

    if ((ixheaacd_abs16_sat((WORD16)((sb - goal_sb))) - 3) < 0) {
      goal_sb = usb;
    }
  }

  patch--;

  if ((patch > 0) && (p_str_patch_param[patch].num_bands_in_patch < 3)) {
    patch--;
    sb = p_str_patch_param[patch].dst_start_band +
         p_str_patch_param[patch].num_bands_in_patch;
  }

  if (patch >= MAX_NUM_PATCHES) {
    return -1;
  }

  pstr_transposer_settings->num_patches = patch + 1;

  temp = 0;

  for (patch = 0; patch < pstr_transposer_settings->num_patches; patch++) {
    sb = ixheaacd_min32(sb, p_str_patch_param[patch].src_start_band);
    temp = ixheaacd_max32(temp, p_str_patch_param[patch].src_end_band);
  }

  pstr_transposer_settings->start_patch = sb;
  pstr_transposer_settings->stop_patch = temp;

  ptr_noise_freq_tbl =
      ptr_header_data->pstr_freq_band_data->freq_band_tbl_noise;
  num_nf_bands = ptr_header_data->pstr_freq_band_data->num_nf_bands;

  memcpy(&pstr_transposer_settings->bw_borders[0], &ptr_noise_freq_tbl[1],
         sizeof(WORD16) * num_nf_bands);

  memset(ptr_hf_gen_str->bw_array_prev, 0, sizeof(WORD32) * MAX_NUM_PATCHES);

  return 0;
}
VOID ixheaacd_rescale_x_overlap(
    ia_sbr_dec_struct *ptr_sbr_dec, ia_sbr_header_data_struct *ptr_header_data,
    ia_sbr_frame_info_data_struct *ptr_frame_data,
    ia_sbr_prev_frame_data_struct *ptr_frame_data_prev,
    WORD32 **pp_overlap_buffer_real, FLAG low_pow_flag) {
  WORD32 k, l;
  WORD32 start_band, end_band;
  WORD32 target_lsb, target_usb;
  WORD32 source_scale, target_scale, delta_scale, reserve;
  WORD32 **pp_overlap_buffer_imag = &pp_overlap_buffer_real[MAX_ENV_COLS];

  WORD32 old_lsb = ptr_frame_data_prev->max_qmf_subband_aac;
  WORD32 start_slot =
      (ptr_header_data->time_step *
       (ptr_frame_data_prev->end_position - ptr_header_data->num_time_slots));
  WORD32 new_lsb = ptr_frame_data->max_qmf_subband_aac;

  ptr_sbr_dec->str_codec_qmf_bank.usb = new_lsb;
  ptr_sbr_dec->str_synthesis_qmf_bank.lsb = new_lsb;

  start_band = ixheaacd_min32(old_lsb, new_lsb);
  end_band = ixheaacd_max32(old_lsb, new_lsb);

  if (new_lsb != old_lsb && old_lsb > 0) {
    for (l = start_slot; l < 6; l++) {
      for (k = old_lsb; k < new_lsb; k++) {
        pp_overlap_buffer_real[l][k] = 0L;

        if (!low_pow_flag) {
          pp_overlap_buffer_imag[l][k] = 0L;
        }
      }
    }

    if (new_lsb > old_lsb) {
      source_scale = ptr_sbr_dec->str_sbr_scale_fact.ov_hb_scale;
      target_scale = ptr_sbr_dec->str_sbr_scale_fact.ov_lb_scale;
      target_lsb = 0;
      target_usb = old_lsb;
    } else {
      source_scale = ptr_sbr_dec->str_sbr_scale_fact.ov_lb_scale;
      target_scale = ptr_sbr_dec->str_sbr_scale_fact.ov_hb_scale;
      target_lsb = old_lsb;
      target_usb = ptr_sbr_dec->str_synthesis_qmf_bank.usb;
    }

    reserve = (*ixheaacd_ixheaacd_expsubbandsamples)(
        pp_overlap_buffer_real, pp_overlap_buffer_imag, start_band, end_band, 0,
        start_slot, low_pow_flag);

    (*ixheaacd_adjust_scale)(pp_overlap_buffer_real, pp_overlap_buffer_imag,
                             start_band, end_band, 0, start_slot, reserve,
                             low_pow_flag);

    source_scale += reserve;

    delta_scale = (target_scale - source_scale);

    if (delta_scale > 0) {
      delta_scale = -(delta_scale);
      start_band = target_lsb;
      end_band = target_usb;

      if (new_lsb > old_lsb) {
        ptr_sbr_dec->str_sbr_scale_fact.ov_lb_scale = source_scale;
      } else {
        ptr_sbr_dec->str_sbr_scale_fact.ov_hb_scale = source_scale;
      }
    }

    (*ixheaacd_adjust_scale)(pp_overlap_buffer_real, pp_overlap_buffer_imag,
                             start_band, end_band, 0, start_slot, delta_scale,
                             low_pow_flag);
  }
}

VOID ixheaacd_map_sineflags(WORD16 *freq_band_table, WORD16 num_sf_bands,
                            FLAG *add_harmonics, WORD8 *harm_flags_prev,
                            WORD16 transient_env, WORD8 *sine_mapped)

{
  WORD32 qmfband2, li, ui, i;
  WORD32 low_subband_sec;
  WORD32 oldflags;

  low_subband_sec = (freq_band_table[0] << 1);

  memset(sine_mapped, MAX_ENVELOPES, sizeof(WORD8) * MAX_FREQ_COEFFS);

  for (i = (num_sf_bands - 1); i >= 0; i--) {
    oldflags = *harm_flags_prev;
    *harm_flags_prev++ = add_harmonics[i];

    if (add_harmonics[i]) {
      li = freq_band_table[i];

      ui = freq_band_table[i + 1];

      qmfband2 = ((ui + li) - low_subband_sec) >> 1;

      if (oldflags)
        sine_mapped[qmfband2] = 0;
      else
        sine_mapped[qmfband2] = (WORD8)transient_env;
    }
  }
}

VOID ixheaacd_map_34_params_to_20(WORD16 *params) {
  params[0] = ixheaacd_divideby3(params[0] + params[0] + params[1]);
  params[1] = ixheaacd_divideby3(params[1] + params[2] + params[2]);
  params[2] = ixheaacd_divideby3(params[3] + params[3] + params[4]);
  params[3] = ixheaacd_divideby3(params[4] + params[5] + params[5]);
  params[4] = ixheaacd_divideby2(params[6] + params[7]);
  params[5] = ixheaacd_divideby2(params[8] + params[9]);
  params[6] = params[10];
  params[7] = params[11];
  params[8] = ixheaacd_divideby2(params[12] + params[13]);
  params[9] = ixheaacd_divideby2(params[14] + params[15]);
  params[10] = params[16];
  params[11] = params[17];
  params[12] = params[18];
  params[13] = params[19];
  params[14] = ixheaacd_divideby2(params[20] + params[21]);
  params[15] = ixheaacd_divideby2(params[22] + params[23]);
  params[16] = ixheaacd_divideby2(params[24] + params[25]);
  params[17] = ixheaacd_divideby2(params[26] + params[27]);
  params[18] = ixheaacd_divideby2(
      ixheaacd_divideby2(params[28] + params[29] + params[30] + params[31]));
  params[19] = ixheaacd_divideby2(params[32] + params[33]);
}

extern const WORD16 ixheaacd_num_bands[3];

WORD16 ixheaacd_read_ps_data(ia_ps_dec_struct *ptr_ps_dec,
                             ia_bit_buf_struct *it_bit_buff,
                             WORD16 num_bits_left,
                             ia_ps_tables_struct *ps_tables_ptr) {
  WORD b, e, temp;
  const WORD16 num_env_tab[4] = {0, 1, 2, 4};
  WORD cnt_bits;
  ia_huffman_data_type huffman_table, huffman_df_table, huffman_dt_table;
  FLAG enable_ps_header;

  if (!ptr_ps_dec) {
    return 0;
  }

  cnt_bits = it_bit_buff->cnt_bits;

  enable_ps_header = ixheaacd_read_bits_buf(it_bit_buff, 1);

  if (enable_ps_header) {
    ptr_ps_dec->enable_iid = ixheaacd_read_bits_buf(it_bit_buff, 1);
    if (ptr_ps_dec->enable_iid) {
      ptr_ps_dec->iid_mode = ixheaacd_read_bits_buf(it_bit_buff, 3);
    }

    if (ptr_ps_dec->iid_mode > 2) {
      ptr_ps_dec->iid_quant = 1;
      ptr_ps_dec->iid_mode -= 3;
    } else {
      ptr_ps_dec->iid_quant = 0;
    }

    ptr_ps_dec->enable_icc = ixheaacd_read_bits_buf(it_bit_buff, 1);
    if (ptr_ps_dec->enable_icc) {
      ptr_ps_dec->icc_mode = ixheaacd_read_bits_buf(it_bit_buff, 3);
    }

    ptr_ps_dec->enable_ext = ixheaacd_read_bits_buf(it_bit_buff, 1);

    if (ptr_ps_dec->icc_mode > 2) {
      ptr_ps_dec->icc_mode -= 3;
    }
  }

  if ((ptr_ps_dec->enable_iid && ptr_ps_dec->iid_mode > 2) ||
      (ptr_ps_dec->enable_icc && ptr_ps_dec->icc_mode > 2)) {
    ptr_ps_dec->ps_data_present = 0;

    num_bits_left -= (cnt_bits - it_bit_buff->cnt_bits);

    while (num_bits_left > 8) {
      ixheaacd_read_bits_buf(it_bit_buff, 8);
      num_bits_left -= 8;
    }
    ixheaacd_read_bits_buf(it_bit_buff, num_bits_left);

    return (cnt_bits - it_bit_buff->cnt_bits);
  }

  ptr_ps_dec->frame_class = (FLAG)ixheaacd_read_bits_buf(it_bit_buff, 1);

  temp = ixheaacd_read_bits_buf(it_bit_buff, 2);

  if (ptr_ps_dec->frame_class == 0) {
    ptr_ps_dec->num_env = num_env_tab[temp];
  } else {
    ptr_ps_dec->num_env = (((1 + temp) << 8) >> 8);

    for (e = 1; e < ptr_ps_dec->num_env + 1; e++) {
      ptr_ps_dec->border_position[e] =
          (((ixheaacd_read_bits_buf(it_bit_buff, 5) + 1) << 8) >> 8);
    }
  }

  if (ptr_ps_dec->enable_iid) {
    if (ptr_ps_dec->iid_quant) {
      huffman_df_table = (ia_huffman_data_type)&ps_tables_ptr->huff_iid_df_fine;
      huffman_dt_table = (ia_huffman_data_type)&ps_tables_ptr->huff_iid_dt_fine;
    } else {
      huffman_df_table = (ia_huffman_data_type)&ps_tables_ptr->huff_iid_df;
      huffman_dt_table = (ia_huffman_data_type)&ps_tables_ptr->huff_iid_dt;
    }

    for (e = 0; e < ptr_ps_dec->num_env; e++) {
      ptr_ps_dec->iid_dt[e] = (FLAG)ixheaacd_read_bits_buf(it_bit_buff, 1);

      if (ptr_ps_dec->iid_dt[e]) {
        huffman_table = huffman_dt_table;
      } else {
        huffman_table = huffman_df_table;
      }

      for (b = 0; b < ixheaacd_num_bands[ptr_ps_dec->iid_mode]; b++) {
        ptr_ps_dec->iid_par_table[e][b] =
            ixheaacd_ssc_huff_dec(huffman_table, it_bit_buff);
      }
    }
  }

  if (ptr_ps_dec->enable_icc) {
    huffman_df_table = (ia_huffman_data_type)&ps_tables_ptr->huff_icc_df;
    huffman_dt_table = (ia_huffman_data_type)&ps_tables_ptr->huff_icc_dt;

    for (e = 0; e < ptr_ps_dec->num_env; e++) {
      ptr_ps_dec->icc_dt[e] = ixheaacd_read_bits_buf(it_bit_buff, 1);

      if (ptr_ps_dec->icc_dt[e]) {
        huffman_table = huffman_dt_table;
      } else {
        huffman_table = huffman_df_table;
      }

      for (b = 0; b < ixheaacd_num_bands[ptr_ps_dec->icc_mode]; b++) {
        ptr_ps_dec->icc_par_table[e][b] =
            ixheaacd_ssc_huff_dec(huffman_table, it_bit_buff);
      }
    }
  }

  if (ptr_ps_dec->enable_ext) {
    WORD32 cnt = ixheaacd_read_bits_buf(it_bit_buff, 4);

    if (cnt == 15) {
      cnt += ixheaacd_read_bits_buf(it_bit_buff, 8);
    }
    while (cnt--) {
      ixheaacd_read_bits_buf(it_bit_buff, 8);
    }
  }

  ptr_ps_dec->ps_data_present = 1;

  return (cnt_bits - it_bit_buff->cnt_bits);
}

VOID ixheaacd_invfilt_level_emphasis(ia_sbr_hf_generator_struct *ptr_hf_gen_str,
                                     WORD32 num_if_bands, WORD32 *inv_filt_mode,
                                     WORD32 *inv_filt_mode_prev,
                                     WORD32 *bw_array) {
  WORD32 i;
  WORD32 accu;
  WORD16 w1, w2;

  for (i = 0; i < num_if_bands; i++) {
    bw_array[i] =
        ixheaacd_inew_bw_table[inv_filt_mode_prev[i]][inv_filt_mode[i]];

    if (bw_array[i] < ptr_hf_gen_str->bw_array_prev[i]) {
      w1 = 0x6000;
      w2 = 0x2000;
    } else {
      w1 = 0x7400;
      w2 = 0x0c00;
    }
    accu = ixheaacd_add32(
        ixheaacd_mult32x16in32_shl(bw_array[i], w1),
        ixheaacd_mult32x16in32_shl(ptr_hf_gen_str->bw_array_prev[i], w2));

    if (accu < 0x02000000) {
      accu = 0;
    }

    if (accu >= 0x7f800000) {
      accu = 0x7f800000;
    }
    bw_array[i] = accu;
  }
}

typedef struct {
  FLOAT32 phi_0_1_real;
  FLOAT32 phi_0_1_imag;
  FLOAT32 phi_0_2_real;
  FLOAT32 phi_0_2_imag;
  FLOAT32 phi_1_1;
  FLOAT32 phi_1_2_real;
  FLOAT32 phi_1_2_imag;
  FLOAT32 phi_2_2;
  FLOAT32 det;
} ia_auto_corr_ele_struct;

static VOID ixheaacd_esbr_calc_co_variance(
    ia_auto_corr_ele_struct *pstr_auto_corr, FLOAT32 vec_x_real[][64],
    FLOAT32 vec_x_imag[][64], WORD32 bd, WORD32 len) {
  WORD32 j, jminus1, jminus2;

  memset(pstr_auto_corr, 0, sizeof(ia_auto_corr_ele_struct));

  for (j = 0; j < len; j++) {
    jminus1 = j - 1;
    jminus2 = jminus1 - 1;

    pstr_auto_corr->phi_0_1_real +=
        vec_x_real[j][bd] * vec_x_real[jminus1][bd] +
        vec_x_imag[j][bd] * vec_x_imag[jminus1][bd];

    pstr_auto_corr->phi_0_1_imag +=
        vec_x_imag[j][bd] * vec_x_real[jminus1][bd] -
        vec_x_real[j][bd] * vec_x_imag[jminus1][bd];

    pstr_auto_corr->phi_0_2_real +=
        vec_x_real[j][bd] * vec_x_real[jminus2][bd] +
        vec_x_imag[j][bd] * vec_x_imag[jminus2][bd];

    pstr_auto_corr->phi_0_2_imag +=
        vec_x_imag[j][bd] * vec_x_real[jminus2][bd] -
        vec_x_real[j][bd] * vec_x_imag[jminus2][bd];

    pstr_auto_corr->phi_1_1 +=
        vec_x_real[jminus1][bd] * vec_x_real[jminus1][bd] +
        vec_x_imag[jminus1][bd] * vec_x_imag[jminus1][bd];

    pstr_auto_corr->phi_1_2_real +=
        vec_x_real[jminus1][bd] * vec_x_real[jminus2][bd] +
        vec_x_imag[jminus1][bd] * vec_x_imag[jminus2][bd];

    pstr_auto_corr->phi_1_2_imag +=
        vec_x_imag[jminus1][bd] * vec_x_real[jminus2][bd] -
        vec_x_real[jminus1][bd] * vec_x_imag[jminus2][bd];

    pstr_auto_corr->phi_2_2 +=
        vec_x_real[jminus2][bd] * vec_x_real[jminus2][bd] +
        vec_x_imag[jminus2][bd] * vec_x_imag[jminus2][bd];
  }

  pstr_auto_corr->det =
      pstr_auto_corr->phi_1_1 * pstr_auto_corr->phi_2_2 -
      (pstr_auto_corr->phi_1_2_real * pstr_auto_corr->phi_1_2_real +
       pstr_auto_corr->phi_1_2_imag * pstr_auto_corr->phi_1_2_imag) *
          SBR_HF_RELAXATION_PARAM;
}

static void ixheaacd_esbr_chirp_fac_calc(WORD32 *inv_filt_mode,
                                         WORD32 *inv_filt_mode_prev,
                                         WORD32 num_if_bands, FLOAT32 *bw_array,
                                         FLOAT32 *bw_array_prev) {
  WORD32 i;

  for (i = 0; i < num_if_bands; i++) {
    bw_array[i] =
        ixheaacd_new_bw_table[inv_filt_mode_prev[i]][inv_filt_mode[i]];

    if (bw_array[i] < bw_array_prev[i])
      bw_array[i] = 0.75000f * bw_array[i] + 0.25000f * bw_array_prev[i];
    else
      bw_array[i] = 0.90625f * bw_array[i] + 0.09375f * bw_array_prev[i];

    if (bw_array[i] < 0.015625) bw_array[i] = 0;
  }
}

static void ixheaacd_gausssolve(WORD32 n, FLOAT32 a[][MAXDEG + 1], FLOAT32 b[],
                                FLOAT32 y[]) {
  WORD32 i, j, k, imax;
  FLOAT32 v;

  for (i = 0; i < n; i++) {
    imax = i;
    for (k = i + 1; k < n; k++) {
      if (fabs(a[k][i]) > fabs(a[imax][i])) {
        imax = k;
      }
    }
    if (imax != i) {
      v = b[imax];
      b[imax] = b[i];
      b[i] = v;
      for (j = i; j < n; j++) {
        v = a[imax][j];
        a[imax][j] = a[i][j];
        a[i][j] = v;
      }
    }

    v = a[i][i];

    b[i] /= v;
    for (j = i; j < n; j++) {
      a[i][j] /= v;
    }

    for (k = i + 1; k < n; k++) {
      v = a[k][i];
      b[k] -= v * b[i];
      for (j = i + 1; j < n; j++) {
        a[k][j] -= v * a[i][j];
      }
    }
  }

  for (i = n - 1; i >= 0; i--) {
    y[i] = b[i];
    for (j = i + 1; j < n; j++) {
      y[i] -= a[i][j] * y[j];
    }
  }
}

void ixheaacd_polyfit(WORD32 n, FLOAT32 y[], FLOAT32 p[]) {
  WORD32 i, j, k;
  FLOAT32 a[MAXDEG + 1][MAXDEG + 1];
  FLOAT32 b[MAXDEG + 1];
  FLOAT32 v[2 * MAXDEG + 1];

  for (i = 0; i <= MAXDEG; i++) {
    b[i] = 0.0f;
    for (j = 0; j <= MAXDEG; j++) {
      a[i][j] = 0.0f;
    }
  }

  for (k = 0; k < n; k++) {
    v[0] = 1.0;
    for (i = 1; i <= 2 * MAXDEG; i++) {
      v[i] = k * v[i - 1];
    }

    for (i = 0; i <= MAXDEG; i++) {
      b[i] += v[MAXDEG - i] * y[k];
      for (j = 0; j <= MAXDEG; j++) {
        a[i][j] += v[2 * MAXDEG - i - j];
      }
    }
  }

  ixheaacd_gausssolve(MAXDEG + 1, a, b, p);
}

VOID ixheaacd_pre_processing(FLOAT32 ptr_src_buf_real[][64],
                             FLOAT32 ptr_src_buf_imag[][64],
                             FLOAT32 gain_vector[], WORD32 num_bands,
                             WORD32 start_sample, WORD32 end_sample) {
  WORD32 k, i;
  FLOAT32 poly_coeff[4];
  FLOAT32 mean_enrg = 0;
  FLOAT32 low_env_slope[64];
  FLOAT32 low_env[64];
  FLOAT32 a0;
  FLOAT32 a1;
  FLOAT32 a2;
  FLOAT32 a3;

  for (k = 0; k < num_bands; k++) {
    FLOAT32 temp = 0;
    for (i = start_sample; i < end_sample; i++) {
      temp += ptr_src_buf_real[i][k] * ptr_src_buf_real[i][k] +
              ptr_src_buf_imag[i][k] * ptr_src_buf_imag[i][k];
    }
    temp /= (end_sample - start_sample);
    low_env[k] = (FLOAT32)(10 * log10(temp + 1));
    mean_enrg = mean_enrg + low_env[k];
  }
  mean_enrg /= num_bands;

  ixheaacd_polyfit(num_bands, low_env, poly_coeff);

  a0 = poly_coeff[0];
  a1 = poly_coeff[1];
  a2 = poly_coeff[2];
  a3 = poly_coeff[3];
  for (k = 0; k < num_bands; k++) {
    FLOAT32 x_low_l = (FLOAT32)k;
    FLOAT32 low_env_slope_l = a3;
    low_env_slope_l = low_env_slope_l + a2 * x_low_l;

    x_low_l = x_low_l * x_low_l;
    low_env_slope_l = low_env_slope_l + a1 * x_low_l;

    x_low_l = x_low_l * (FLOAT32)k;
    low_env_slope_l = low_env_slope_l + a0 * x_low_l;

    low_env_slope[k] = low_env_slope_l;
  }

  for (i = 0; i < num_bands; i++) {
    gain_vector[i] = (FLOAT32)pow(10, (mean_enrg - low_env_slope[i]) / 20.0f);
  }
}

WORD32 ixheaacd_generate_hf(FLOAT32 ptr_src_buf_real[][64],
                            FLOAT32 ptr_src_buf_imag[][64],
                            FLOAT32 ptr_ph_vocod_buf_real[][64],
                            FLOAT32 ptr_ph_vocod_buf_imag[][64],
                            FLOAT32 ptr_dst_buf_real[][64],
                            FLOAT32 ptr_dst_buf_imag[][64],
                            ia_sbr_frame_info_data_struct *ptr_frame_data,
                            ia_sbr_header_data_struct *ptr_header_data) {
  WORD32 bw_index, i, k, k2, patch = 0;
  WORD32 co_var_len;
  WORD32 start_sample, end_sample, goal_sb;
  WORD32 sb, source_start_band, patch_stride, num_bands_in_patch;
  WORD32 hbe_flag = ptr_header_data->hbe_flag;
  FLOAT32 a0r, a0i, a1r, a1i;
  FLOAT32 bw_array[MAX_NUM_PATCHES] = {0};

  ia_auto_corr_ele_struct str_auto_corr;

  WORD16 *ptr_invf_band_tbl =
      &ptr_header_data->pstr_freq_band_data->freq_band_tbl_noise[1];
  WORD32 num_if_bands = ptr_header_data->pstr_freq_band_data->num_nf_bands;
  WORD32 sub_band_start = ptr_header_data->pstr_freq_band_data->sub_band_start;
  WORD16 *f_master_tbl = ptr_header_data->pstr_freq_band_data->f_master_tbl;
  WORD32 num_mf_bands = ptr_header_data->pstr_freq_band_data->num_mf_bands;
  WORD32 *inv_filt_mode = ptr_frame_data->sbr_invf_mode;
  WORD32 *inv_filt_mode_prev = ptr_frame_data->sbr_invf_mode_prev;
  WORD32 sbr_patching_mode = ptr_frame_data->sbr_patching_mode;
  ia_frame_info_struct *p_frame_info = &ptr_frame_data->str_frame_info_details;
  WORD32 pre_proc_flag = ptr_header_data->pre_proc_flag;
  WORD32 is_usf_4 = ptr_header_data->is_usf_4;
  WORD32 fs = ptr_header_data->out_sampling_freq;

  WORD32 lsb = f_master_tbl[0];
  WORD32 usb = f_master_tbl[num_mf_bands];
  WORD32 xover_offset = sub_band_start - f_master_tbl[0];

  FLOAT32 bw = 0.0f;
  FLOAT32 fac = 0.0f;

  FLOAT32 gain;
  FLOAT32 gain_vector[64];

  WORD32 slope_length = 0;
  WORD32 first_slot_offset = p_frame_info->border_vec[0];
  WORD32 end_slot_offs = 0;

  FLOAT32 *bw_array_prev = ptr_frame_data->bw_array_prev;

  end_slot_offs = p_frame_info->border_vec[p_frame_info->num_env] - 16;
  if (is_usf_4) {
    start_sample = first_slot_offset * 4;
    end_sample = 64 + end_slot_offs * 4;
    co_var_len = 76;
  } else {
    start_sample = first_slot_offset * 2;
    end_sample = 32 + end_slot_offs * 2;
    co_var_len = 38;
  }

  if (pre_proc_flag) {
    ixheaacd_pre_processing(ptr_src_buf_real, ptr_src_buf_imag, gain_vector,
                            f_master_tbl[0], start_sample, end_sample);
  }

  ixheaacd_esbr_chirp_fac_calc(inv_filt_mode, inv_filt_mode_prev, num_if_bands,
                               bw_array, bw_array_prev);

  for (i = start_sample; i < end_sample; i++) {
    memset(ptr_dst_buf_real[i] + usb, 0, (64 - usb) * sizeof(FLOAT32));
    memset(ptr_dst_buf_imag[i] + usb, 0, (64 - usb) * sizeof(FLOAT32));
  }

  if (sbr_patching_mode || !hbe_flag) {
    FLOAT32 alpha_real[64][2], alpha_imag[64][2];

    for (k = 1; k < f_master_tbl[0]; k++) {
      ixheaacd_esbr_calc_co_variance(&str_auto_corr, &ptr_src_buf_real[0],
                                     &ptr_src_buf_imag[0], k, co_var_len);
      if (str_auto_corr.det == 0.0f) {
        alpha_real[k][1] = alpha_imag[k][1] = 0;
      } else {
        fac = 1.0f / str_auto_corr.det;
        alpha_real[k][1] =
            (str_auto_corr.phi_0_1_real * str_auto_corr.phi_1_2_real -
             str_auto_corr.phi_0_1_imag * str_auto_corr.phi_1_2_imag -
             str_auto_corr.phi_0_2_real * str_auto_corr.phi_1_1) *
            fac;
        alpha_imag[k][1] =
            (str_auto_corr.phi_0_1_imag * str_auto_corr.phi_1_2_real +
             str_auto_corr.phi_0_1_real * str_auto_corr.phi_1_2_imag -
             str_auto_corr.phi_0_2_imag * str_auto_corr.phi_1_1) *
            fac;
      }

      if (str_auto_corr.phi_1_1 == 0) {
        alpha_real[k][0] = alpha_imag[k][0] = 0;
      } else {
        fac = 1.0f / str_auto_corr.phi_1_1;
        alpha_real[k][0] = -(str_auto_corr.phi_0_1_real +
                             alpha_real[k][1] * str_auto_corr.phi_1_2_real +
                             alpha_imag[k][1] * str_auto_corr.phi_1_2_imag) *
                           fac;
        alpha_imag[k][0] = -(str_auto_corr.phi_0_1_imag +
                             alpha_imag[k][1] * str_auto_corr.phi_1_2_real -
                             alpha_real[k][1] * str_auto_corr.phi_1_2_imag) *
                           fac;
      }

      if ((alpha_real[k][0] * alpha_real[k][0] +
               alpha_imag[k][0] * alpha_imag[k][0] >=
           16.0f) ||
          (alpha_real[k][1] * alpha_real[k][1] +
               alpha_imag[k][1] * alpha_imag[k][1] >=
           16.0f)) {
        alpha_real[k][0] = 0.0f;
        alpha_imag[k][0] = 0.0f;
        alpha_real[k][1] = 0.0f;
        alpha_imag[k][1] = 0.0f;
      }
    }

    goal_sb = (WORD32)(2.048e6f / fs + 0.5f);
    {
      WORD32 index;
      if (goal_sb < f_master_tbl[num_mf_bands]) {
        for (index = 0; (f_master_tbl[index] < goal_sb); index++)
          ;
        goal_sb = f_master_tbl[index];
      } else {
        goal_sb = f_master_tbl[num_mf_bands];
      }
    }

    source_start_band = xover_offset + 1;
    sb = lsb + xover_offset;

    patch = 0;
    while (sb < usb) {
      if (MAX_NUM_PATCHES <= patch) return -1;
      ptr_frame_data->patch_param.start_subband[patch] = sb;
      num_bands_in_patch = goal_sb - sb;

      if (num_bands_in_patch >= lsb - source_start_band) {
        patch_stride = sb - source_start_band;
        patch_stride = patch_stride & ~1;
        num_bands_in_patch = lsb - (sb - patch_stride);
        num_bands_in_patch =
            ixheaacd_find_closest_entry(sb + num_bands_in_patch, f_master_tbl,
                                        (WORD16)(num_mf_bands), 0) -
            (WORD32)(sb);
      }

      patch_stride = num_bands_in_patch + sb - lsb;
      patch_stride = (patch_stride + 1) & ~1;

      source_start_band = 1;

      if (goal_sb - (sb + num_bands_in_patch) < 3) {
        goal_sb = usb;
      }

      if ((num_bands_in_patch < 3) && (patch > 0) &&
          (sb + num_bands_in_patch == usb)) {
        for (i = start_sample + slope_length; i < end_sample + slope_length;
             i++) {
          for (k2 = sb; k2 < sb + num_bands_in_patch; k2++) {
            ptr_dst_buf_real[i][k2] = 0.0f;
            ptr_dst_buf_imag[i][k2] = 0.0f;
          }
        }

        break;
      }

      if (num_bands_in_patch <= 0) {
        return -1;
      }

      for (k2 = sb; k2 < sb + num_bands_in_patch; k2++) {
        k = k2 - patch_stride;
        bw_index = 0;
        while (k2 >= ptr_invf_band_tbl[bw_index]) bw_index++;

        bw = bw_array[bw_index];

        a0r = bw * alpha_real[k][0];
        a0i = bw * alpha_imag[k][0];
        bw *= bw;
        a1r = bw * alpha_real[k][1];
        a1i = bw * alpha_imag[k][1];

        if (pre_proc_flag) {
          gain = gain_vector[k];
        } else {
          gain = 1.0f;
        }

        for (i = start_sample + slope_length; i < end_sample + slope_length;
             i++) {
          ptr_dst_buf_real[i][k2] = ptr_src_buf_real[i][k] * gain;

          ptr_dst_buf_imag[i][k2] = ptr_src_buf_imag[i][k] * gain;

          if (bw > 0.0f) {
            ptr_dst_buf_real[i][k2] += (a0r * ptr_src_buf_real[i - 1][k] -
                                        a0i * ptr_src_buf_imag[i - 1][k] +
                                        a1r * ptr_src_buf_real[i - 2][k] -
                                        a1i * ptr_src_buf_imag[i - 2][k]) *
                                       gain;
            ptr_dst_buf_imag[i][k2] += (a0i * ptr_src_buf_real[i - 1][k] +
                                        a0r * ptr_src_buf_imag[i - 1][k] +
                                        a1i * ptr_src_buf_real[i - 2][k] +
                                        a1r * ptr_src_buf_imag[i - 2][k]) *
                                       gain;
          }
        }
      }
      sb += num_bands_in_patch;
      patch++;
    }
  }

  if (hbe_flag && !sbr_patching_mode) {
    FLOAT32 alpha_real[2], alpha_imag[2];

    bw_index = 0, patch = 1;
    if (NULL == ptr_ph_vocod_buf_real || NULL == ptr_ph_vocod_buf_imag)
      return -1;

    for (k2 = sub_band_start; k2 < f_master_tbl[num_mf_bands]; k2++) {
      ixheaacd_esbr_calc_co_variance(&str_auto_corr, &ptr_ph_vocod_buf_real[0],
                                     &ptr_ph_vocod_buf_imag[0], k2, co_var_len);

      if (str_auto_corr.det == 0.0f) {
        alpha_real[1] = alpha_imag[1] = 0;
      } else {
        fac = 1.0f / str_auto_corr.det;
        alpha_real[1] =
            (str_auto_corr.phi_0_1_real * str_auto_corr.phi_1_2_real -
             str_auto_corr.phi_0_1_imag * str_auto_corr.phi_1_2_imag -
             str_auto_corr.phi_0_2_real * str_auto_corr.phi_1_1) *
            fac;
        alpha_imag[1] =
            (str_auto_corr.phi_0_1_imag * str_auto_corr.phi_1_2_real +
             str_auto_corr.phi_0_1_real * str_auto_corr.phi_1_2_imag -
             str_auto_corr.phi_0_2_imag * str_auto_corr.phi_1_1) *
            fac;
      }

      if (str_auto_corr.phi_1_1 == 0) {
        alpha_real[0] = alpha_imag[0] = 0;
      } else {
        fac = 1.0f / str_auto_corr.phi_1_1;
        alpha_real[0] = -(str_auto_corr.phi_0_1_real +
                          alpha_real[1] * str_auto_corr.phi_1_2_real +
                          alpha_imag[1] * str_auto_corr.phi_1_2_imag) *
                        fac;
        alpha_imag[0] = -(str_auto_corr.phi_0_1_imag +
                          alpha_imag[1] * str_auto_corr.phi_1_2_real -
                          alpha_real[1] * str_auto_corr.phi_1_2_imag) *
                        fac;
      }

      if (alpha_real[0] * alpha_real[0] + alpha_imag[0] * alpha_imag[0] >=
              16.0f ||
          alpha_real[1] * alpha_real[1] + alpha_imag[1] * alpha_imag[1] >=
              16.0f) {
        alpha_real[0] = 0.0f;
        alpha_imag[0] = 0.0f;
        alpha_real[1] = 0.0f;
        alpha_imag[1] = 0.0f;
      }

      while (k2 >= ptr_invf_band_tbl[bw_index]) bw_index++;

      bw = bw_array[bw_index];

      a0r = bw * alpha_real[0];
      a0i = bw * alpha_imag[0];
      bw *= bw;
      a1r = bw * alpha_real[1];
      a1i = bw * alpha_imag[1];

      if (bw > 0.0f) {
        for (i = start_sample; i < end_sample; i++) {
          FLOAT32 real1, imag1, real2, imag2, realTarget, imag_target;

          realTarget = ptr_ph_vocod_buf_real[i][k2];
          imag_target = ptr_ph_vocod_buf_imag[i][k2];
          real1 = ptr_ph_vocod_buf_real[i - 1][k2];
          imag1 = ptr_ph_vocod_buf_imag[i - 1][k2];
          real2 = ptr_ph_vocod_buf_real[i - 2][k2];
          imag2 = ptr_ph_vocod_buf_imag[i - 2][k2];
          realTarget +=
              ((a0r * real1 - a0i * imag1) + (a1r * real2 - a1i * imag2));
          imag_target +=
              ((a0i * real1 + a0r * imag1) + (a1i * real2 + a1r * imag2));

          ptr_dst_buf_real[i][k2] = realTarget;
          ptr_dst_buf_imag[i][k2] = imag_target;
        }
      } else {
        for (i = start_sample; i < end_sample; i++) {
          ptr_dst_buf_real[i][k2] = ptr_ph_vocod_buf_real[i][k2];
          ptr_dst_buf_imag[i][k2] = ptr_ph_vocod_buf_imag[i][k2];
        }
      }
    }
  }
  ptr_frame_data->patch_param.num_patches = patch;
  if (patch >= (MAX_NUM_PATCHES + 1)) return -1;
  for (i = 0; i < num_if_bands; i++) {
    bw_array_prev[i] = bw_array[i];
  }
  return 0;
}
