/******************************************************************************
 *
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "impd_type_def.h"
#include "impd_error_standards.h"
#include "impd_drc_extr_delta_coded_info.h"
#include "impd_drc_common.h"
#include "impd_drc_struct.h"
#include "impd_drc_filter_bank.h"
#include "impd_drc_multi_band.h"
#include "impd_drc_rom.h"

IA_ERRORCODE impd_fcenter_norm_sb_init(WORD32 num_subbands,
                                       FLOAT32* fcenter_norm_subband) {
  WORD32 s;
  for (s = 0; s < num_subbands; s++) {
    fcenter_norm_subband[s] = (s + 0.5f) / (2.0f * num_subbands);
  }
  return (0);
}

IA_ERRORCODE impd_generate_slope(WORD32 num_sub_bands,
                                 FLOAT32* fcenter_norm_subband,
                                 FLOAT32 fcross_norm_lo, FLOAT32 fcross_norm_hi,
                                 FLOAT32* response) {
  WORD32 i;
  FLOAT32 filter_slope = -24.0f;
  FLOAT32 inv_log10_2 = 3.32192809f;
  FLOAT32 norm = 0.05f * filter_slope * inv_log10_2;

  for (i = 0; i < num_sub_bands; i++) {
    if (fcenter_norm_subband[i] < fcross_norm_lo) {
      response[i] = (FLOAT32)pow(
          10.0, norm * log10(fcross_norm_lo / fcenter_norm_subband[i]));
    } else if (fcenter_norm_subband[i] < fcross_norm_hi) {
      response[i] = 1.0f;
    } else {
      response[i] = (FLOAT32)pow(
          10.0, norm * log10(fcenter_norm_subband[i] / fcross_norm_hi));
    }
  }
  return (0);
}

IA_ERRORCODE impd_generate_overlap_weights(
    WORD32 num_drc_bands, WORD32 drc_band_type,
    ia_gain_params_struct* gain_params, WORD32 dec_subband_count,
    ia_group_overlap_params_struct* pstr_group_overlap_params) {
  FLOAT32 fcenter_norm_subband[AUDIO_CODEC_SUBBAND_COUNT_MAX];
  FLOAT32 w_norm[AUDIO_CODEC_SUBBAND_COUNT_MAX];
  FLOAT32 fcross_norm_lo, fcross_norm_hi;
  WORD32 err, b, s, start_subband_index = 0, stop_sub_band_index = 0;
  err = impd_fcenter_norm_sb_init(dec_subband_count, fcenter_norm_subband);

  if (drc_band_type == 1) {
    fcross_norm_lo = 0.0f;
    for (b = 0; b < num_drc_bands; b++) {
      if (b < num_drc_bands - 1) {
        fcross_norm_hi =
            normal_cross_freq[gain_params[b + 1].crossover_freq_idx]
                .f_cross_norm;
      } else {
        fcross_norm_hi = 0.5f;
      }
      impd_generate_slope(
          dec_subband_count, fcenter_norm_subband, fcross_norm_lo,
          fcross_norm_hi,
          pstr_group_overlap_params->str_band_overlap_params[b].overlap_weight);

      fcross_norm_lo = fcross_norm_hi;
    }
    for (s = 0; s < dec_subband_count; s++) {
      w_norm[s] = pstr_group_overlap_params->str_band_overlap_params[0]
                      .overlap_weight[s];
      for (b = 1; b < num_drc_bands; b++) {
        w_norm[s] += pstr_group_overlap_params->str_band_overlap_params[b]
                         .overlap_weight[s];
      }
    }

    for (s = 0; s < dec_subband_count; s++) {
      for (b = 0; b < num_drc_bands; b++) {
        pstr_group_overlap_params->str_band_overlap_params[b]
            .overlap_weight[s] /= w_norm[s];
      }
    }
  } else {
    start_subband_index = 0;
    for (b = 0; b < num_drc_bands; b++) {
      if (b < num_drc_bands - 1) {
        stop_sub_band_index = gain_params[b + 1].start_subband_index - 1;
      } else {
        stop_sub_band_index = dec_subband_count - 1;
      }
      for (s = 0; s < dec_subband_count; s++) {
        if (s >= start_subband_index && s <= stop_sub_band_index) {
          pstr_group_overlap_params->str_band_overlap_params[b]
              .overlap_weight[s] = 1.0;
        } else {
          pstr_group_overlap_params->str_band_overlap_params[b]
              .overlap_weight[s] = 0.0;
        }
      }
      start_subband_index = stop_sub_band_index + 1;
    }
  }

  return (0);
}

IA_ERRORCODE impd_init_overlap_weight(
    ia_uni_drc_coeffs_struct* str_p_loc_drc_coefficients_uni_drc,
    ia_drc_instructions_struct* str_drc_instruction_str,
    WORD32 sub_band_domain_mode,
    ia_overlap_params_struct* pstr_overlap_params) {
  WORD32 err = 0, g;
  WORD32 dec_subband_count = 0;
  switch (sub_band_domain_mode) {
    case SUBBAND_DOMAIN_MODE_QMF64:
      dec_subband_count = AUDIO_CODEC_SUBBAND_COUNT_QMF64;
      break;
    case SUBBAND_DOMAIN_MODE_QMF71:
      dec_subband_count = AUDIO_CODEC_SUBBAND_COUNT_QMF71;
      break;
    case SUBBAND_DOMAIN_MODE_STFT256:
      dec_subband_count = AUDIO_CODEC_SUBBAND_COUNT_STFT256;
      break;
  }

  for (g = 0; g < str_drc_instruction_str->num_drc_ch_groups; g++) {
    if (str_drc_instruction_str->band_count_of_ch_group[g] > 1) {
      err = impd_generate_overlap_weights(
          str_drc_instruction_str->band_count_of_ch_group[g],
          str_p_loc_drc_coefficients_uni_drc
              ->gain_set_params[str_drc_instruction_str
                                    ->gain_set_index_for_channel_group[g]]
              .drc_band_type,
          str_p_loc_drc_coefficients_uni_drc
              ->gain_set_params[str_drc_instruction_str
                                    ->gain_set_index_for_channel_group[g]]
              .gain_params,
          dec_subband_count,
          &(pstr_overlap_params->str_group_overlap_params[g]));
      if (err) return (err);
    }
  }

  return (0);
}
