/******************************************************************************
 *                                                                            *
 * Copyright (C) 2023 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 <math.h>
#include <string.h>
#include "ixheaac_type_def.h"
#include "ixheaac_error_standards.h"
#include "ixheaace_error_codes.h"

#include "iusace_bitbuffer.h"
#include "iusace_cnst.h"
#include "impd_drc_common_enc.h"
#include "impd_drc_uni_drc.h"
#include "impd_drc_tables.h"
#include "impd_drc_api.h"
#include "impd_drc_uni_drc_eq.h"
#include "impd_drc_uni_drc_filter_bank.h"
#include "impd_drc_gain_enc.h"
#include "impd_drc_struct_def.h"
#include "impd_drc_enc.h"
#include "impd_drc_mux.h"

static IA_ERRORCODE impd_drc_get_drc_complexity_level(
    ia_drc_uni_drc_config_struct *pstr_uni_drc_config, ia_drc_gain_enc_struct *pstr_drc_gain_enc,
    ia_drc_instructions_uni_drc *pstr_drc_instructions_uni_drc, VOID *ptr_scratch) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX c, g, k, i, group;
  WORD32 band_count;
  WORD32 gain_set_index;
  WORD32 skip_set;
  WORD32 gain_set_index_offset;
  WORD32 parametric_drc_type = 0;
  WORD32 channel_count_side_chain;
  WORD32 channel_count_drom_downmix_id;
  WORD32 channel_count_temp;
  WORD32 weighting_filter_order;
  WORD32 channel_count = pstr_uni_drc_config->str_channel_layout.base_ch_count;
  FLOAT32 w_mod, cplx, cplx_tmp, ratio;
  ia_drc_gain_modifiers_struct *pstr_gain_modifiers = NULL;
  ia_drc_shape_filter_block_params_struct *pstr_shape_filter_block_params = NULL;
  ia_drc_gain_set_params_struct *pstr_gain_set_params = NULL;
  ia_drc_parametric_drc_instructions_struct *pstr_parametric_drc_instructions = NULL;
  ia_drc_parametric_drc_gain_set_params_struct *pstr_parametric_drc_gain_set_params = NULL;

  if (pstr_drc_instructions_uni_drc->drc_apply_to_downmix != 0 &&
      ((pstr_drc_instructions_uni_drc->downmix_id == 0x7F) ||
       (pstr_drc_instructions_uni_drc->additional_downmix_id_count != 0))) {
    channel_count = 1;
  } else if ((pstr_drc_instructions_uni_drc->drc_apply_to_downmix != 0) &&
             (pstr_drc_instructions_uni_drc->downmix_id != 0) &&
             (pstr_drc_instructions_uni_drc->downmix_id != 0x7F) &&
             (pstr_drc_instructions_uni_drc->additional_downmix_id_count == 0)) {
    for (i = 0; i < pstr_uni_drc_config->downmix_instructions_count; i++) {
      if (pstr_drc_instructions_uni_drc->downmix_id ==
          pstr_uni_drc_config->str_downmix_instructions[i].downmix_id) {
        break;
      }
    }
    if (i == pstr_uni_drc_config->downmix_instructions_count) {
      return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
    }
    channel_count = pstr_uni_drc_config->str_downmix_instructions[i].target_ch_count;
  }

  pstr_drc_instructions_uni_drc->drc_channel_count = channel_count;
  group = 0;
  for (c = 0; c < pstr_drc_instructions_uni_drc->drc_channel_count; c++) {
    gain_set_index = pstr_drc_instructions_uni_drc->gain_set_index[c];
    skip_set = FALSE;
    if (gain_set_index < 0) {
      pstr_drc_instructions_uni_drc->channel_group_for_channel[c] = -1;
    } else {
      for (k = c - 1; k >= 0; k--) {
        if (pstr_drc_instructions_uni_drc->gain_set_index[k] == gain_set_index) {
          pstr_drc_instructions_uni_drc->channel_group_for_channel[c] =
              pstr_drc_instructions_uni_drc->channel_group_for_channel[k];
          skip_set = TRUE;
        }
      }
      if (skip_set == FALSE) {
        pstr_drc_instructions_uni_drc->channel_group_for_channel[c] = group;
        group++;
      }
    }
  }
  if (group != pstr_drc_instructions_uni_drc->num_drc_channel_groups) {
    return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
  }

  for (g = 0; g < pstr_drc_instructions_uni_drc->num_drc_channel_groups; g++) {
    pstr_drc_instructions_uni_drc->num_channels_per_channel_group[g] = 0;
    for (c = 0; c < pstr_drc_instructions_uni_drc->drc_channel_count; c++) {
      if (pstr_drc_instructions_uni_drc->channel_group_for_channel[c] == g) {
        pstr_drc_instructions_uni_drc->num_channels_per_channel_group[g]++;
      }
    }
  }

  cplx = 0.0f;

  if (pstr_drc_gain_enc->domain == TIME_DOMAIN) {
    w_mod = COMPLEXITY_W_MOD_TIME;
  } else {
    w_mod = COMPLEXITY_W_MOD_SUBBAND;
  }
  for (c = 0; c < pstr_drc_instructions_uni_drc->drc_channel_count; c++) {
    if (pstr_drc_instructions_uni_drc->gain_set_index[c] >= 0) {
      cplx += w_mod;
    }
  }

  if (pstr_drc_gain_enc->domain != TIME_DOMAIN) {
    pstr_gain_set_params =
        pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coefficients_uni_drc_v1[0]
            .str_gain_set_params;
    for (c = 0; c < pstr_drc_instructions_uni_drc->drc_channel_count; c++) {
      gain_set_index = pstr_drc_instructions_uni_drc->gain_set_index[c];
      if (gain_set_index >= 0) {
        if (pstr_gain_set_params[gain_set_index].drc_band_type == 1) {
          band_count = pstr_gain_set_params[gain_set_index].band_count;
          if (band_count > 1) {
            cplx += COMPLEXITY_W_LAP * band_count;
          }
        }
      }
    }
  } else {
    err_code = impd_drc_init_all_filter_banks(
        &pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coefficients_uni_drc_v1[0],
        pstr_drc_instructions_uni_drc, &pstr_drc_gain_enc->str_filter_banks, ptr_scratch);

    if (err_code) return err_code;

    cplx += COMPLEXITY_W_IIR * pstr_drc_gain_enc->str_filter_banks.complexity;

    for (g = 0; g < pstr_drc_instructions_uni_drc->num_drc_channel_groups; g++) {
      pstr_gain_modifiers = &pstr_drc_instructions_uni_drc->str_gain_modifiers[g];
      if (pstr_gain_modifiers->shape_filter_present == 1) {
        cplx_tmp = 0.0f;
        pstr_shape_filter_block_params =
            &pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coefficients_uni_drc_v1[0]
                 .str_shape_filter_block_params[pstr_gain_modifiers->shape_filter_index];
        if (pstr_shape_filter_block_params->lf_cut_filter_present == 1) {
          cplx_tmp += COMPLEXITY_W_SHAPE;
        }
        if (pstr_shape_filter_block_params->lf_boost_filter_present == 1) {
          cplx_tmp += COMPLEXITY_W_SHAPE;
        }
        if (pstr_shape_filter_block_params->hf_cut_filter_present == 1) {
          cplx_tmp += COMPLEXITY_W_SHAPE * 2.0f;
        }
        if (pstr_shape_filter_block_params->hf_boost_filter_present == 1) {
          cplx_tmp += COMPLEXITY_W_SHAPE * 2.0f;
        }
        cplx += cplx_tmp * pstr_drc_instructions_uni_drc->num_channels_per_channel_group[g];
      }
    }
  }

  for (g = 0; g < pstr_drc_instructions_uni_drc->num_drc_channel_groups; g++) {
    gain_set_index_offset = 0;
    gain_set_index = -1;
    for (c = 0; c < pstr_drc_instructions_uni_drc->drc_channel_count; c++) {
      if (pstr_drc_instructions_uni_drc->channel_group_for_channel[c] == g) {
        gain_set_index = pstr_drc_instructions_uni_drc->gain_set_index[c];
        break;
      }
    }
    if (pstr_uni_drc_config->str_uni_drc_config_ext.drc_coefficients_uni_drc_v1_count > 0) {
      gain_set_index_offset =
          pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coefficients_uni_drc_v1[0]
              .gain_set_count;
      pstr_gain_set_params =
          pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coefficients_uni_drc_v1[0]
              .str_gain_set_params;
    }
    if (gain_set_index >= gain_set_index_offset) {
      pstr_parametric_drc_instructions = NULL;
      pstr_parametric_drc_gain_set_params =
          &pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coeff_parametric_drc
               .parametric_drc_gain_set_params[gain_set_index - gain_set_index_offset];
      for (i = 0;
           i < pstr_uni_drc_config->str_uni_drc_config_ext.parametric_drc_instructions_count;
           i++) {
        if (pstr_parametric_drc_gain_set_params->parametric_drc_id ==
            pstr_uni_drc_config->str_uni_drc_config_ext.str_parametric_drc_instructions[i]
                .parametric_drc_id) {
          pstr_parametric_drc_instructions =
              &pstr_uni_drc_config->str_uni_drc_config_ext.str_parametric_drc_instructions[i];
          break;
        }
      }
      if (pstr_parametric_drc_instructions != NULL) {
        if (pstr_parametric_drc_instructions->parametric_drc_preset_id_present) {
          switch (pstr_parametric_drc_instructions->parametric_drc_preset_id) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
              parametric_drc_type = PARAM_DRC_TYPE_FF;
              break;
            case 5:
              parametric_drc_type = PARAM_DRC_TYPE_LIM;
              break;
            default:
              return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
              break;
          }
        } else {
          parametric_drc_type = pstr_parametric_drc_instructions->parametric_drc_type;
        }
      }
      channel_count_side_chain = pstr_drc_instructions_uni_drc->num_channels_per_channel_group[g];
      if (pstr_parametric_drc_gain_set_params->side_chain_config_type == 1) {
        channel_count_temp = 0;
        if (pstr_parametric_drc_gain_set_params->downmix_id == 0x0) {
          channel_count_drom_downmix_id = pstr_uni_drc_config->str_channel_layout.base_ch_count;
        } else if (pstr_parametric_drc_gain_set_params->downmix_id == 0x7F) {
          channel_count_drom_downmix_id = 1;
        } else {
          for (i = 0; i < pstr_uni_drc_config->downmix_instructions_count; i++) {
            if (pstr_parametric_drc_gain_set_params->downmix_id ==
                pstr_uni_drc_config->str_downmix_instructions[i].downmix_id) {
              break;
            }
          }
          if (i == pstr_uni_drc_config->downmix_instructions_count) {
            return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
          }
          channel_count_drom_downmix_id =
              pstr_uni_drc_config->str_downmix_instructions[i].target_ch_count;
        }

        for (i = 0; i < channel_count_drom_downmix_id; i++) {
          if (pstr_parametric_drc_gain_set_params->level_estim_channel_weight[i] != 0) {
            channel_count_temp++;
          }
        }
        channel_count_side_chain = channel_count_temp;
      }
      if (pstr_parametric_drc_instructions != NULL) {
        if (pstr_drc_gain_enc->domain == TIME_DOMAIN) {
          if (parametric_drc_type == PARAM_DRC_TYPE_FF) {
            weighting_filter_order = 2;
            if (pstr_parametric_drc_instructions->parametric_drc_preset_id_present == 0) {
              if (pstr_parametric_drc_instructions->str_parametric_drc_type_feed_forward
                      .level_estim_k_weighting_type == 0) {
                weighting_filter_order = 0;
              } else if (pstr_parametric_drc_instructions->str_parametric_drc_type_feed_forward
                             .level_estim_k_weighting_type == 1) {
                weighting_filter_order = 1;
              }
            }
            cplx += channel_count_side_chain *
                        (COMPLEXITY_W_PARAM_DRC_FILT * weighting_filter_order + 1) +
                    3;
          } else if (parametric_drc_type == PARAM_DRC_TYPE_LIM) {
            ratio = 1.0f;
            if (pstr_parametric_drc_instructions->parametric_drc_look_ahead_present == 1) {
              ratio = (FLOAT32)pstr_parametric_drc_instructions->parametric_drc_look_ahead /
                      (FLOAT32)PARAM_DRC_TYPE_LIM_ATTACK_DEFAULT;
            }
            cplx += (FLOAT32)(channel_count_side_chain * COMPLEXITY_W_PARAM_LIM_FILT +
                              COMPLEXITY_W_PARAM_DRC_ATTACK * sqrt(ratio));
          }
        } else {
          if (parametric_drc_type == PARAM_DRC_TYPE_FF) {
            cplx += channel_count_side_chain * COMPLEXITY_W_PARAM_DRC_SUBBAND;
          }
        }
      }
    } else {
      if (pstr_drc_gain_enc->domain == TIME_DOMAIN && pstr_gain_set_params != NULL) {
        if (pstr_gain_set_params[gain_set_index].gain_interpolation_type ==
            GAIN_INTERPOLATION_TYPE_SPLINE) {
          cplx += COMPLEXITY_W_SPLINE;
        }
        if (pstr_gain_set_params[gain_set_index].gain_interpolation_type ==
            GAIN_INTERPOLATION_TYPE_LINEAR) {
          cplx += COMPLEXITY_W_LINEAR;
        }
      }
    }
  }

  if (pstr_drc_instructions_uni_drc->downmix_id == 0x7F) {
    channel_count = pstr_uni_drc_config->str_channel_layout.base_ch_count;
  }

  cplx = (FLOAT32)(log10(cplx / channel_count) / log10(2.0f));
  pstr_drc_instructions_uni_drc->drc_set_complexity_level = (WORD32)MAX(0, ceil(cplx));

  if (pstr_drc_instructions_uni_drc->drc_set_complexity_level > DRC_COMPLEXITY_LEVEL_MAX) {
    return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
  }

  return IA_NO_ERROR;
}

static IA_ERRORCODE impd_drc_get_eq_complexity_level(
    ia_drc_uni_drc_config_ext_struct *pstr_uni_drc_config_ext,
    ia_drc_gain_enc_struct *pstr_drc_params, ia_drc_eq_instructions_struct *pstr_eq_instructions,
    VOID *ptr_scratch, WORD32 *scratch_used) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  WORD32 subband_domain_mode;
  ia_drc_eq_set_struct *pstr_eq_set = &pstr_drc_params->str_eq_set;

  if ((pstr_drc_params->domain == TIME_DOMAIN) &&
      (pstr_eq_instructions->td_filter_cascade_present == 0) &&
      (pstr_eq_instructions->subband_gains_present == 0)) {
    pstr_eq_instructions->eq_set_complexity_level = 0;
    return err_code;
  }

  subband_domain_mode = SUBBAND_DOMAIN_MODE_OFF;
  if (pstr_eq_instructions->subband_gains_present == 1) {
    subband_domain_mode = SUBBAND_DOMAIN_MODE_QMF64;
  }
  memset(pstr_eq_set, 0, sizeof(ia_drc_eq_set_struct));

  err_code = impd_drc_derive_eq_set(&pstr_uni_drc_config_ext->str_eq_coefficients,
                                    pstr_eq_instructions, (FLOAT32)pstr_drc_params->sample_rate,
                                    pstr_drc_params->drc_frame_size, subband_domain_mode,
                                    pstr_eq_set, ptr_scratch, scratch_used);
  if (err_code & IA_FATAL_ERROR) {
    return err_code;
  }

  err_code =
      impd_drc_get_eq_complexity(pstr_eq_set, &pstr_eq_instructions->eq_set_complexity_level);
  if (err_code & IA_FATAL_ERROR) {
    return err_code;
  }

  return err_code;
}

static WORD32 impd_drc_encode_downmix_coefficient(FLOAT32 downmix_coeff, FLOAT32 downmix_offset) {
  WORD32 idx, code;
  FLOAT32 coeff_db;
  const FLOAT32 *coeff_table;

  coeff_table = impd_drc_downmix_coeff_v1;
  coeff_db = 20.0f * (FLOAT32)log10(downmix_coeff) - downmix_offset;

  if (coeff_db >= coeff_table[30]) {
    idx = 0;
    while (coeff_db < coeff_table[idx]) {
      idx++;
    }
    if ((idx > 0) && (coeff_db > 0.5f * (coeff_table[idx - 1] + coeff_table[idx]))) {
      idx--;
    }
    code = idx;
  } else {
    code = 31;
  }

  return code;
}

static VOID impd_drc_dec_write_downmix_coeff_v1(ia_bit_buf_struct *it_bit_buf,
                                                const FLOAT32 downmix_coeff[],
                                                const WORD32 base_ch_count,
                                                const WORD32 target_ch_count,
                                                WORD32 *ptr_bit_cnt) {
  LOOPIDX i, j;
  WORD32 bs_downmix_offset = 0, code;
  WORD32 bit_cnt_local = 0;
  FLOAT32 downmix_offset[3];
  FLOAT32 tmp;
  FLOAT32 quant_err, quant_err_min;
  const FLOAT32 *coeff_table;

  coeff_table = impd_drc_downmix_coeff_v1;
  tmp = (FLOAT32)log10((FLOAT32)target_ch_count / (FLOAT32)base_ch_count);
  downmix_offset[0] = 0.0f;
  downmix_offset[1] = (FLOAT32)(0.5f * floor(0.5f + 20.0f * tmp));
  downmix_offset[2] = (FLOAT32)(0.5f * floor(0.5f + 40.0f * tmp));

  quant_err_min = 1000.0f;
  for (i = 0; i < 3; i++) {
    quant_err = 0.0f;
    for (j = 0; j < (target_ch_count * base_ch_count); j++) {
      code = impd_drc_encode_downmix_coefficient(downmix_coeff[j], downmix_offset[i]);
      quant_err += (FLOAT32)fabs(20.0f * log10(downmix_coeff[j]) -
                                 (coeff_table[code] + downmix_offset[i]));
    }
    if (quant_err_min > quant_err) {
      quant_err_min = quant_err;
      bs_downmix_offset = i;
    }
  }

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_downmix_offset, 4);

  for (j = 0; j < target_ch_count * base_ch_count; j++) {
    code =
        impd_drc_encode_downmix_coefficient(downmix_coeff[j], downmix_offset[bs_downmix_offset]);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 5);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_enc_downmix_coeff(const FLOAT32 downmix_coeff_var,
                                       const WORD32 is_lfe_channel, WORD32 *code_size,
                                       WORD32 *code) {
  LOOPIDX idx;
  const FLOAT32 *coeff_table;
  FLOAT32 coeff_db;

  coeff_db = 20.0f * (FLOAT32)log10(downmix_coeff_var);

  if (is_lfe_channel == TRUE) {
    coeff_table = impd_drc_downmix_coeff_lfe;
  } else {
    coeff_table = impd_drc_downmix_coeff;
  }
  if (coeff_db >= coeff_table[14]) {
    idx = 0;
    while (coeff_db < coeff_table[idx]) {
      idx++;
    }
    if ((idx > 0) && (coeff_db > 0.5f * (coeff_table[idx - 1] + coeff_table[idx]))) {
      idx--;
    }
    *code = idx;
  } else {
    *code = 15;
  }

  *code_size = 4;
}

static VOID impd_drc_enc_peak(const FLOAT32 peak_level, WORD32 *code, WORD32 *code_size) {
  WORD32 bits;

  bits = ((WORD32)(0.5f + 32.0f * (20.0f - peak_level) + 10000.0f)) - 10000;
  bits = MIN(0x0FFF, bits);
  bits = MAX(0x1, bits);

  *code = bits;
  *code_size = 12;
}

static IA_ERRORCODE impd_drc_enc_method_value(const WORD32 method_definition,
                                              const FLOAT32 method_value, WORD32 *code_size,
                                              WORD32 *code) {
  WORD32 bits;
  switch (method_definition) {
    case METHOD_DEFINITION_UNKNOWN_OTHER:
    case METHOD_DEFINITION_PROGRAM_LOUDNESS:
    case METHOD_DEFINITION_ANCHOR_LOUDNESS:
    case METHOD_DEFINITION_MAX_OF_LOUDNESS_RANGE:
    case METHOD_DEFINITION_MOMENTARY_LOUDNESS_MAX:
    case METHOD_DEFINITION_SHORT_TERM_LOUDNESS_MAX:
      bits = ((WORD32)(0.5f + 4.0f * (method_value + 57.75f) + 10000.0f)) - 10000;
      bits = MIN(0x0FF, bits);
      bits = MAX(0x0, bits);
      *code_size = 8;
      break;
    case METHOD_DEFINITION_LOUDNESS_RANGE:
      if (method_value >= 121.0f) {
        bits = 255;
      } else if (method_value > 70.0f) {
        bits = ((WORD32)((method_value - 70.0f) + 0.5f)) + 204;
      } else if (method_value > 32.0f) {
        bits = ((WORD32)(2.0f * (method_value - 32.0f) + 0.5f)) + 128;
      } else if (method_value >= 0.0f) {
        bits = (WORD32)(4.0f * method_value + 0.5f);
      } else {
        bits = 0;
      }
      *code_size = 8;
      break;
    case METHOD_DEFINITION_MIXING_LEVEL:
      bits = (WORD32)(0.5f + method_value - 80.0f);
      bits = MIN(0x1F, bits);
      bits = MAX(0x0, bits);
      *code_size = 5;
      break;
    case METHOD_DEFINITION_ROOM_TYPE:
      bits = (WORD32)(0.5f + method_value);
      if (bits > 0x2) {
        return IA_EXHEAACE_CONFIG_FATAL_DRC_PARAM_OUT_OF_RANGE;
      }
      bits = MIN(0x2, bits);
      bits = MAX(0x0, bits);
      *code_size = 2;
      break;
    case METHOD_DEFINITION_SHORT_TERM_LOUDNESS:
      bits = ((WORD32)(0.5f + 2.0f * (method_value + 116.f) + 10000.0f)) - 10000;
      bits = MIN(0x0FF, bits);
      bits = MAX(0x0, bits);
      *code_size = 8;
      break;
    default: {
      return IA_EXHEAACE_CONFIG_FATAL_DRC_PARAM_OUT_OF_RANGE;
    }
  }
  *code = bits;

  return IA_NO_ERROR;
}

static VOID impd_drc_quantize_ducking_scaling(
    ia_drc_ducking_modifiers_struct *pstr_ducking_modifiers) {
  WORD32 mu;
  FLOAT32 delta;

  if (pstr_ducking_modifiers->ducking_scaling_present) {
    delta = pstr_ducking_modifiers->ducking_scaling - 1.0f;

    if (delta <= 0.0f) {
      mu = -1 + (WORD32)(0.5f - 8.0f * delta);
      if (mu != -1) {
        mu = MIN(7, mu);
        mu = MAX(0, mu);
        pstr_ducking_modifiers->ducking_scaling_quantized = 1.0f - 0.125f * (1.0f + mu);
      } else {
        pstr_ducking_modifiers->ducking_scaling_quantized = 1.0f;
        pstr_ducking_modifiers->ducking_scaling_present = FALSE;
      }
    } else {
      mu = -1 + (WORD32)(0.5f + 8.0f * delta);
      if (mu != -1) {
        mu = MIN(7, mu);
        mu = MAX(0, mu);
        pstr_ducking_modifiers->ducking_scaling_quantized = 1.0f + 0.125f * (1.0f + mu);
      } else {
        pstr_ducking_modifiers->ducking_scaling_quantized = 1.0f;
        pstr_ducking_modifiers->ducking_scaling_present = FALSE;
      }
    }
  } else {
    pstr_ducking_modifiers->ducking_scaling_quantized = 1.0f;
  }
}

static VOID impd_drc_enc_ducking_scaling(const FLOAT32 scaling, WORD32 *bits,
                                         FLOAT32 *scaling_quantized,
                                         WORD32 *remove_scaling_value) {
  WORD32 mu, sigma;
  FLOAT32 delta;

  delta = scaling - 1.0f;
  *remove_scaling_value = FALSE;
  if (delta <= 0.0f) {
    mu = -1 + (WORD32)(0.5f - 8.0f * delta);
    sigma = -1;
    *bits = 1 << 3;
  } else {
    mu = -1 + (WORD32)(0.5f + 8.0f * delta);
    sigma = 0;
    *bits = 0;
  }
  if (mu != -1) {
    mu = MIN(7, mu);
    mu = MAX(0, mu);
    *bits += mu;
    if (sigma == 0) {
      *scaling_quantized = 1.0f + 0.125f * (1.0f + mu);
    } else {
      *scaling_quantized = 1.0f - 0.125f * (1.0f + mu);
    }
  } else {
    *scaling_quantized = 1.0f;
    *remove_scaling_value = TRUE;
  }
}

static VOID impd_drc_enc_ducking_modifiers(
    ia_bit_buf_struct *it_bit_buf, ia_drc_ducking_modifiers_struct *pstr_ducking_modifiers,
    WORD32 *ptr_bit_cnt) {
  WORD32 bits;
  WORD32 remove_scaling_value;
  WORD32 bit_cnt_local = 0;

  if (pstr_ducking_modifiers->ducking_scaling_present == FALSE) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_ducking_modifiers->ducking_scaling_present, 1);
  } else {
    impd_drc_enc_ducking_scaling(pstr_ducking_modifiers->ducking_scaling, &bits,
                                 &(pstr_ducking_modifiers->ducking_scaling_quantized),
                                 &remove_scaling_value);

    if (remove_scaling_value) {
      pstr_ducking_modifiers->ducking_scaling_present = FALSE;
    }

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_ducking_modifiers->ducking_scaling_present, 1);

    if (pstr_ducking_modifiers->ducking_scaling_present) {
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bits, 4);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_enc_gain_modifiers(ia_bit_buf_struct *it_bit_buf, const WORD32 version,
                                        const WORD32 band_count,
                                        ia_drc_gain_modifiers_struct *pstr_gain_modifiers,
                                        WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 tmp, sign;
  WORD32 bit_cnt_local = 0;

  if (version == 1) {
    for (idx = 0; idx < band_count; idx++) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_gain_modifiers->target_characteristic_left_present[idx], 1);
      if (pstr_gain_modifiers->target_characteristic_left_present[idx]) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_gain_modifiers->target_characteristic_left_index[idx], 4);
      }

      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_gain_modifiers->target_characteristic_right_present[idx], 1);
      if (pstr_gain_modifiers->target_characteristic_right_present[idx]) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_gain_modifiers->target_characteristic_right_index[idx], 4);
      }

      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_gain_modifiers->gain_scaling_present[idx], 1);
      if (pstr_gain_modifiers->gain_scaling_present[idx]) {
        tmp = (WORD32)(0.5f + 8.0f * pstr_gain_modifiers->attenuation_scaling[idx]);
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, tmp, 4);

        tmp = (WORD32)(0.5f + 8.0f * pstr_gain_modifiers->amplification_scaling[idx]);
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, tmp, 4);
      }

      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_gain_modifiers->gain_offset_present[idx], 1);
      if (pstr_gain_modifiers->gain_offset_present[idx]) {
        if (pstr_gain_modifiers->gain_offset[idx] >= 0.0f) {
          tmp = (WORD32)(0.5f + MAX(0.0f, 4.0f * pstr_gain_modifiers->gain_offset[idx] - 1.0f));
          sign = 0;
        } else {
          tmp = (WORD32)(0.5f + MAX(0.0f, -4.0f * pstr_gain_modifiers->gain_offset[idx] - 1.0f));
          sign = 1;
        }
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, sign, 1);
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, tmp, 5);
      }
    }
    if (band_count == 1) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_gain_modifiers->shape_filter_present, 1);
      if (pstr_gain_modifiers->shape_filter_present) {
        bit_cnt_local +=
            iusace_write_bits_buf(it_bit_buf, pstr_gain_modifiers->shape_filter_index, 4);
      }
    }
  } else if (version == 0) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_gain_modifiers->gain_scaling_present[0], 1);

    if (pstr_gain_modifiers->gain_scaling_present[0]) {
      tmp = (WORD32)(0.5f + 8.0f * pstr_gain_modifiers->attenuation_scaling[0]);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, tmp, 4);

      tmp = (WORD32)(0.5f + 8.0f * pstr_gain_modifiers->amplification_scaling[0]);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, tmp, 4);
    }

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_gain_modifiers->gain_offset_present[0], 1);
    if (pstr_gain_modifiers->gain_offset_present[0]) {
      if (pstr_gain_modifiers->gain_offset[0] >= 0.0f) {
        tmp = (WORD32)(0.5f + MAX(0.0f, 4.0f * pstr_gain_modifiers->gain_offset[0] - 1.0f));
        sign = 0;
      } else {
        tmp = (WORD32)(0.5f + MAX(0.0f, -4.0f * pstr_gain_modifiers->gain_offset[0] - 1.0f));
        sign = 1;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, sign, 1);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, tmp, 5);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static IA_ERRORCODE impd_drc_write_loudness_measure(
    ia_bit_buf_struct *it_bit_buf, ia_drc_loudness_measure_struct *pstr_loudness_measure,
    WORD32 *ptr_bit_cnt) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  WORD32 code, code_size;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loudness_measure->method_definition, 4);

  err_code = impd_drc_enc_method_value(pstr_loudness_measure->method_definition,
                                       pstr_loudness_measure->method_value, &code_size, &code);
  if (err_code) return (err_code);

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, (UWORD8)code_size);
  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loudness_measure->measurement_system, 4);
  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loudness_measure->reliability, 2);

  *ptr_bit_cnt += bit_cnt_local;

  return IA_NO_ERROR;
}

static IA_ERRORCODE impd_drc_write_loudness_info(ia_bit_buf_struct *it_bit_buf,
                                                 const WORD32 version,
                                                 ia_drc_loudness_info_struct *pstr_loudness_info,
                                                 WORD32 *ptr_bit_cnt) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 code, code_size;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loudness_info->drc_set_id, 6);
  if (version >= 1) {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loudness_info->eq_set_id, 6);
  }
  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loudness_info->downmix_id, 7);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loudness_info->sample_peak_level_present, 1);
  if (pstr_loudness_info->sample_peak_level_present) {
    impd_drc_enc_peak(pstr_loudness_info->sample_peak_level, &code, &code_size);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, (UWORD8)code_size);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loudness_info->true_peak_level_present, 1);
  if (pstr_loudness_info->true_peak_level_present) {
    impd_drc_enc_peak(pstr_loudness_info->true_peak_level, &code, &code_size);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, (UWORD8)code_size);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_loudness_info->true_peak_level_measurement_system, 4);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_loudness_info->true_peak_level_reliability, 2);
  }

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loudness_info->measurement_count, 4);

  for (idx = 0; idx < pstr_loudness_info->measurement_count; idx++) {
    err_code = impd_drc_write_loudness_measure(
        it_bit_buf, &(pstr_loudness_info->str_loudness_measure[idx]), &bit_cnt_local);

    if (err_code) return (err_code);
  }

  *ptr_bit_cnt += bit_cnt_local;

  return IA_NO_ERROR;
}

static IA_ERRORCODE impd_drc_write_drc_instruct_uni_drc(
    ia_bit_buf_struct *it_bit_buf, const WORD32 version,
    ia_drc_uni_drc_config_struct *pstr_uni_drc_config, ia_drc_gain_enc_struct *pstr_gain_enc,
    ia_drc_instructions_uni_drc *pstr_drc_instructions_uni_drc, VOID *ptr_scratch,
    WORD32 *ptr_bit_cnt) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX i, j, n;
  WORD32 g, k, tmp, tmp_2, match, channel_count;
  WORD32 bs_sequence_index, sequence_index_prev, repeat_sequence_count;
  WORD32 ducking_sequence, index;
  WORD32 repeat_parameters_count;
  WORD32 bit_cnt_local = 0;
  WORD32 band_count = 0;
  WORD32 *unique_index;
  FLOAT32 *unique_scaling;
  FLOAT32 ducking_scaling_quantized_prev, factor;
  ia_drc_ducking_modifiers_struct *pstr_ducking_modifiers;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->drc_set_id, 6);
  if (version == 1) {
    err_code = impd_drc_get_drc_complexity_level(pstr_uni_drc_config, pstr_gain_enc,
                                                 pstr_drc_instructions_uni_drc, ptr_scratch);
    if (err_code & IA_FATAL_ERROR) {
      return (err_code);
    }

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_instructions_uni_drc->drc_set_complexity_level, 4);
  }

  unique_index = (WORD32 *)ptr_scratch;
  unique_scaling =
      (FLOAT32 *)((UWORD8 *)ptr_scratch + (MAX_CHANNEL_COUNT) * sizeof(unique_index[0]));
  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->drc_location, 4);

  if (version != 1) {
    pstr_drc_instructions_uni_drc->downmix_id_present = 1;
  } else {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->downmix_id_present, 1);
  }

  if (pstr_drc_instructions_uni_drc->downmix_id_present != 1) {
    pstr_drc_instructions_uni_drc->downmix_id = 0;
  } else {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->downmix_id, 7);
    if (version == 1) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_drc_instructions_uni_drc->drc_apply_to_downmix, 1);
    }
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_instructions_uni_drc->additional_downmix_id_present, 1);

    if (pstr_drc_instructions_uni_drc->additional_downmix_id_present) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_drc_instructions_uni_drc->additional_downmix_id_count, 3);
      for (i = 0; i < pstr_drc_instructions_uni_drc->additional_downmix_id_count; i++) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_drc_instructions_uni_drc->additional_downmix_id[i], 7);
      }
    } else {
      pstr_drc_instructions_uni_drc->additional_downmix_id_count = 0;
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->drc_set_effect, 16);

  if ((pstr_drc_instructions_uni_drc->drc_set_effect &
       (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) == 0) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_instructions_uni_drc->limiter_peak_target_present, 1);
    if (pstr_drc_instructions_uni_drc->limiter_peak_target_present) {
      tmp = (WORD32)(0.5f - 8.0f * pstr_drc_instructions_uni_drc->limiter_peak_target);
      tmp = MAX(0, tmp);
      tmp = MIN(0xFF, tmp);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, tmp, 8);
    }
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_drc_instructions_uni_drc->drc_set_target_loudness_present, 1);

  if (pstr_drc_instructions_uni_drc->drc_set_target_loudness_present == 1) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_instructions_uni_drc->drc_set_target_loudness_value_upper + 63, 6);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_instructions_uni_drc->drc_set_target_loudness_value_lower_present,
        1);
    if (pstr_drc_instructions_uni_drc->drc_set_target_loudness_value_lower_present == 1) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_drc_instructions_uni_drc->drc_set_target_loudness_value_lower + 63, 6);
    }
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_drc_instructions_uni_drc->depends_on_drc_set_present, 1);

  if (pstr_drc_instructions_uni_drc->depends_on_drc_set_present) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->depends_on_drc_set, 6);
  } else {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->no_independent_use, 1);
  }

  if (version == 1) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_instructions_uni_drc->requires_eq, 1);
  }

  channel_count = pstr_uni_drc_config->str_channel_layout.base_ch_count;
  if (pstr_drc_instructions_uni_drc->drc_set_effect &
      (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) {
    i = 0;
    while (i < channel_count) {
      pstr_ducking_modifiers = pstr_drc_instructions_uni_drc->str_ducking_modifiers_for_channel;
      bs_sequence_index = pstr_drc_instructions_uni_drc->gain_set_index[i] + 1;

      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_sequence_index, 6);

      impd_drc_enc_ducking_modifiers(it_bit_buf, &(pstr_ducking_modifiers[i]), &bit_cnt_local);

      sequence_index_prev = pstr_drc_instructions_uni_drc->gain_set_index[i];
      ducking_scaling_quantized_prev = pstr_ducking_modifiers[i].ducking_scaling_quantized;
      i++;

      if (i < channel_count) {
        impd_drc_quantize_ducking_scaling(&(pstr_ducking_modifiers[i]));
      }

      repeat_parameters_count = 0;
      while ((i < channel_count) && (repeat_parameters_count <= 32) &&
             (sequence_index_prev == pstr_drc_instructions_uni_drc->gain_set_index[i]) &&
             (ducking_scaling_quantized_prev ==
              pstr_ducking_modifiers[i].ducking_scaling_quantized)) {
        repeat_parameters_count++;
        i++;
        if (i < channel_count) {
          impd_drc_quantize_ducking_scaling(&(pstr_ducking_modifiers[i]));
        }
      }
      if (repeat_parameters_count <= 0) {
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 0, 1);
      } else {
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 1, 1);
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, repeat_parameters_count - 1, 5);
      }
    }
    for (j = 0; j < MAX_CHANNEL_COUNT; j++) {
      unique_index[j] = -10;
      unique_scaling[j] = -10.0f;
    }

    ducking_sequence = -1;
    g = 0;

    if (pstr_drc_instructions_uni_drc->drc_set_effect & EFFECT_BIT_DUCK_SELF) {
      for (j = 0; j < channel_count; j++) {
        match = FALSE;
        index = pstr_drc_instructions_uni_drc->gain_set_index[j];
        factor =
            pstr_drc_instructions_uni_drc->str_ducking_modifiers_for_channel[j].ducking_scaling;
        for (n = 0; n < g; n++) {
          if ((index >= 0) && (unique_index[n] == index) && (unique_scaling[n] == factor)) {
            match = TRUE;
            break;
          }
        }
        if (match == FALSE) {
          if (index >= 0) {
            unique_index[g] = index;
            unique_scaling[g] = factor;
            g++;
          }
        }
      }
      pstr_drc_instructions_uni_drc->num_drc_channel_groups = g;
    } else if (pstr_drc_instructions_uni_drc->drc_set_effect & EFFECT_BIT_DUCK_OTHER) {
      for (j = 0; j < channel_count; j++) {
        match = FALSE;
        index = pstr_drc_instructions_uni_drc->gain_set_index[j];
        factor =
            pstr_drc_instructions_uni_drc->str_ducking_modifiers_for_channel[j].ducking_scaling;
        for (n = 0; n < g; n++) {
          if (((index >= 0) && (unique_index[n] == index)) ||
              ((index < 0) && (unique_scaling[n] == factor))) {
            match = TRUE;
            break;
          }
        }
        if (match == FALSE) {
          if (index < 0) {
            unique_index[g] = index;
            unique_scaling[g] = factor;
            g++;
          } else {
            if ((ducking_sequence > 0) && (ducking_sequence != index)) {
              return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
            }
            ducking_sequence = index;
          }
        }
      }
      pstr_drc_instructions_uni_drc->num_drc_channel_groups = g;
      if (ducking_sequence < 0) {
        return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
      }
    }

    for (g = 0; g < pstr_drc_instructions_uni_drc->num_drc_channel_groups; g++) {
      if (pstr_drc_instructions_uni_drc->drc_set_effect & EFFECT_BIT_DUCK_SELF) {
        pstr_drc_instructions_uni_drc->gain_set_index_for_channel_group[g] = unique_index[g];
      } else if (pstr_drc_instructions_uni_drc->drc_set_effect & EFFECT_BIT_DUCK_OTHER) {
        pstr_drc_instructions_uni_drc->gain_set_index_for_channel_group[g] = -1;
      }

      pstr_drc_instructions_uni_drc->str_ducking_modifiers_for_channel_group[g].ducking_scaling =
          unique_scaling[g];
      if (unique_scaling[g] == 1.0f) {
        pstr_drc_instructions_uni_drc->str_ducking_modifiers_for_channel_group[g]
            .ducking_scaling_present = FALSE;
      } else {
        pstr_drc_instructions_uni_drc->str_ducking_modifiers_for_channel_group[g]
            .ducking_scaling_present = TRUE;
      }
    }
  } else {
    if ((version == 0 || pstr_drc_instructions_uni_drc->drc_apply_to_downmix != 0) &&
        ((pstr_drc_instructions_uni_drc->downmix_id == 0x7F) ||
         (pstr_drc_instructions_uni_drc->additional_downmix_id_count != 0))) {
      channel_count = 1;
    } else if ((version == 0 || pstr_drc_instructions_uni_drc->drc_apply_to_downmix != 0) &&
               (pstr_drc_instructions_uni_drc->downmix_id != 0) &&
               (pstr_drc_instructions_uni_drc->downmix_id != 0x7F) &&
               (pstr_drc_instructions_uni_drc->additional_downmix_id_count == 0)) {
      for (i = 0; i < pstr_uni_drc_config->downmix_instructions_count; i++) {
        if (pstr_drc_instructions_uni_drc->downmix_id ==
            pstr_uni_drc_config->str_downmix_instructions[i].downmix_id) {
          break;
        }
      }
      if (i == pstr_uni_drc_config->downmix_instructions_count) {
        return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
      }
      channel_count = pstr_uni_drc_config->str_downmix_instructions[i].target_ch_count;
    }

    i = 0;
    while (i < channel_count) {
      bs_sequence_index = pstr_drc_instructions_uni_drc->gain_set_index[i] + 1;
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_sequence_index, 6);
      sequence_index_prev = pstr_drc_instructions_uni_drc->gain_set_index[i];
      i++;

      repeat_sequence_count = 0;
      while ((i < channel_count) &&
             (sequence_index_prev == pstr_drc_instructions_uni_drc->gain_set_index[i]) &&
             (repeat_sequence_count <= 32)) {
        repeat_sequence_count++;
        i++;
      }
      if (repeat_sequence_count <= 0) {
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 0, 1);
      } else {
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 1, 1);
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, repeat_sequence_count - 1, 5);
      }
    }
    for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
      unique_index[i] = -1;
    }

    k = 0;
    for (i = 0; i < channel_count; i++) {
      tmp_2 = pstr_drc_instructions_uni_drc->gain_set_index[i];
      if (tmp_2 >= 0) {
        match = FALSE;
        for (n = 0; n < k; n++) {
          if (unique_index[n] == tmp_2) {
            match = TRUE;
          }
        }
        if (match == FALSE) {
          unique_index[k] = tmp_2;
          k++;
        }
      }
    }
    pstr_drc_instructions_uni_drc->num_drc_channel_groups = k;
    for (i = 0; i < pstr_drc_instructions_uni_drc->num_drc_channel_groups; i++) {
      band_count = 0;
      pstr_drc_instructions_uni_drc->gain_set_index_for_channel_group[i] = unique_index[i];

      if (pstr_uni_drc_config->str_uni_drc_config_ext.drc_coefficients_uni_drc_v1_count > 0) {
        band_count =
            pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coefficients_uni_drc_v1[0]
                .str_gain_set_params[pstr_drc_instructions_uni_drc
                                         ->gain_set_index_for_channel_group[i]]
                .band_count;
      } else if (pstr_uni_drc_config->drc_coefficients_uni_drc_count > 0) {
        band_count = pstr_uni_drc_config->str_drc_coefficients_uni_drc[0]
                         .str_gain_set_params[pstr_drc_instructions_uni_drc
                                                  ->gain_set_index_for_channel_group[i]]
                         .band_count;
      }

      impd_drc_enc_gain_modifiers(it_bit_buf, version, band_count,
                                  &(pstr_drc_instructions_uni_drc->str_gain_modifiers[i]),
                                  &bit_cnt_local);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
  return err_code;
}

#ifdef LOUDNESS_LEVELING_SUPPORT
static UWORD32 get_num_ducking_only_drc_sets(
    ia_drc_instructions_uni_drc const *pstr_drc_instructions_uni_drc,
    UWORD32 drc_intructions_uni_drc_count) {
  UWORD32 num_ducking_only_drc_sets = 0;
  for (UWORD16 i = 0; i < drc_intructions_uni_drc_count; i++) {
    if (pstr_drc_instructions_uni_drc[i].ducking_only_set_present) {
      num_ducking_only_drc_sets++;
    }
  }

  return num_ducking_only_drc_sets;
}

static WORD32 write_loudness_leveling_extension(ia_bit_buf_struct *it_bit_buf,
                                                ia_drc_uni_drc_config_struct *pstr_uni_drc_config,
                                                ia_drc_gain_enc_struct *pstr_gain_enc,
                                                VOID *ptr_scratch, WORD32 *bit_cnt) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  WORD32 bit_cnt_local = 0;
  WORD32 drc_instructions_uni_drc_count_v1 =
      pstr_uni_drc_config->str_uni_drc_config_ext.drc_instructions_uni_drc_v1_count;
  WORD32 drc_instructions_uni_drc_count = pstr_uni_drc_config->drc_instructions_uni_drc_count;
  WORD32 version = 0;
  WORD16 ducking_set_expected = 0;
  // V0 instructions
  for (WORD16 i = 0; i < drc_instructions_uni_drc_count; i++) {
    ia_drc_instructions_uni_drc *pstr_drc_instruction =
        &pstr_uni_drc_config->str_drc_instructions_uni_drc[i];
    if (pstr_drc_instruction->drc_set_effect & EFFECT_BIT_DUCK_SELF) {
      if (ducking_set_expected) {
        ia_drc_instructions_uni_drc *pstr_drc_instruction_prev =
            &pstr_uni_drc_config->str_drc_instructions_uni_drc[i - 1];
        if (pstr_drc_instruction_prev->ducking_only_set_present) {
          err_code = impd_drc_write_drc_instruct_uni_drc(it_bit_buf, version, pstr_uni_drc_config,
                                                         pstr_gain_enc, pstr_drc_instruction,
                                                         ptr_scratch, &bit_cnt_local);
          if (err_code & IA_FATAL_ERROR) {
            return (err_code);
          }
        }
        ducking_set_expected = 0;
      } else {
        bit_cnt_local +=
            iusace_write_bits_buf(it_bit_buf, pstr_drc_instruction->leveling_present, 1);
        if (pstr_drc_instruction->leveling_present) {
          ducking_set_expected = 1;
          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_drc_instruction->ducking_only_set_present, 1);
          continue;
        }
      }
    }
  }

  // V1 instructions
  version = 1;
  ducking_set_expected = 0;
  for (WORD16 i = 0; i < drc_instructions_uni_drc_count_v1; i++) {
    ia_drc_instructions_uni_drc *pstr_drc_instruction =
        &pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_instructions_uni_drc_v1[i];
    if (pstr_drc_instruction->drc_set_effect & EFFECT_BIT_DUCK_SELF) {
      if (ducking_set_expected) {
        ia_drc_instructions_uni_drc *pstr_drc_instruction_prev =
            &pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_instructions_uni_drc_v1[i - 1];
        if (pstr_drc_instruction_prev->ducking_only_set_present) {
          err_code = impd_drc_write_drc_instruct_uni_drc(it_bit_buf, version, pstr_uni_drc_config,
                                                         pstr_gain_enc, pstr_drc_instruction,
                                                         ptr_scratch, &bit_cnt_local);
          if (err_code & IA_FATAL_ERROR) {
            return (err_code);
          }
        }
        ducking_set_expected = 0;
      } else {
        bit_cnt_local +=
            iusace_write_bits_buf(it_bit_buf, pstr_drc_instruction->leveling_present, 1);
        if (pstr_drc_instruction->leveling_present) {
          ducking_set_expected = 1;
          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_drc_instruction->ducking_only_set_present, 1);
          continue;
        }
      }
    }
  }
  *bit_cnt += bit_cnt_local;
  return IA_NO_ERROR;
}
#endif

static VOID impd_drc_write_gain_params(ia_bit_buf_struct *it_bit_buf, const WORD32 version,
                                       const WORD32 band_count, const WORD32 drc_band_type,
                                       ia_drc_gain_params_struct *pstr_gain_params,
                                       WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 bit_cnt_local = 0;

  if (version != 1) {
    for (idx = 0; idx < band_count; idx++) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_gain_params[idx].drc_characteristic, 7);
    }
  } else {
    WORD32 index_present;
    WORD32 gain_sequence_index_last = -1;
    for (idx = 0; idx < band_count; idx++) {
      if (pstr_gain_params[idx].gain_sequence_index == gain_sequence_index_last + 1) {
        index_present = 0;
      } else {
        index_present = 1;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, index_present, 1);

      if (index_present == 1) {
        bit_cnt_local +=
            iusace_write_bits_buf(it_bit_buf, pstr_gain_params[idx].gain_sequence_index, 6);
        gain_sequence_index_last = pstr_gain_params[idx].gain_sequence_index;
      }

      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_gain_params[idx].drc_characteristic_present, 1);
      if (pstr_gain_params[idx].drc_characteristic_present) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_gain_params[idx].drc_characteristic_format_is_cicp, 1);
        if (pstr_gain_params[idx].drc_characteristic_format_is_cicp == 1) {
          bit_cnt_local +=
              iusace_write_bits_buf(it_bit_buf, pstr_gain_params[idx].drc_characteristic, 7);
        } else {
          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_gain_params[idx].drc_characteristic_left_index, 4);

          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_gain_params[idx].drc_characteristic_right_index, 4);
        }
      }
    }
  }

  for (idx = 1; idx < band_count; idx++) {
    if (drc_band_type) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_gain_params[idx].crossover_freq_index, 4);
    } else {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_gain_params[idx].start_sub_band_index, 10);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_gain_set_params(ia_bit_buf_struct *it_bit_buf, const WORD32 version,
                                           ia_drc_gain_set_params_struct *pstr_gain_set_params,
                                           WORD32 *ptr_bit_cnt) {
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->gain_coding_profile, 2);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->gain_interpolation_type, 1);

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->full_frame, 1);

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->time_alignment, 1);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->time_delta_min_present, 1);

  if (pstr_gain_set_params->time_delta_min_present) {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->delta_tmin - 1, 11);
  }
  if (pstr_gain_set_params->gain_coding_profile != GAIN_CODING_PROFILE_CONSTANT) {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->band_count, 4);
    if (pstr_gain_set_params->band_count > 1) {
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_gain_set_params->drc_band_type, 1);
    }

    impd_drc_write_gain_params(it_bit_buf, version, pstr_gain_set_params->band_count,
                               pstr_gain_set_params->drc_band_type,
                               pstr_gain_set_params->gain_params, &bit_cnt_local);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_split_drc_characteristic(
    ia_bit_buf_struct *it_bit_buf, const WORD32 side,
    ia_drc_split_drc_characteristic_struct *pstr_split_characteristic, WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 bs_node_gain, bs_node_level_delta;
  WORD32 bit_cnt_local = 0;
  FLOAT32 bs_node_level_previous;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_split_characteristic->characteristic_format, 1);

  if (pstr_split_characteristic->characteristic_format != 0) {
    bs_node_level_previous = DRC_INPUT_LOUDNESS_TARGET;

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_split_characteristic->characteristic_node_count - 1, 2);

    for (idx = 1; idx <= pstr_split_characteristic->characteristic_node_count; idx++) {
      bs_node_level_delta = (WORD32)(floor(fabs(pstr_split_characteristic->node_level[idx] -
                                                bs_node_level_previous) +
                0.5f) -
          1);

      if (bs_node_level_delta < 0) {
        bs_node_level_delta = 0;
      }
      if (bs_node_level_delta > 31) {
        bs_node_level_delta = 31;
      }
      if (side == RIGHT_SIDE) {
        bs_node_level_previous = bs_node_level_previous + (bs_node_level_delta + 1);
      } else {
        bs_node_level_previous = bs_node_level_previous - (bs_node_level_delta + 1);
      }

      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_node_level_delta, 5);

      bs_node_gain =
          (WORD32)floor((pstr_split_characteristic->node_gain[idx] + 64.0f) * 2.0f + 0.5f);

      if (bs_node_gain < 0) {
        bs_node_gain = 0;
      }
      if (bs_node_gain > 255) {
        bs_node_gain = 255;
      }

      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_node_gain, 8);
    }
  } else {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_split_characteristic->bs_gain, 6);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_split_characteristic->bs_io_ratio, 4);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_split_characteristic->bs_exp, 4);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_split_characteristic->flip_sign, 1);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_shape_filter_block_params(
    ia_bit_buf_struct *it_bit_buf,
    ia_drc_shape_filter_block_params_struct *pstr_shape_filter_block_params,
    WORD32 *ptr_bit_cnt) {
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_shape_filter_block_params->lf_cut_filter_present, 1);
  if (pstr_shape_filter_block_params->lf_cut_filter_present == 1) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_lf_cut_params.corner_freq_index, 3);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_lf_cut_params.filter_strength_index, 2);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_shape_filter_block_params->lf_boost_filter_present, 1);
  if (pstr_shape_filter_block_params->lf_boost_filter_present == 1) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_lf_boost_params.corner_freq_index, 3);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_lf_boost_params.filter_strength_index, 2);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_shape_filter_block_params->hf_cut_filter_present, 1);
  if (pstr_shape_filter_block_params->hf_cut_filter_present == 1) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_hf_cut_params.corner_freq_index, 3);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_hf_cut_params.filter_strength_index, 2);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_shape_filter_block_params->hf_boost_filter_present, 1);
  if (pstr_shape_filter_block_params->hf_boost_filter_present == 1) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_hf_boost_params.corner_freq_index, 3);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_shape_filter_block_params->str_hf_boost_params.filter_strength_index, 2);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_drc_coeff_uni_drc(
    ia_bit_buf_struct *it_bit_buf, const WORD32 version,
    ia_drc_coefficients_uni_drc_struct *pstr_drc_coefficients_uni_drc, WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_drc_coefficients_uni_drc->drc_location, 4);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_drc_coefficients_uni_drc->drc_frame_size_present, 1);

  if (pstr_drc_coefficients_uni_drc->drc_frame_size_present) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, (pstr_drc_coefficients_uni_drc->drc_frame_size - 1), 15);
  }

  if (version != 1) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_coefficients_uni_drc->gain_set_count, 6);

    for (idx = 0; idx < pstr_drc_coefficients_uni_drc->gain_set_count; idx++) {
      impd_drc_write_gain_set_params(it_bit_buf, version,
                                     &(pstr_drc_coefficients_uni_drc->str_gain_set_params[idx]),
                                     &bit_cnt_local);
    }
  } else {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_coefficients_uni_drc->drc_characteristic_left_present, 1);
    if (pstr_drc_coefficients_uni_drc->drc_characteristic_left_present) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_drc_coefficients_uni_drc->characteristic_left_count, 4);

      for (idx = 1; idx <= pstr_drc_coefficients_uni_drc->characteristic_left_count; idx++) {
        impd_drc_write_split_drc_characteristic(
            it_bit_buf, LEFT_SIDE,
            &pstr_drc_coefficients_uni_drc->str_split_characteristic_left[idx], &bit_cnt_local);
      }
    }

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_coefficients_uni_drc->drc_characteristic_right_present, 1);
    if (pstr_drc_coefficients_uni_drc->drc_characteristic_right_present) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_drc_coefficients_uni_drc->characteristic_right_count, 4);
      for (idx = 1; idx <= pstr_drc_coefficients_uni_drc->characteristic_right_count; idx++) {
        impd_drc_write_split_drc_characteristic(
            it_bit_buf, RIGHT_SIDE,
            &pstr_drc_coefficients_uni_drc->str_split_characteristic_right[idx], &bit_cnt_local);
      }
    }

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_drc_coefficients_uni_drc->shape_filters_present, 1);
    if (pstr_drc_coefficients_uni_drc->shape_filters_present) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_drc_coefficients_uni_drc->shape_filter_count, 4);
      for (idx = 1; idx <= pstr_drc_coefficients_uni_drc->shape_filter_count; idx++) {
        impd_drc_write_shape_filter_block_params(
            it_bit_buf, &pstr_drc_coefficients_uni_drc->str_shape_filter_block_params[idx],
            &bit_cnt_local);
      }
    }

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_coefficients_uni_drc->gain_sequence_count, 6);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_coefficients_uni_drc->gain_set_count, 6);

    for (idx = 0; idx < pstr_drc_coefficients_uni_drc->gain_set_count; idx++) {
      impd_drc_write_gain_set_params(it_bit_buf, version,
                                     &(pstr_drc_coefficients_uni_drc->str_gain_set_params[idx]),
                                     &bit_cnt_local);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_downmix_instructions(
    ia_bit_buf_struct *it_bit_buf, const WORD32 version, ia_drc_gain_enc_struct *pstr_gain_enc,
    ia_drc_downmix_instructions_struct *pstr_downmix_instructions, WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 code, code_size;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_downmix_instructions->downmix_id, 7);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_downmix_instructions->target_ch_count, 7);

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_downmix_instructions->target_layout, 8);

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_downmix_instructions->downmix_coefficients_present, 1);

  if (pstr_downmix_instructions->downmix_coefficients_present) {
    if (version != 1) {
      WORD32 is_lfe_channel = FALSE;
      for (idx = 0;
           idx < (pstr_downmix_instructions->target_ch_count * pstr_gain_enc->base_ch_count);
           idx++) {
        impd_drc_enc_downmix_coeff(pstr_downmix_instructions->downmix_coeff[idx], is_lfe_channel,
                                   &code_size, &code);
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, (UWORD8)code_size);
      }
    } else {
      impd_drc_dec_write_downmix_coeff_v1(
          it_bit_buf, pstr_downmix_instructions->downmix_coeff, pstr_gain_enc->base_ch_count,
          pstr_downmix_instructions->target_ch_count, &bit_cnt_local);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_enc_channel_weight(const FLOAT32 channel_weight_lin, WORD32 *code_size,
                                        WORD32 *code) {
  LOOPIDX idx;
  FLOAT32 channel_weight_db;
  const FLOAT32 *channel_weight_table;

  channel_weight_table = impd_drc_channel_weight;
  channel_weight_db = 20.0f * (FLOAT32)log10(channel_weight_lin);

  if (channel_weight_db >= channel_weight_table[14]) {
    idx = 0;
    while (channel_weight_db < channel_weight_table[idx]) {
      idx++;
    }
    if ((idx > 0) && (channel_weight_db >
                      0.5f * (channel_weight_table[idx - 1] + channel_weight_table[idx]))) {
      idx--;
    }
    *code = idx;
  } else {
    *code = 15;
  }

  *code_size = 4;
}

static IA_ERRORCODE impd_drc_write_parametric_drc_gain_set_params(
    ia_bit_buf_struct *it_bit_buf, ia_drc_uni_drc_config_struct *pstr_uni_drc_config,
    ia_drc_parametric_drc_gain_set_params_struct *pstr_parametric_drc_gain_set_params,
    WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 code_size = 0, code = 0;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_gain_set_params->parametric_drc_id, 4);

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_gain_set_params->side_chain_config_type, 3);

  if (pstr_parametric_drc_gain_set_params->side_chain_config_type == 1) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_parametric_drc_gain_set_params->downmix_id, 7);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_gain_set_params->level_estim_channel_weight_format, 1);

    if (pstr_parametric_drc_gain_set_params->downmix_id == 0x7F) {
      pstr_parametric_drc_gain_set_params->channel_count_drom_downmix_id = 1;
    } else if (pstr_parametric_drc_gain_set_params->downmix_id == 0x0) {
      pstr_parametric_drc_gain_set_params->channel_count_drom_downmix_id =
          pstr_uni_drc_config->str_channel_layout.base_ch_count;
    } else {
      for (idx = 0; idx < pstr_uni_drc_config->downmix_instructions_count; idx++) {
        if (pstr_parametric_drc_gain_set_params->downmix_id ==
            pstr_uni_drc_config->str_downmix_instructions[idx].downmix_id) {
          break;
        }
      }
      if (idx == pstr_uni_drc_config->downmix_instructions_count) {
        return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
      }
      pstr_parametric_drc_gain_set_params->channel_count_drom_downmix_id =
          pstr_uni_drc_config->str_downmix_instructions[idx].target_ch_count;
    }

    for (idx = 0; idx < pstr_parametric_drc_gain_set_params->channel_count_drom_downmix_id;
         idx++) {
      if (pstr_parametric_drc_gain_set_params->level_estim_channel_weight_format != 0) {
        impd_drc_enc_channel_weight(
            pstr_parametric_drc_gain_set_params->level_estim_channel_weight[idx], &code_size,
            &code);
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, (UWORD8)code_size);
      } else {
        if (pstr_parametric_drc_gain_set_params->level_estim_channel_weight[idx] == 0) {
          code = 0;
        } else {
          code = 1;
        }
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 1);
      }
    }
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_gain_set_params->drc_input_loudness_present, 1);
  if (pstr_parametric_drc_gain_set_params->drc_input_loudness_present) {
    code = ((WORD32)(0.5f +
                     4.0f * (pstr_parametric_drc_gain_set_params->drc_input_loudness + 57.75f) +
                     10000.0f)) -
           10000;
    code = MIN(0x0FF, code);
    code = MAX(0x0, code);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 8);
  }

  *ptr_bit_cnt += bit_cnt_local;

  return IA_NO_ERROR;
}

static VOID impd_drc_write_parametric_drc_type_feed_forward(
    ia_bit_buf_struct *it_bit_buf, WORD32 drc_frame_size_parametric_drc,
    ia_drc_parametric_drc_type_feed_forward_struct *pstr_parametric_drc_type_feed_forward,
    WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 code = 0;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_type_feed_forward->level_estim_k_weighting_type, 2);

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_type_feed_forward->level_estim_integration_time_present, 1);

  if (pstr_parametric_drc_type_feed_forward->level_estim_integration_time_present) {
    code =
        (WORD32)(((FLOAT32)pstr_parametric_drc_type_feed_forward->level_estim_integration_time /
                      drc_frame_size_parametric_drc +
                  0.5f) -
                 1);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 6);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_type_feed_forward->drc_curve_definition_type, 1);
  if (pstr_parametric_drc_type_feed_forward->drc_curve_definition_type != 0) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_type_feed_forward->node_count - 2, 3);

    for (idx = 0; idx < pstr_parametric_drc_type_feed_forward->node_count; idx++) {
      if (idx == 0) {
        code = -11 - pstr_parametric_drc_type_feed_forward->node_level[0];
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 6);
      } else {
        code = pstr_parametric_drc_type_feed_forward->node_level[idx] -
               pstr_parametric_drc_type_feed_forward->node_level[idx - 1] - 1;
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 5);
      }
      code = pstr_parametric_drc_type_feed_forward->node_gain[idx] + 39;
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 6);
    }
  } else {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_type_feed_forward->drc_characteristic, 7);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_type_feed_forward->drc_gain_smooth_parameters_present, 1);
  if (pstr_parametric_drc_type_feed_forward->drc_gain_smooth_parameters_present) {
    code = (WORD32)(pstr_parametric_drc_type_feed_forward->gain_smooth_attack_time_slow * 0.2);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 8);

    code = (WORD32)(pstr_parametric_drc_type_feed_forward->gain_smooth_release_time_slow * 0.025);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 8);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_type_feed_forward->gain_smooth_time_fast_present, 1);
    if (pstr_parametric_drc_type_feed_forward->gain_smooth_time_fast_present) {
      code = (WORD32)(pstr_parametric_drc_type_feed_forward->gain_smooth_attack_time_fast * 0.2);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 8);

      code =
          (WORD32)(pstr_parametric_drc_type_feed_forward->gain_smooth_release_time_fast * 0.05);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 8);

      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_parametric_drc_type_feed_forward->gain_smooth_threshold_present, 1);
      if (pstr_parametric_drc_type_feed_forward->gain_smooth_threshold_present) {
        if (pstr_parametric_drc_type_feed_forward->gain_smooth_attack_threshold <= 30) {
          code = pstr_parametric_drc_type_feed_forward->gain_smooth_attack_threshold;
        } else {
          code = 31;
        }
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 5);

        if (pstr_parametric_drc_type_feed_forward->gain_smooth_release_threshold <= 30) {
          code = pstr_parametric_drc_type_feed_forward->gain_smooth_release_threshold;
        } else {
          code = 31;
        }
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 5);
      }
    }

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_type_feed_forward->gain_smooth_hold_off_count_present, 1);
    if (pstr_parametric_drc_type_feed_forward->gain_smooth_hold_off_count_present) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_parametric_drc_type_feed_forward->gain_smooth_hold_off, 7);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_parametric_drc_type_lim(
    ia_bit_buf_struct *it_bit_buf,
    ia_drc_parametric_drc_type_lim_struct *pstr_parametric_drc_type_lim, WORD32 *ptr_bit_cnt) {
  WORD32 temp = 0;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_type_lim->parametric_lim_threshold_present, 1);
  if (pstr_parametric_drc_type_lim->parametric_lim_threshold_present) {
    temp = (WORD32)(0.5f - 8.0f * pstr_parametric_drc_type_lim->parametric_lim_threshold);
    temp = MAX(0, temp);
    temp = MIN(0xFF, temp);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, temp, 8);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_type_lim->parametric_lim_release_present, 1);
  if (pstr_parametric_drc_type_lim->parametric_lim_release_present) {
    temp = (WORD32)(pstr_parametric_drc_type_lim->parametric_lim_release * 0.1);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, temp, 8);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static IA_ERRORCODE impd_drc_write_parametric_drc_instructions(
    ia_bit_buf_struct *it_bit_buf, WORD32 drc_frame_size_parametric_drc,
    ia_drc_parametric_drc_instructions_struct *pstr_parametric_drc_instructions,
    WORD32 *ptr_bit_cnt) {
  WORD32 bit_size = 0, len_size_bits = 0, bit_size_len = 0;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_parametric_drc_instructions->parametric_drc_id, 4);

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_instructions->parametric_drc_look_ahead_present, 1);

  if (pstr_parametric_drc_instructions->parametric_drc_look_ahead_present) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_instructions->parametric_drc_look_ahead, 7);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_parametric_drc_instructions->parametric_drc_preset_id_present, 1);
  if (!(pstr_parametric_drc_instructions->parametric_drc_preset_id_present)) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_instructions->parametric_drc_type, 3);

    if (pstr_parametric_drc_instructions->parametric_drc_type == PARAM_DRC_TYPE_LIM) {
      impd_drc_write_parametric_drc_type_lim(
          it_bit_buf, &(pstr_parametric_drc_instructions->str_parametric_drc_type_lim),
          &bit_cnt_local);
    } else if (pstr_parametric_drc_instructions->parametric_drc_type == PARAM_DRC_TYPE_FF) {
      impd_drc_write_parametric_drc_type_feed_forward(
          it_bit_buf, drc_frame_size_parametric_drc,
          &(pstr_parametric_drc_instructions->str_parametric_drc_type_feed_forward),
          &bit_cnt_local);
    } else {
      bit_size = pstr_parametric_drc_instructions->len_bit_size - 1;
      len_size_bits = (WORD32)(log((FLOAT32)bit_size) / log(2.f)) + 1;
      bit_size_len = len_size_bits - 4;
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size_len, 4);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size, (UWORD8)bit_size);
      switch (pstr_parametric_drc_instructions->parametric_drc_type) {
        default:
          return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
      }
    }
  } else {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_parametric_drc_instructions->parametric_drc_preset_id, 7);
  }

  *ptr_bit_cnt += bit_cnt_local;

  return IA_NO_ERROR;
}

static IA_ERRORCODE impd_drc_write_drc_coeff_parametric_drc(
    ia_bit_buf_struct *it_bit_buf, ia_drc_uni_drc_config_struct *pstr_uni_drc_config,
    ia_drc_coeff_parametric_drc_struct *pstr_drc_coeff_parametric_drc, WORD32 *ptr_bit_cnt) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 bits = 0, mu = 0, nu = 0;
  WORD32 bit_cnt_local = 0;
  FLOAT32 exp = 0.f;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_drc_coeff_parametric_drc->drc_location, 4);

  exp = (FLOAT32)(log(pstr_drc_coeff_parametric_drc->parametric_drc_frame_size) / log(2));
  if (exp == (FLOAT32)((WORD32)exp)) {
    pstr_drc_coeff_parametric_drc->parametric_drc_frame_size_format = 0;
  } else {
    pstr_drc_coeff_parametric_drc->parametric_drc_frame_size_format = 1;
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_drc_coeff_parametric_drc->parametric_drc_frame_size_format, 1);
  if (!(pstr_drc_coeff_parametric_drc->parametric_drc_frame_size_format)) {
    bits = (WORD32)exp;
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bits, 4);
  } else {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, (pstr_drc_coeff_parametric_drc->parametric_drc_frame_size - 1), 15);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_drc_coeff_parametric_drc->parametric_drc_delay_max_present, 1);
  if (pstr_drc_coeff_parametric_drc->parametric_drc_delay_max_present == 1) {
    for (nu = 0; nu < 8; nu++) {
      mu = pstr_drc_coeff_parametric_drc->parametric_drc_delay_max / (16 << nu);
      if (mu * (16 << nu) < pstr_drc_coeff_parametric_drc->parametric_drc_delay_max) {
        mu++;
      }
      if (mu < 32) {
        break;
      }
    }
    if (nu == 8) {
      mu = 31;
      nu = 7;
    }
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, mu, 5);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, nu, 3);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_drc_coeff_parametric_drc->reset_parametric_drc, 1);

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_drc_coeff_parametric_drc->parametric_drc_gain_set_count, 6);
  for (idx = 0; idx < pstr_drc_coeff_parametric_drc->parametric_drc_gain_set_count; idx++) {
    err_code = impd_drc_write_parametric_drc_gain_set_params(
        it_bit_buf, pstr_uni_drc_config,
        &(pstr_drc_coeff_parametric_drc->parametric_drc_gain_set_params[idx]), &bit_cnt_local);

    if (err_code & IA_FATAL_ERROR) {
      return err_code;
    }
  }

  *ptr_bit_cnt += bit_cnt_local;

  return err_code;
}

static VOID impd_drc_write_loud_eq_instructions(
    ia_bit_buf_struct *it_bit_buf, ia_drc_loud_eq_instructions_struct *pstr_loud_eq_instructions,
    WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 bit_cnt_local = 0;
  WORD32 bs_loud_eq_offset;
  WORD32 bs_loud_eq_scaling;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->loud_eq_set_id, 4);

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->drc_location, 4);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->downmix_id_present, 1);
  if (pstr_loud_eq_instructions->downmix_id_present) {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->downmix_id, 7);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_loud_eq_instructions->additional_downmix_id_present, 1);
    if (!(pstr_loud_eq_instructions->additional_downmix_id_present)) {
      pstr_loud_eq_instructions->additional_downmix_id_count = 0;
    } else {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_loud_eq_instructions->additional_downmix_id_count, 7);
      for (idx = 0; idx < pstr_loud_eq_instructions->additional_downmix_id_count; idx++) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_loud_eq_instructions->additional_downmix_id[idx], 7);
      }
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->drc_set_id_present, 1);
  if (pstr_loud_eq_instructions->drc_set_id_present) {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->drc_set_id, 6);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_loud_eq_instructions->additional_drc_set_id_present, 1);
    if (!(pstr_loud_eq_instructions->additional_drc_set_id_present)) {
      pstr_loud_eq_instructions->additional_drc_set_id_count = 0;
    } else {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_loud_eq_instructions->additional_drc_set_id_count, 6);
      for (idx = 0; idx < pstr_loud_eq_instructions->additional_drc_set_id_count; idx++) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_loud_eq_instructions->additional_drc_set_id[idx], 6);
      }
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->eq_set_id_present, 1);
  if (pstr_loud_eq_instructions->eq_set_id_present) {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->eq_set_id, 6);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_loud_eq_instructions->additional_eq_set_id_present, 1);
    if (!(pstr_loud_eq_instructions->additional_eq_set_id_present)) {
      pstr_loud_eq_instructions->additional_eq_set_id_count = 0;
    } else {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_loud_eq_instructions->additional_eq_set_id_count, 6);
      for (idx = 0; idx < pstr_loud_eq_instructions->additional_eq_set_id_count; idx++) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_loud_eq_instructions->additional_eq_set_id[idx], 6);
      }
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->loudness_after_drc, 1);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->loudness_after_eq, 1);

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_loud_eq_instructions->loud_eq_gain_sequence_count, 6);
  for (idx = 0; idx < pstr_loud_eq_instructions->loud_eq_gain_sequence_count; idx++) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_loud_eq_instructions->gain_sequence_index[idx], 6);

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_loud_eq_instructions->drc_characteristic_format_is_cicp[idx], 1);
    if (pstr_loud_eq_instructions->drc_characteristic_format_is_cicp[idx] == 1) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_loud_eq_instructions->drc_characteristic[idx], 7);
    } else {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_loud_eq_instructions->drc_characteristic_left_index[idx], 4);

      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, pstr_loud_eq_instructions->drc_characteristic_right_index[idx], 4);
    }

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_loud_eq_instructions->frequency_range_index[idx], 6);
    bs_loud_eq_scaling = (WORD32)floor(
        0.5f - 2.0f * INV_LOG10_2 * log10(pstr_loud_eq_instructions->loud_eq_scaling[idx]));
    if (bs_loud_eq_scaling < 0) {
      bs_loud_eq_scaling = 0;
    } else if (bs_loud_eq_scaling > 7) {
      bs_loud_eq_scaling = 7;
    }

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_loud_eq_scaling, 3);
    bs_loud_eq_offset =
        (WORD32)floor(0.5f + pstr_loud_eq_instructions->loud_eq_offset[idx] / 1.5f + 16.0f);
    if (bs_loud_eq_offset < 0) {
      bs_loud_eq_offset = 0;
    } else if (bs_loud_eq_offset > 31) {
      bs_loud_eq_offset = 31;
    }

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_loud_eq_offset, 5);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_filter_element(ia_bit_buf_struct *it_bit_buf,
                                          ia_drc_filter_element_struct *pstr_filter_element,
                                          WORD32 *ptr_bit_cnt) {
  WORD32 bs_filter_element_gain;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_filter_element->filter_element_index, 6);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_filter_element->filter_element_gain_present, 1);
  if (pstr_filter_element->filter_element_gain_present) {
    bs_filter_element_gain =
        (WORD32)floor(0.5f + 8.0f * (pstr_filter_element->filter_element_gain + 96.0f));
    bs_filter_element_gain = MAX(0, bs_filter_element_gain);
    bs_filter_element_gain = MIN(1023, bs_filter_element_gain);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_filter_element_gain, 10);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_filter_block(ia_bit_buf_struct *it_bit_buf,
                                        ia_drc_filter_block_struct *pstr_filter_block,
                                        WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_filter_block->filter_element_count, 6);
  for (idx = 0; idx < pstr_filter_block->filter_element_count; idx++) {
    impd_drc_write_filter_element(it_bit_buf, &(pstr_filter_block->filter_element[idx]),
                                  &bit_cnt_local);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static IA_ERRORCODE impd_drc_encode_radius(FLOAT32 radius, WORD32 *code) {
  LOOPIDX idx;
  FLOAT32 rho;

  if (radius < 0.0f) {
    return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
  }
  rho = 1.0f - radius;
  if ((rho < 0.0f) || (rho > 1.0f)) {
    if (rho < 0.0f) {
      rho = 0.0f;
    }
    if (rho > 1.0f) {
      rho = 1.0f;
    }
  }
  if (rho > impd_drc_zero_pole_radius_table[127]) {
    rho = impd_drc_zero_pole_radius_table[127];
  }
  idx = 0;
  while (rho > impd_drc_zero_pole_radius_table[idx]) {
    idx++;
  }
  if (idx == 0) {
    return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
  }
  if (rho <
      0.5f * (impd_drc_zero_pole_radius_table[idx - 1] + impd_drc_zero_pole_radius_table[idx])) {
    idx--;
  }
  *code = idx;

  return IA_NO_ERROR;
}

static LOOPIDX impd_drc_encode_angle(FLOAT32 angle) {
  LOOPIDX idx;

  if ((angle < 0.0f) || (angle > 1.0f)) {
    if (angle < 0.0f) {
      angle = 0.0f;
    }
    if (angle > 1.0f) {
      angle = 1.0f;
    }
  }
  idx = 0;
  while (angle > impd_drc_zero_pole_angle_table[idx]) {
    idx++;
  }
  if (idx == 0) {
    return idx;
  }
  if (angle <
      0.5f * (impd_drc_zero_pole_angle_table[idx - 1] + impd_drc_zero_pole_angle_table[idx])) {
    idx--;
  }

  return (idx);
}

static IA_ERRORCODE impd_drc_write_unique_td_filter_element(
    ia_bit_buf_struct *it_bit_buf,
    ia_drc_unique_td_filter_element_struct *pstr_unique_td_filter_element, WORD32 *ptr_bit_cnt) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 sign, code;
  WORD32 bs_real_zero_radius_one_count;
  WORD32 bs_fir_coefficient;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_unique_td_filter_element->eq_filter_format, 1);
  if (pstr_unique_td_filter_element->eq_filter_format != 0) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_unique_td_filter_element->fir_filter_order, 7);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_unique_td_filter_element->fir_symmetry, 1);

    for (idx = 0; idx < pstr_unique_td_filter_element->fir_filter_order / 2 + 1; idx++) {
      if (pstr_unique_td_filter_element->fir_coefficient[idx] >= 0.0f) {
        sign = 0;
      } else {
        sign = 1;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, sign, 1);

      bs_fir_coefficient =
          (WORD32)floor(0.5f - log10(fabs(pstr_unique_td_filter_element->fir_coefficient[idx])) /
                                   (0.05f * 0.0625f));

      if (bs_fir_coefficient > 1023) {
        bs_fir_coefficient = 1023;
      }
      if (bs_fir_coefficient < 0) {
        bs_fir_coefficient = 0;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_fir_coefficient, 10);
    }
  } else {
    bs_real_zero_radius_one_count = pstr_unique_td_filter_element->real_zero_radius_one_count / 2;
    if ((pstr_unique_td_filter_element->real_zero_radius_one_count ==
         2 * bs_real_zero_radius_one_count) &&
        (bs_real_zero_radius_one_count < 8)) {
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_real_zero_radius_one_count, 3);
    } else {
      return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
    }

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_unique_td_filter_element->real_zero_count, 6);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_unique_td_filter_element->generic_zero_count, 6);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_unique_td_filter_element->real_pole_count, 4);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_unique_td_filter_element->complex_pole_count, 4);

    for (idx = 0; idx < pstr_unique_td_filter_element->real_zero_radius_one_count; idx++) {
      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf, (UWORD32)pstr_unique_td_filter_element->zero_sign[idx], 1);
    }

    for (idx = 0; idx < pstr_unique_td_filter_element->real_zero_count; idx++) {
      err_code = impd_drc_encode_radius(
          (FLOAT32)fabs(pstr_unique_td_filter_element->real_zero_radius[idx]), &code);

      if (err_code & IA_FATAL_ERROR) {
        return err_code;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 7);

      if (pstr_unique_td_filter_element->real_zero_radius[idx] >= 0.0f) {
        sign = 0;
      } else {
        sign = 1;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, sign, 1);
    }

    for (idx = 0; idx < pstr_unique_td_filter_element->generic_zero_count; idx++) {
      err_code =
          impd_drc_encode_radius(pstr_unique_td_filter_element->generic_zero_radius[idx], &code);
      if (err_code & IA_FATAL_ERROR) {
        return err_code;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 7);

      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf,
          impd_drc_encode_angle(pstr_unique_td_filter_element->generic_zero_angle[idx]), 7);
    }

    for (idx = 0; idx < pstr_unique_td_filter_element->real_pole_count; idx++) {
      err_code = impd_drc_encode_radius(
          (FLOAT32)fabs(pstr_unique_td_filter_element->real_pole_radius[idx]), &code);
      if (err_code & IA_FATAL_ERROR) {
        return err_code;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 7);

      if (pstr_unique_td_filter_element->real_pole_radius[idx] >= 0.0f) {
        sign = 0;
      } else {
        sign = 1;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, sign, 1);
    }

    for (idx = 0; idx < pstr_unique_td_filter_element->complex_pole_count; idx++) {
      err_code =
          impd_drc_encode_radius(pstr_unique_td_filter_element->complex_pole_radius[idx], &code);
      if (err_code & IA_FATAL_ERROR) {
        return err_code;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 7);

      bit_cnt_local += iusace_write_bits_buf(
          it_bit_buf,
          impd_drc_encode_angle(pstr_unique_td_filter_element->complex_pole_angle[idx]), 7);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;

  return err_code;
}

static VOID impd_drc_encode_eq_slope(FLOAT32 eq_slope, WORD32 *size, WORD32 *code) {
  LOOPIDX idx;

  if (fabs(eq_slope) >= 0.5f) {
    *size = 5;
    if (eq_slope > 32.0f) {
      *code = 15;
    } else if (eq_slope <= -32.0f) {
      *code = 0;
    } else {
      idx = 1;
      while (eq_slope > impd_drc_eq_slope_table[idx]) {
        idx++;
      }
      if (eq_slope < 0.5f * (impd_drc_eq_slope_table[idx - 1] + impd_drc_eq_slope_table[idx])) {
        idx--;
      }
      *code = idx;
    }
  } else {
    *size = 1;
    *code = 1;
  }
}

static VOID impd_drc_encode_eq_gain_initial(FLOAT32 eq_gain_initial, WORD32 *prefix_code,
                                            WORD32 *size, WORD32 *code) {
  if ((eq_gain_initial > -8.5f) && (eq_gain_initial < 7.75f)) {
    *size = 5;
    *prefix_code = 0;
    *code = (WORD32)floor(0.5f + 2.0f * (MAX(-8.0f, eq_gain_initial) + 8.0f));
  } else if (eq_gain_initial < 0.0f) {
    if (eq_gain_initial > -17.0f) {
      *size = 4;
      *prefix_code = 1;
      *code = (WORD32)floor(0.5f + MAX(-16.0f, eq_gain_initial) + 16.0f);
    } else if (eq_gain_initial > -34.0f) {
      *size = 4;
      *prefix_code = 2;
      *code = (WORD32)floor(0.5f + 0.5f * (MAX(-32.0f, eq_gain_initial) + 32.0f));
    } else {
      *size = 3;
      *prefix_code = 3;
      *code = (WORD32)floor(0.5f + 0.25f * (MAX(-64.0f, eq_gain_initial) + 64.0f));
    }
  } else {
    if (eq_gain_initial >= 15.5f) {
      *size = 4;
      *prefix_code = 2;
      *code = (WORD32)floor(0.5f + 0.5f * MIN(30.0f, eq_gain_initial));
    } else {
      *size = 4;
      *prefix_code = 1;
      *code = (WORD32)floor(0.5f + eq_gain_initial);
    }
  }
}

static VOID impd_drc_encode_eq_gain_delta(FLOAT32 eq_gain_delta, WORD32 *code) {
  LOOPIDX idx;

  if (eq_gain_delta >= 32.0f) {
    *code = 31;
  } else if (eq_gain_delta <= -22.0f) {
    *code = 0;
  } else {
    idx = 1;
    while (eq_gain_delta > impd_drc_eq_gain_delta_table[idx]) {
      idx++;
    }
    if (eq_gain_delta <
        0.5f * (impd_drc_eq_gain_delta_table[idx - 1] + impd_drc_eq_gain_delta_table[idx])) {
      idx--;
    }
    *code = idx;
  }
}

static VOID impd_drc_write_eq_subband_gain_spline(
    ia_bit_buf_struct *it_bit_buf,
    ia_drc_eq_subband_gain_spline_struct *pstr_eq_subband_gain_spline, WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 size, code, prefix_code;
  WORD32 bit_cnt_local = 0;
  WORD32 bs_eq_node_count = pstr_eq_subband_gain_spline->n_eq_nodes - 2;

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_eq_node_count, 5);

  for (idx = 0; idx < pstr_eq_subband_gain_spline->n_eq_nodes; idx++) {
    impd_drc_encode_eq_slope(pstr_eq_subband_gain_spline->eq_slope[idx], &size, &code);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, (UWORD8)size);
  }

  for (idx = 1; idx < pstr_eq_subband_gain_spline->n_eq_nodes; idx++) {
    code = MIN(15, pstr_eq_subband_gain_spline->eq_freq_delta[idx] - 1);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 4);
  }

  impd_drc_encode_eq_gain_initial(pstr_eq_subband_gain_spline->eq_gain_initial, &prefix_code,
                                  &size, &code);

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, prefix_code, 2);
  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, (UWORD8)size);

  for (idx = 1; idx < pstr_eq_subband_gain_spline->n_eq_nodes; idx++) {
    impd_drc_encode_eq_gain_delta(pstr_eq_subband_gain_spline->eq_gain_delta[idx], &code);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, code, 5);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_eq_subband_gain_vector(
    ia_bit_buf_struct *it_bit_buf, WORD32 eq_subband_gain_count,
    ia_drc_eq_subband_gain_vector_struct *pstr_eq_subband_gain_vector, WORD32 *ptr_bit_cnt) {
  LOOPIDX idx = 0;
  WORD32 sign;
  WORD32 bs_eq_subband_gain;
  WORD32 bit_cnt_local = 0;

  for (idx = 0; idx < eq_subband_gain_count; idx++) {
    bs_eq_subband_gain =
        (WORD32)floor(0.5f + fabs(pstr_eq_subband_gain_vector->eq_subband_gain[idx] * 8.0f));

    if (pstr_eq_subband_gain_vector->eq_subband_gain[idx] >= 0.0f) {
      sign = 0;
    } else {
      sign = 1;
    }

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, sign, 1);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_eq_subband_gain, 8);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static IA_ERRORCODE impd_drc_write_eq_coefficients(
    ia_bit_buf_struct *it_bit_buf, ia_drc_eq_coefficients_struct *pstr_eq_coefficients,
    WORD32 *ptr_bit_cnt) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 bs_eq_gain_count;
  WORD32 mu = 0, nu = 0;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_coefficients->eq_delay_max_present, 1);
  if (pstr_eq_coefficients->eq_delay_max_present == 1) {
    for (nu = 0; nu < 8; nu++) {
      mu = pstr_eq_coefficients->eq_delay_max / (16 << nu);
      if (mu * (16 << nu) < pstr_eq_coefficients->eq_delay_max) {
        mu++;
      }
      if (mu < 32) {
        break;
      }
    }
    if (nu == 8) {
      mu = 31;
      nu = 7;
    }
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, mu, 5);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, nu, 3);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_coefficients->unique_filter_block_count, 6);
  for (idx = 0; idx < pstr_eq_coefficients->unique_filter_block_count; idx++) {
    impd_drc_write_filter_block(it_bit_buf, &(pstr_eq_coefficients->str_filter_block[idx]),
                                &bit_cnt_local);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_coefficients->unique_td_filter_element_count, 6);
  for (idx = 0; idx < pstr_eq_coefficients->unique_td_filter_element_count; idx++) {
    err_code = impd_drc_write_unique_td_filter_element(
        it_bit_buf, &(pstr_eq_coefficients->str_unique_td_filter_element[idx]), &bit_cnt_local);
    if (err_code & IA_FATAL_ERROR) {
      return err_code;
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_coefficients->unique_eq_subband_gains_count, 6);
  if (pstr_eq_coefficients->unique_eq_subband_gains_count > 0) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_eq_coefficients->eq_subband_gain_representation, 1);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_eq_coefficients->eq_subband_gain_format, 4);

    switch (pstr_eq_coefficients->eq_subband_gain_format) {
      case GAINFORMAT_QMFHYBRID135:
        pstr_eq_coefficients->eq_subband_gain_count = 135;
        break;
      case GAINFORMAT_QMF128:
        pstr_eq_coefficients->eq_subband_gain_count = 128;
        break;
      case GAINFORMAT_QMFHYBRID71:
        pstr_eq_coefficients->eq_subband_gain_count = 71;
        break;
      case GAINFORMAT_QMF64:
        pstr_eq_coefficients->eq_subband_gain_count = 64;
        break;
      case GAINFORMAT_QMFHYBRID39:
        pstr_eq_coefficients->eq_subband_gain_count = 39;
        break;
      case GAINFORMAT_QMF32:
        pstr_eq_coefficients->eq_subband_gain_count = 32;
        break;
      case GAINFORMAT_UNIFORM:
      default:
        bs_eq_gain_count = pstr_eq_coefficients->eq_subband_gain_count - 1;
        bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_eq_gain_count, 8);
        break;
    }

    for (idx = 0; idx < pstr_eq_coefficients->unique_eq_subband_gains_count; idx++) {
      if (pstr_eq_coefficients->eq_subband_gain_representation != 1) {
        impd_drc_write_eq_subband_gain_vector(
            it_bit_buf, pstr_eq_coefficients->eq_subband_gain_count,
            &(pstr_eq_coefficients->str_eq_subband_gain_vector[idx]), &bit_cnt_local);
      } else {
        impd_drc_write_eq_subband_gain_spline(
            it_bit_buf, &(pstr_eq_coefficients->str_eq_subband_gain_spline[idx]), &bit_cnt_local);
      }
    }
  }

  *ptr_bit_cnt += bit_cnt_local;

  return err_code;
}

static VOID impd_drc_write_filter_block_refs(
    ia_bit_buf_struct *it_bit_buf, ia_drc_filter_block_refs_struct *pstr_filter_block_refs,
    WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_filter_block_refs->filter_block_count, 4);
  for (idx = 0; idx < pstr_filter_block_refs->filter_block_count; idx++) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_filter_block_refs->filter_block_index[idx], 7);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_td_filter_cascade(
    ia_bit_buf_struct *it_bit_buf, const WORD32 eq_channel_group_count,
    ia_drc_td_filter_cascade_struct *pstr_td_filter_cascade, WORD32 *ptr_bit_cnt) {
  LOOPIDX i, j;
  WORD32 bs_eq_cascade_gain;
  WORD32 bit_cnt_local = 0;

  for (i = 0; i < eq_channel_group_count; i++) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_td_filter_cascade->eq_cascade_gain_present[i], 1);
    if (pstr_td_filter_cascade->eq_cascade_gain_present[i] == 1) {
      bs_eq_cascade_gain =
          (WORD32)floor(0.5f + 8.0f * (pstr_td_filter_cascade->eq_cascade_gain[i] + 96.0f));
      bs_eq_cascade_gain = MAX(0, bs_eq_cascade_gain);
      bs_eq_cascade_gain = MIN(1023, bs_eq_cascade_gain);
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_eq_cascade_gain, 10);
    }
    impd_drc_write_filter_block_refs(
        it_bit_buf, &(pstr_td_filter_cascade->str_filter_block_refs[i]), &bit_cnt_local);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_td_filter_cascade->eq_phase_alignment_present, 1);
  if (pstr_td_filter_cascade->eq_phase_alignment_present == 1) {
    for (i = 0; i < eq_channel_group_count; i++) {
      for (j = i + 1; j < eq_channel_group_count; j++) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_td_filter_cascade->eq_phase_alignment[i][j], 1);
      }
    }
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static IA_ERRORCODE impd_drc_write_eq_instructions(
    ia_bit_buf_struct *it_bit_buf, ia_drc_uni_drc_config_ext_struct *pstr_uni_drc_config_ext,
    ia_drc_gain_enc_struct *pstr_gain_enc, ia_drc_eq_instructions_struct *pstr_eq_instructions,
    WORD32 *ptr_bit_cnt, VOID *ptr_scratch, WORD32 *scratch_used) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 bs_eq_transition_duration;
  WORD32 bit_cnt_local = 0;
  FLOAT32 temp;

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->eq_set_id, 6);

  err_code = impd_drc_get_eq_complexity_level(pstr_uni_drc_config_ext, pstr_gain_enc,
                                              pstr_eq_instructions, ptr_scratch, scratch_used);
  if (err_code & IA_FATAL_ERROR) {
    return err_code;
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->eq_set_complexity_level, 4);

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->downmix_id_present, 1);
  if (pstr_eq_instructions->downmix_id_present == 1) {
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->downmix_id, 7);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->eq_apply_to_downmix, 1);

    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->additional_downmix_id_present, 1);
    if (pstr_eq_instructions->additional_downmix_id_present == 1) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->additional_downmix_id_count, 7);
      for (idx = 0; idx < pstr_eq_instructions->additional_downmix_id_count; idx++) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_eq_instructions->additional_downmix_id[idx], 7);
      }
    }
  }

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->drc_set_id, 6);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->additional_drc_set_id_present, 1);
  if (pstr_eq_instructions->additional_drc_set_id_present == 1) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->additional_drc_set_id_count, 6);
    for (idx = 0; idx < pstr_eq_instructions->additional_drc_set_id_count; idx++) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->additional_drc_set_id[idx], 6);
    }
  }

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->eq_set_purpose, 16);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->depends_on_eq_set_present, 1);
  if (pstr_eq_instructions->depends_on_eq_set_present != 1) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->no_independent_eq_use, 1);
  } else {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->depends_on_eq_set, 6);
  }

  for (idx = 0; idx < pstr_eq_instructions->eq_channel_count; idx++) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_eq_instructions->eq_channel_group_for_channel[idx], 7);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->td_filter_cascade_present, 1);
  if (pstr_eq_instructions->td_filter_cascade_present == 1) {
    impd_drc_write_td_filter_cascade(it_bit_buf, pstr_eq_instructions->eq_channel_group_count,
                                     &(pstr_eq_instructions->str_td_filter_cascade),
                                     &bit_cnt_local);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->subband_gains_present, 1);
  if (pstr_eq_instructions->subband_gains_present == 1) {
    for (idx = 0; idx < pstr_eq_instructions->eq_channel_group_count; idx++) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->subband_gains_index[idx], 6);
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_eq_instructions->eq_transition_duration_present, 1);
  if (pstr_eq_instructions->eq_transition_duration_present == 1) {
    temp = MAX(0.004f, pstr_eq_instructions->eq_transition_duration);
    temp = MIN(0.861f, temp);
    bs_eq_transition_duration =
        (WORD32)floor(0.5f + 4.0f * (log10(1000.0f * temp) / log10(2.0f) - 2.0f));
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bs_eq_transition_duration, 5);
  }

  *ptr_bit_cnt += bit_cnt_local;

  return err_code;
}

static IA_ERRORCODE impd_drc_write_uni_drc_config_extn(
    ia_drc_enc_state *pstr_drc_state, ia_drc_gain_enc_struct *pstr_gain_enc,
    ia_drc_uni_drc_config_struct *pstr_uni_drc_config,
    ia_drc_uni_drc_config_ext_struct *pstr_uni_drc_config_ext, WORD32 *ptr_bit_cnt,
    FLAG write_bs) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 version;
  WORD32 counter = 0;
  WORD32 ext_size_bits = 0, bit_size_len = 0, bit_size = 0;
  WORD32 bit_cnt_local = 0, bit_cnt_local_ext = 0;
  WORD32 *scratch_used = &pstr_drc_state->drc_scratch_used;
  VOID *ptr_scratch = &pstr_drc_state->drc_scratch_mem;
  ia_bit_buf_struct *it_bit_buf = NULL;
  ia_bit_buf_struct *ptr_bit_buf_ext = NULL;

  if (write_bs) {
    it_bit_buf = &pstr_drc_state->str_bit_buf_cfg;
    ptr_bit_buf_ext = &pstr_drc_state->str_bit_buf_cfg_ext;

    iusace_reset_bit_buffer(ptr_bit_buf_ext);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_uni_drc_config_ext->uni_drc_config_ext_type[counter], 4);
  while (counter < 2 &&
         pstr_uni_drc_config_ext->uni_drc_config_ext_type[counter] != UNIDRC_CONF_EXT_TERM) {
    switch (pstr_uni_drc_config_ext->uni_drc_config_ext_type[counter]) {
      case UNIDRC_CONF_EXT_PARAM_DRC: {
#ifdef LOUDNESS_LEVELING_SUPPORT
        bit_cnt_local_ext = 0;
#endif  // LOUDNESS_LEVELING_SUPPORT
        err_code = impd_drc_write_drc_coeff_parametric_drc(
            ptr_bit_buf_ext, pstr_uni_drc_config,
            &(pstr_uni_drc_config_ext->str_drc_coeff_parametric_drc), &bit_cnt_local_ext);

        if (err_code & IA_FATAL_ERROR) {
          return err_code;
        }

        bit_cnt_local_ext += iusace_write_bits_buf(
            ptr_bit_buf_ext, pstr_uni_drc_config_ext->parametric_drc_instructions_count, 4);
        for (idx = 0; idx < pstr_uni_drc_config_ext->parametric_drc_instructions_count; idx++) {
          err_code = impd_drc_write_parametric_drc_instructions(
              ptr_bit_buf_ext,
              pstr_uni_drc_config_ext->str_drc_coeff_parametric_drc.parametric_drc_frame_size,
              &(pstr_uni_drc_config_ext->str_parametric_drc_instructions[idx]),
              &bit_cnt_local_ext);
          if (err_code & IA_FATAL_ERROR) {
            return err_code;
          }
        }
      } break;
      case UNIDRC_CONF_EXT_V1: {
        version = 1;
#ifdef LOUDNESS_LEVELING_SUPPORT
        bit_cnt_local_ext = 0;
#endif  // LOUDNESS_LEVELING_SUPPORT
        bit_cnt_local_ext += iusace_write_bits_buf(
            ptr_bit_buf_ext, pstr_uni_drc_config_ext->downmix_instructions_v1_present, 1);
        if (pstr_uni_drc_config_ext->downmix_instructions_v1_present == 1) {
          bit_cnt_local_ext += iusace_write_bits_buf(
              ptr_bit_buf_ext, pstr_uni_drc_config_ext->downmix_instructions_v1_count, 7);
          for (idx = 0; idx < pstr_uni_drc_config_ext->downmix_instructions_v1_count; idx++) {
            impd_drc_write_downmix_instructions(
                ptr_bit_buf_ext, version, pstr_gain_enc,
                &(pstr_uni_drc_config_ext->str_downmix_instructions_v1[idx]), &bit_cnt_local_ext);
          }
        }

        bit_cnt_local_ext += iusace_write_bits_buf(
            ptr_bit_buf_ext,
            pstr_uni_drc_config_ext->drc_coeffs_and_instructions_uni_drc_v1_present, 1);
        if (pstr_uni_drc_config_ext->drc_coeffs_and_instructions_uni_drc_v1_present == 1) {
          bit_cnt_local_ext += iusace_write_bits_buf(
              ptr_bit_buf_ext, pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count, 3);
          for (idx = 0; idx < pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count; idx++) {
            impd_drc_write_drc_coeff_uni_drc(
                ptr_bit_buf_ext, version,
                &(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[idx]),
                &bit_cnt_local_ext);
          }
#ifdef LOUDNESS_LEVELING_SUPPORT
          UWORD32 num_ducking_only_drc_sets = get_num_ducking_only_drc_sets(
              pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1,
              pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count);

          bit_cnt_local_ext +=
              iusace_write_bits_buf(ptr_bit_buf_ext,
                                    pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count -
                                        num_ducking_only_drc_sets,
                                    6);
#else
          bit_cnt_local_ext += iusace_write_bits_buf(
              ptr_bit_buf_ext, pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count, 6);
#endif
          for (idx = 0; idx < pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count; idx++) {
#ifdef LOUDNESS_LEVELING_SUPPORT
            if (idx > 0 && pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[idx - 1]
                               .ducking_only_set_present) {
              continue;
            }
#endif
            err_code = impd_drc_write_drc_instruct_uni_drc(
                ptr_bit_buf_ext, version, pstr_uni_drc_config, pstr_gain_enc,
                &(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[idx]), ptr_scratch,
                &bit_cnt_local_ext);
            if (err_code & IA_FATAL_ERROR) {
              return (err_code);
            }
          }
        }

        bit_cnt_local_ext += iusace_write_bits_buf(
            ptr_bit_buf_ext, pstr_uni_drc_config_ext->loud_eq_instructions_present, 1);
        if (pstr_uni_drc_config_ext->loud_eq_instructions_present == 1) {
          bit_cnt_local_ext += iusace_write_bits_buf(
              ptr_bit_buf_ext, pstr_uni_drc_config_ext->loud_eq_instructions_count, 4);
          for (idx = 0; idx < pstr_uni_drc_config_ext->loud_eq_instructions_count; idx++) {
            impd_drc_write_loud_eq_instructions(
                ptr_bit_buf_ext, &(pstr_uni_drc_config_ext->str_loud_eq_instructions[idx]),
                &bit_cnt_local_ext);
          }
        }

        bit_cnt_local_ext +=
            iusace_write_bits_buf(ptr_bit_buf_ext, pstr_uni_drc_config_ext->eq_present, 1);
        if (pstr_uni_drc_config_ext->eq_present == 1) {
          err_code = impd_drc_write_eq_coefficients(
              ptr_bit_buf_ext, &(pstr_uni_drc_config_ext->str_eq_coefficients),
              &bit_cnt_local_ext);
          if (err_code & IA_FATAL_ERROR) {
            return err_code;
          }

          bit_cnt_local_ext += iusace_write_bits_buf(
              ptr_bit_buf_ext, pstr_uni_drc_config_ext->eq_instructions_count, 4);
          for (idx = 0; idx < pstr_uni_drc_config_ext->eq_instructions_count; idx++) {
            err_code = impd_drc_write_eq_instructions(
                ptr_bit_buf_ext, pstr_uni_drc_config_ext, pstr_gain_enc,
                &(pstr_uni_drc_config_ext->str_eq_instructions[idx]), &bit_cnt_local_ext,
                ptr_scratch, scratch_used);
            if (err_code & IA_FATAL_ERROR) {
              return (err_code);
            }
          }
        }
      } break;

#ifdef LOUDNESS_LEVELING_SUPPORT
      case UNIDRCCONFEXT_LEVELING: {
        bit_cnt_local_ext = 0;
        err_code = write_loudness_leveling_extension(
            ptr_bit_buf_ext, pstr_uni_drc_config, pstr_gain_enc, ptr_scratch, &bit_cnt_local_ext);
        if (err_code & IA_FATAL_ERROR) {
          return (err_code);
        }
      } break;
#endif
      default:
        break;
    }

    pstr_uni_drc_config_ext->ext_bit_size[counter] = bit_cnt_local_ext;
    bit_size = pstr_uni_drc_config_ext->ext_bit_size[counter] - 1;
    ext_size_bits = (WORD32)(log((FLOAT32)bit_size) / log(2.f)) + 1;
#ifdef LOUDNESS_LEVELING_SUPPORT
    ext_size_bits = (ext_size_bits < 4) ? 4 : ext_size_bits;
#endif  // LOUDNESS_LEVELING_SUPPORT
    bit_size_len = ext_size_bits - 4;

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size_len, 4);

    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size, (UWORD8)ext_size_bits);

    switch (pstr_uni_drc_config_ext->uni_drc_config_ext_type[counter]) {
      case UNIDRC_CONF_EXT_PARAM_DRC: {
        err_code = impd_drc_write_drc_coeff_parametric_drc(
            it_bit_buf, pstr_uni_drc_config,
            &(pstr_uni_drc_config_ext->str_drc_coeff_parametric_drc), &bit_cnt_local);

        if (err_code & IA_FATAL_ERROR) {
          return (err_code);
        }

        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_uni_drc_config_ext->parametric_drc_instructions_count, 4);
        for (idx = 0; idx < pstr_uni_drc_config_ext->parametric_drc_instructions_count; idx++) {
          err_code = impd_drc_write_parametric_drc_instructions(
              it_bit_buf,
              pstr_uni_drc_config_ext->str_drc_coeff_parametric_drc.parametric_drc_frame_size,
              &(pstr_uni_drc_config_ext->str_parametric_drc_instructions[idx]), &bit_cnt_local);
          if (err_code & IA_FATAL_ERROR) {
            return (err_code);
          }
        }
      } break;
      case UNIDRC_CONF_EXT_V1: {
        version = 1;
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_uni_drc_config_ext->downmix_instructions_v1_present, 1);
        if (pstr_uni_drc_config_ext->downmix_instructions_v1_present == 1) {
          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_uni_drc_config_ext->downmix_instructions_v1_count, 7);
          for (idx = 0; idx < pstr_uni_drc_config_ext->downmix_instructions_v1_count; idx++) {
            impd_drc_write_downmix_instructions(
                it_bit_buf, version, pstr_gain_enc,
                &(pstr_uni_drc_config_ext->str_downmix_instructions_v1[idx]), &bit_cnt_local);
          }
        }

        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_uni_drc_config_ext->drc_coeffs_and_instructions_uni_drc_v1_present,
            1);
        if (pstr_uni_drc_config_ext->drc_coeffs_and_instructions_uni_drc_v1_present == 1) {
          version = 1;
          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count, 3);
          for (idx = 0; idx < pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count; idx++) {
            impd_drc_write_drc_coeff_uni_drc(
                it_bit_buf, version,
                &(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[idx]), &bit_cnt_local);
          }
#ifdef LOUDNESS_LEVELING_SUPPORT
          UWORD32 num_ducking_only_drc_sets = get_num_ducking_only_drc_sets(
              pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1,
              pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count);
          bit_cnt_local +=
              iusace_write_bits_buf(it_bit_buf,
                                    pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count -
                                        num_ducking_only_drc_sets,
                                    6);
#else
          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count, 6);
#endif
          for (idx = 0; idx < pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count; idx++) {
#ifdef LOUDNESS_LEVELING_SUPPORT
            if (idx > 0 && pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[idx - 1]
                               .ducking_only_set_present) {
              continue;
            }
#endif
            err_code = impd_drc_write_drc_instruct_uni_drc(
                it_bit_buf, version, pstr_uni_drc_config, pstr_gain_enc,
                &(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[idx]), ptr_scratch,
                &bit_cnt_local);
            if (err_code & IA_FATAL_ERROR) {
              return (err_code);
            }
          }
        }

        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_uni_drc_config_ext->loud_eq_instructions_present, 1);
        if (pstr_uni_drc_config_ext->loud_eq_instructions_present == 1) {
          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_uni_drc_config_ext->loud_eq_instructions_count, 4);
          for (idx = 0; idx < pstr_uni_drc_config_ext->loud_eq_instructions_count; idx++) {
            impd_drc_write_loud_eq_instructions(
                it_bit_buf, &(pstr_uni_drc_config_ext->str_loud_eq_instructions[idx]),
                &bit_cnt_local);
          }
        }

        bit_cnt_local +=
            iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config_ext->eq_present, 1);
        if (pstr_uni_drc_config_ext->eq_present == 1) {
          err_code = impd_drc_write_eq_coefficients(
              it_bit_buf, &(pstr_uni_drc_config_ext->str_eq_coefficients), &bit_cnt_local);
          if (err_code & IA_FATAL_ERROR) {
            return err_code;
          }

          bit_cnt_local += iusace_write_bits_buf(
              it_bit_buf, pstr_uni_drc_config_ext->eq_instructions_count, 4);
          for (idx = 0; idx < pstr_uni_drc_config_ext->eq_instructions_count; idx++) {
            err_code = impd_drc_write_eq_instructions(
                it_bit_buf, pstr_uni_drc_config_ext, pstr_gain_enc,
                &(pstr_uni_drc_config_ext->str_eq_instructions[idx]), &bit_cnt_local, ptr_scratch,
                scratch_used);
            if (err_code & IA_FATAL_ERROR) {
              return err_code;
            }
          }
        }
      } break;
#ifdef LOUDNESS_LEVELING_SUPPORT
      case UNIDRCCONFEXT_LEVELING: {
        err_code = write_loudness_leveling_extension(it_bit_buf, pstr_uni_drc_config,
                                                     pstr_gain_enc, ptr_scratch, &bit_cnt_local);
        if (err_code & IA_FATAL_ERROR) {
          return (err_code);
        }
      } break;
#endif
      default:
        for (idx = 0; idx < pstr_uni_drc_config_ext->ext_bit_size[counter]; idx++) {
          bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 0, 1);
        }
        break;
    }

    counter++;

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_uni_drc_config_ext->uni_drc_config_ext_type[counter], 4);
  }

  *ptr_bit_cnt += bit_cnt_local;

  return err_code;
}

IA_ERRORCODE impd_drc_write_loudness_info_set_extension(
    ia_drc_enc_state *pstr_drc_state, ia_bit_buf_struct *it_bit_buf,
    ia_drc_loudness_info_set_extension_struct *pstr_loudness_info_set_extension,
    WORD32 *ptr_bit_cnt, FLAG write_bs) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 counter = 0, version = 1;
  WORD32 ext_size_bits = 0, bit_size_len = 0, bit_size = 0;
  WORD32 bit_cnt_local = 0;
  WORD32 bit_cnt_local_tmp = 0;
  ia_drc_loudness_info_set_ext_eq_struct *pstr_loudness_info_set_ext_eq =
      &pstr_loudness_info_set_extension->str_loudness_info_set_ext_eq;
  ia_bit_buf_struct *ptr_bit_buf_tmp = NULL;

  if (write_bs) {
    ptr_bit_buf_tmp = &pstr_drc_state->str_bit_buf_cfg_tmp;

    iusace_reset_bit_buffer(ptr_bit_buf_tmp);
  }

  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_loudness_info_set_extension->loudness_info_set_ext_type[counter], 4);
  while ((counter < 2) &&
         (pstr_loudness_info_set_extension->loudness_info_set_ext_type[counter] !=
          UNIDRC_LOUD_EXT_TERM)) {
    switch (pstr_loudness_info_set_extension->loudness_info_set_ext_type[counter]) {
      case UNIDRC_LOUD_EXT_EQ: {
        bit_cnt_local_tmp += iusace_write_bits_buf(
            ptr_bit_buf_tmp, pstr_loudness_info_set_ext_eq->loudness_info_v1_album_count, 6);

        bit_cnt_local_tmp += iusace_write_bits_buf(
            ptr_bit_buf_tmp, pstr_loudness_info_set_ext_eq->loudness_info_v1_count, 6);
        for (idx = 0; idx < pstr_loudness_info_set_ext_eq->loudness_info_v1_album_count; idx++) {
          err_code = impd_drc_write_loudness_info(
              ptr_bit_buf_tmp, version,
              &(pstr_loudness_info_set_ext_eq->str_loudness_info_v1_album[idx]),
              &bit_cnt_local_tmp);
          if (err_code) {
            return err_code;
          }
        }
        for (idx = 0; idx < pstr_loudness_info_set_ext_eq->loudness_info_v1_count; idx++) {
          err_code = impd_drc_write_loudness_info(
              ptr_bit_buf_tmp, version,
              &(pstr_loudness_info_set_ext_eq->str_loudness_info_v1[idx]), &bit_cnt_local_tmp);
          if (err_code) {
            return (err_code);
          }
        }
      } break;
      default:
        break;
    }
    pstr_loudness_info_set_extension->ext_bit_size[counter] = bit_cnt_local_tmp;
    bit_size = pstr_loudness_info_set_extension->ext_bit_size[counter] - 1;
    ext_size_bits = (WORD32)(log((FLOAT32)bit_size) / log(2.f)) + 1;
    bit_size_len = ext_size_bits - 4;
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size_len, 4);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size, (UWORD8)ext_size_bits);

    switch (pstr_loudness_info_set_extension->loudness_info_set_ext_type[counter]) {
      case UNIDRC_LOUD_EXT_EQ: {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_loudness_info_set_ext_eq->loudness_info_v1_album_count, 6);

        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_loudness_info_set_ext_eq->loudness_info_v1_count, 6);
        for (idx = 0; idx < pstr_loudness_info_set_ext_eq->loudness_info_v1_album_count; idx++) {
          err_code = impd_drc_write_loudness_info(
              it_bit_buf, version,
              &(pstr_loudness_info_set_ext_eq->str_loudness_info_v1_album[idx]), &bit_cnt_local);
          if (err_code) {
            return err_code;
          }
        }
        for (idx = 0; idx < pstr_loudness_info_set_ext_eq->loudness_info_v1_count; idx++) {
          err_code = impd_drc_write_loudness_info(
              it_bit_buf, version, &(pstr_loudness_info_set_ext_eq->str_loudness_info_v1[idx]),
              &bit_cnt_local);
          if (err_code) {
            return (err_code);
          }
        }
      } break;
      default:
        for (idx = 0; idx < pstr_loudness_info_set_extension->ext_bit_size[counter]; idx++) {
          bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 0, 1);
        }
        break;
    }
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_loudness_info_set_extension->loudness_info_set_ext_type[counter], 4);

    counter++;
  }

  *ptr_bit_cnt += bit_cnt_local;

  return IA_NO_ERROR;
}

IA_ERRORCODE impd_drc_write_loudness_info_set(ia_drc_enc_state *pstr_drc_state,
                                              ia_bit_buf_struct *it_bit_buf, WORD32 *ptr_bit_cnt,
                                              FLAG write_bs) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 version = 0;
  WORD32 bit_cnt_local = 0;
  ia_drc_gain_enc_struct *pstr_gain_enc = &pstr_drc_state->str_gain_enc;
  ia_drc_loudness_info_set_struct *pstr_loudness_info_set =
      &(pstr_gain_enc->str_loudness_info_set);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loudness_info_set->loudness_info_album_count, 6);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loudness_info_set->loudness_info_count, 6);

  for (idx = 0; idx < pstr_loudness_info_set->loudness_info_album_count; idx++) {
    err_code = impd_drc_write_loudness_info(it_bit_buf, version,
                                            &pstr_loudness_info_set->str_loudness_info_album[idx],
                                            &bit_cnt_local);
    if (err_code) {
      return err_code;
    }
  }

  for (idx = 0; idx < pstr_loudness_info_set->loudness_info_count; idx++) {
    err_code = impd_drc_write_loudness_info(
        it_bit_buf, version, &pstr_loudness_info_set->str_loudness_info[idx], &bit_cnt_local);
    if (err_code) {
      return err_code;
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_loudness_info_set->loudness_info_set_ext_present, 1);
  if (pstr_loudness_info_set->loudness_info_set_ext_present) {
    err_code = impd_drc_write_loudness_info_set_extension(
        pstr_drc_state, it_bit_buf, &pstr_loudness_info_set->str_loudness_info_set_extension,
        &bit_cnt_local, write_bs);
    if (err_code) {
      return err_code;
    }
  }

  *ptr_bit_cnt += bit_cnt_local;

  return err_code;
}

IA_ERRORCODE impd_drc_write_uni_drc_config(ia_drc_enc_state *pstr_drc_state, WORD32 *ptr_bit_cnt,
                                           FLAG write_bs) {
  IA_ERRORCODE err_code = IA_NO_ERROR;
  LOOPIDX idx;
  WORD32 version = 0;
  WORD32 bit_cnt_local = 0;
  VOID *ptr_scratch = pstr_drc_state->drc_scratch_mem;
  ia_bit_buf_struct *it_bit_buf = NULL;
  ia_drc_gain_enc_struct *pstr_gain_enc = &pstr_drc_state->str_gain_enc;
  ia_drc_uni_drc_config_struct *pstr_uni_drc_config = &(pstr_gain_enc->str_uni_drc_config);

  if (write_bs) {
    it_bit_buf = &pstr_drc_state->str_bit_buf_cfg;
  }

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->sample_rate_present, 1);

  if (1 == pstr_uni_drc_config->sample_rate_present) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, (pstr_uni_drc_config->sample_rate - 1000), 18);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->downmix_instructions_count, 7);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->drc_description_basic_present, 1);

  if (1 == pstr_uni_drc_config->drc_description_basic_present) {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->drc_coefficients_basic_count, 3);
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->drc_instructions_basic_count, 4);
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->drc_coefficients_uni_drc_count, 3);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->drc_instructions_uni_drc_count, 6);

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->str_channel_layout.base_ch_count, 7);
  bit_cnt_local += iusace_write_bits_buf(
      it_bit_buf, pstr_uni_drc_config->str_channel_layout.layout_signaling_present, 1);
  if (1 == pstr_uni_drc_config->str_channel_layout.layout_signaling_present) {
    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_uni_drc_config->str_channel_layout.defined_layout, 8);
    if (0 == pstr_uni_drc_config->str_channel_layout.defined_layout) {
      for (idx = 0; idx < pstr_uni_drc_config->str_channel_layout.base_ch_count; idx++) {
        bit_cnt_local += iusace_write_bits_buf(
            it_bit_buf, pstr_uni_drc_config->str_channel_layout.speaker_position[idx], 7);
      }
    }
  }

  for (idx = 0; idx < pstr_uni_drc_config->downmix_instructions_count; idx++) {
    // downmixInstructions();
  }

  for (idx = 0; idx < pstr_uni_drc_config->drc_coefficients_basic_count; idx++) {
    // drcCoefficientsBasic();
  }

  for (idx = 0; idx < pstr_uni_drc_config->drc_instructions_basic_count; idx++) {
    // drcInstructionsBasics();
  }

  for (idx = 0; idx < pstr_uni_drc_config->drc_coefficients_uni_drc_count; idx++) {
    impd_drc_write_drc_coeff_uni_drc(it_bit_buf, version,
                                     &(pstr_uni_drc_config->str_drc_coefficients_uni_drc[idx]),
                                     &bit_cnt_local);
  }

  for (idx = 0; idx < pstr_uni_drc_config->drc_instructions_uni_drc_count; idx++) {
    err_code = impd_drc_write_drc_instruct_uni_drc(
        it_bit_buf, version, pstr_uni_drc_config, pstr_gain_enc,
        &(pstr_uni_drc_config->str_drc_instructions_uni_drc[idx]), ptr_scratch, &bit_cnt_local);
    if (err_code & IA_FATAL_ERROR) {
      return err_code;
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_config->uni_drc_config_ext_present, 1);
  if (pstr_uni_drc_config->uni_drc_config_ext_present) {
    err_code = impd_drc_write_uni_drc_config_extn(
        pstr_drc_state, pstr_gain_enc, pstr_uni_drc_config,
        &(pstr_uni_drc_config->str_uni_drc_config_ext), &bit_cnt_local, write_bs);
    if (err_code & IA_FATAL_ERROR) {
      return (err_code);
    }
  }

  *ptr_bit_cnt += bit_cnt_local;

  return err_code;
}

IA_ERRORCODE impd_drc_write_measured_loudness_info(ia_drc_enc_state *pstr_drc_state) {

  IA_ERRORCODE err_code = IA_NO_ERROR;
  ia_bit_buf_struct *it_bit_buf_lis = &pstr_drc_state->str_bit_buf_cfg_ext;
  WORD32 bit_cnt_lis = 0;
  err_code = impd_drc_write_loudness_info_set(pstr_drc_state, it_bit_buf_lis, &bit_cnt_lis, 1);
  if (err_code & IA_FATAL_ERROR) {
    return (err_code);
  }
  pstr_drc_state->drc_config_ext_data_size_bit = bit_cnt_lis;

  return err_code;
}

IA_ERRORCODE impd_drc_enc_initial_gain(const WORD32 gain_coding_profile, FLOAT32 gain_initial,
                                       FLOAT32 *gain_initial_quant, WORD32 *code_size,
                                       WORD32 *code) {
  WORD32 sign, magnitude, bits, size;

  switch (gain_coding_profile) {
    case GAIN_CODING_PROFILE_CONSTANT: {
      bits = 0;
      size = 0;
    } break;
    case GAIN_CODING_PROFILE_CLIPPING: {
      if (gain_initial > -0.0625f) {
        sign = 0;
        *gain_initial_quant = 0.0f;
        bits = sign;
        size = 1;
      } else {
        sign = 1;
        gain_initial = MAX(-1000.0f, gain_initial);
        magnitude = (WORD32)(-1.0f + 0.5f - 8.0f * gain_initial);
        magnitude = MIN(0xFF, magnitude);
        *gain_initial_quant = -(magnitude + 1) * 0.125f;
        bits = (sign << 8) + magnitude;
        size = 9;
      }
    } break;
    case GAIN_CODING_PROFILE_FADING: {
      if (gain_initial > -0.0625f) {
        sign = 0;
        *gain_initial_quant = 0.0f;
        bits = sign;
        size = 1;
      } else {
        sign = 1;
        gain_initial = MAX(-1000.0f, gain_initial);
        magnitude = (WORD32)(-1.0f + 0.5f - 8.0f * gain_initial);
        magnitude = MIN(0x3FF, magnitude);
        *gain_initial_quant = -(magnitude + 1) * 0.125f;
        bits = (sign << 10) + magnitude;
        size = 11;
      }
    } break;
    case GAIN_CODING_PROFILE_REGULAR: {
      if (gain_initial < 0.0f) {
        sign = 1;
        gain_initial = MAX(-1000.0f, gain_initial);
        magnitude = (WORD32)(0.5f - 8.0f * gain_initial);
        magnitude = MIN(0xFF, magnitude);
        *gain_initial_quant = -magnitude * 0.125f;
      } else {
        sign = 0;
        gain_initial = MIN(1000.0f, gain_initial);
        magnitude = (WORD32)(0.5f + 8.0f * gain_initial);
        magnitude = MIN(0xFF, magnitude);
        *gain_initial_quant = magnitude * 0.125f;
      }
      bits = (sign << 8) + magnitude;
      size = 9;
    } break;
    default:
      return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
  }

  *code = bits;
  *code_size = size;

  return IA_NO_ERROR;
}

static VOID impd_drc_write_spline_nodes(ia_bit_buf_struct *it_bit_buf,
                                        ia_drc_gain_enc_struct *pstr_gain_enc,
                                        ia_drc_gain_set_params_struct *pstr_gain_set_params,
                                        ia_drc_group_for_output_struct *pstr_drc_group_for_output,
                                        WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 frame_end_flag;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local += iusace_write_bits_buf(it_bit_buf, pstr_drc_group_for_output->coding_mode, 1);
  if (pstr_drc_group_for_output->coding_mode != 0) {
    for (idx = 0; idx < pstr_drc_group_for_output->n_gain_values - 1; idx++) {
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 0, 1);
    }
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 1, 1);

    if (pstr_gain_set_params->gain_interpolation_type == GAIN_INTERPOLATION_TYPE_SPLINE) {
      for (idx = 0; idx < pstr_drc_group_for_output->n_gain_values; idx++) {
        bit_cnt_local +=
            iusace_write_bits_buf(it_bit_buf, pstr_drc_group_for_output->slope_code[idx],
                                  (UWORD8)pstr_drc_group_for_output->slope_code_size[idx]);
      }
    }

    if (pstr_gain_set_params->full_frame == 0 && pstr_drc_group_for_output->n_gain_values > 0) {
      if (pstr_drc_group_for_output->ts_gain_quant[pstr_drc_group_for_output->n_gain_values -
                                                   1] == (pstr_gain_enc->drc_frame_size - 1)) {
        frame_end_flag = 1;
      } else {
        frame_end_flag = 0;
      }
      bit_cnt_local += iusace_write_bits_buf(it_bit_buf, frame_end_flag, 1);
    } else {
      frame_end_flag = 1;
    }

    for (idx = 0; idx < pstr_drc_group_for_output->n_gain_values; idx++) {
      if (idx < (pstr_drc_group_for_output->n_gain_values - 1) || !frame_end_flag) {
        bit_cnt_local +=
            iusace_write_bits_buf(it_bit_buf, pstr_drc_group_for_output->time_delta_code[idx],
                                  (UWORD8)pstr_drc_group_for_output->time_delta_code_size[idx]);
      }
    }
    for (idx = 0; idx < pstr_drc_group_for_output->n_gain_values; idx++) {
      bit_cnt_local +=
          iusace_write_bits_buf(it_bit_buf, pstr_drc_group_for_output->gain_code[idx],
                                (UWORD8)pstr_drc_group_for_output->gain_code_length[idx]);
    }
  } else {
    bit_cnt_local +=
        iusace_write_bits_buf(it_bit_buf, pstr_drc_group_for_output->gain_code[0],
                              (UWORD8)pstr_drc_group_for_output->gain_code_length[0]);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

static VOID impd_drc_write_uni_drc_gain_extension(
    ia_bit_buf_struct *it_bit_buf, ia_drc_uni_drc_gain_ext_struct *pstr_uni_drc_gain_ext,
    WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 counter = 0;
  WORD32 ext_size_bits, bit_size_len, bit_size;
  WORD32 bit_cnt_local = 0;

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, pstr_uni_drc_gain_ext->uni_drc_gain_ext_type[counter], 4);
  while (pstr_uni_drc_gain_ext->uni_drc_gain_ext_type[counter] != UNIDRC_GAIN_EXT_TERM) {
    bit_size = pstr_uni_drc_gain_ext->ext_bit_size[counter] - 1;
    ext_size_bits = (WORD32)(log((FLOAT32)bit_size) / log(2.f)) + 1;
    bit_size_len = ext_size_bits - 4;
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size_len, 3);
    bit_cnt_local += iusace_write_bits_buf(it_bit_buf, bit_size, (UWORD8)ext_size_bits);
    switch (pstr_uni_drc_gain_ext->uni_drc_gain_ext_type[counter]) {
      default:
        for (idx = 0; idx < pstr_uni_drc_gain_ext->ext_bit_size[counter]; idx++) {
          bit_cnt_local += iusace_write_bits_buf(it_bit_buf, 0, 1);
        }
    }
    counter++;

    bit_cnt_local += iusace_write_bits_buf(
        it_bit_buf, pstr_uni_drc_gain_ext->uni_drc_gain_ext_type[counter], 4);
  }

  *ptr_bit_cnt += bit_cnt_local;
}

VOID impd_drc_write_uni_drc_gain(ia_drc_enc_state *pstr_drc_state, WORD32 *ptr_bit_cnt) {
  LOOPIDX idx;
  WORD32 bit_cnt_local = 0;
  ia_bit_buf_struct *it_bit_buf = &pstr_drc_state->str_bit_buf_out;
  ia_drc_gain_enc_struct *pstr_gain_enc = &pstr_drc_state->str_gain_enc;
  ia_drc_group_for_output_struct *pstr_drc_group_for_output;
  ia_drc_gain_set_params_struct *pstr_gain_set_params;
  ia_drc_uni_drc_gain_ext_struct str_uni_drc_gain_extension =
      pstr_drc_state->str_enc_gain_extension;

  for (idx = 0; idx < pstr_gain_enc->n_sequences; idx++) {
    pstr_drc_group_for_output =
        &(pstr_gain_enc->str_drc_gain_seq_buf[idx].str_drc_group_for_output);
    pstr_gain_set_params = &(pstr_gain_enc->str_drc_gain_seq_buf[idx].str_gain_set_params);

    if (pstr_gain_set_params->gain_coding_profile < GAIN_CODING_PROFILE_CONSTANT) {
      impd_drc_write_spline_nodes(it_bit_buf, pstr_gain_enc, pstr_gain_set_params,
                                  pstr_drc_group_for_output, &bit_cnt_local);
    }
  }

  bit_cnt_local +=
      iusace_write_bits_buf(it_bit_buf, str_uni_drc_gain_extension.uni_drc_gain_ext_present, 1);
  if (str_uni_drc_gain_extension.uni_drc_gain_ext_present) {
    impd_drc_write_uni_drc_gain_extension(it_bit_buf, &str_uni_drc_gain_extension,
                                          &bit_cnt_local);
  }

  if (bit_cnt_local & 0x07) {
    pstr_drc_state->bit_buf_base_out[bit_cnt_local >> 3] |= 0xFF >> (bit_cnt_local & 0x07);

    bit_cnt_local += 8 - (bit_cnt_local & 0x07);
  }

  *ptr_bit_cnt += bit_cnt_local;
}
