libxaac/encoder/drc_src/impd_drc_api.c
akshayragir833 3dfa708b6e
Loudness leveling support for encoder and decoder (#99)
* Loudness leveling support for encoder and decoder

- Addition of loudness leveling support to encoder and
  decoder as per ISO/IEC 23003-4:2020/Amd.2:2023(E)

Testing:

Encoder: Smoke-test

Decoder: CTS and Conformance for x86, x86_64, armv7 and armv8 are
         passing

* Addressed review comments

* Addressed minor nits in documentation

---------

Co-authored-by: Akshay Ragir <100833@ittiam.com>
2025-07-28 17:40:45 +05:30

683 lines
34 KiB
C

/******************************************************************************
* *
* 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 <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"
#define IMPD_DRC_BOUND_CHECK(var, lower_bound, upper_bound) \
{ \
var = MIN(var, upper_bound); \
var = MAX(var, lower_bound); \
}
IA_ERRORCODE impd_drc_validate_config_params(ia_drc_input_config *pstr_inp_config) {
LOOPIDX i, j, k;
WORD32 curr_start_subband_idx, next_start_subband_idx;
ia_drc_uni_drc_config_struct *pstr_uni_drc_config = &pstr_inp_config->str_uni_drc_config;
ia_drc_loudness_info_set_struct *pstr_enc_loudness_info_set =
&pstr_inp_config->str_enc_loudness_info_set;
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->drc_instructions_uni_drc_count, 0,
MAX_DRC_INSTRUCTIONS_COUNT);
for (i = 0; i < pstr_uni_drc_config->drc_instructions_uni_drc_count; i++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i].drc_set_id, 0,
MAX_DRC_SET_ID);
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].additional_downmix_id_count, 0,
ADDITIONAL_DOWNMIX_ID_COUNT_MAX);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i].drc_location, 0,
MAX_DRC_LOCATION);
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].drc_set_target_loudness_value_upper,
MIN_DRC_TARGET_LOUDNESS, 0);
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].drc_set_target_loudness_value_lower,
MIN_DRC_TARGET_LOUDNESS, 0);
for (j = 0; j < MAX_CHANNEL_COUNT; j++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i].gain_set_index[j],
0, GAIN_SET_COUNT_MAX - 1);
}
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].num_drc_channel_groups, 0,
MAX_CHANNEL_GROUP_COUNT);
for (j = 0; j < pstr_uni_drc_config->str_drc_instructions_uni_drc[i].num_drc_channel_groups;
j++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i]
.str_gain_modifiers[j]
.attenuation_scaling[0],
0, MAX_ATTENUATION_SCALING);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i]
.str_gain_modifiers[j]
.amplification_scaling[0],
0, MAX_AMPLIFICATION_SCALING);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i]
.str_gain_modifiers[j]
.gain_offset[0],
MIN_DRC_GAIN_OFFSET, MAX_DRC_GAIN_OFFSET);
}
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i].limiter_peak_target,
MIN_LIMITER_PEAK_TARGET, 0.0f);
#ifdef LOUDNESS_LEVELING_SUPPORT
if (pstr_uni_drc_config->str_drc_instructions_uni_drc[i].drc_set_effect &
EFFECT_BIT_DUCK_SELF) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_instructions_uni_drc[i].leveling_present,
0, 1);
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].ducking_only_set_present, 0, 1);
}
#endif
}
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->drc_coefficients_uni_drc_count, 0,
MAX_DRC_COEFF_COUNT);
for (i = 0; i < pstr_uni_drc_config->drc_coefficients_uni_drc_count; i++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i].drc_location, 0,
MAX_DRC_LOCATION);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i].gain_set_count, 0,
MAX_CHANNEL_GROUP_COUNT);
for (j = 0; j < pstr_uni_drc_config->str_drc_coefficients_uni_drc[i].gain_set_count; j++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_coding_profile,
0, MAX_GAIN_CODING_PROFILE);
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config->str_drc_coefficients_uni_drc[i].str_gain_set_params[j].band_count,
0, MAX_BAND_COUNT);
for (k = 0;
k <
pstr_uni_drc_config->str_drc_coefficients_uni_drc[i].str_gain_set_params[j].band_count;
k++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.nb_points,
0, MAX_GAIN_POINTS);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.drc_characteristic,
0, MAX_DRC_CHARACTERISTIC_VALUE);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.crossover_freq_index,
0, MAX_CROSSOVER_FREQ_INDEX);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.start_sub_band_index,
0, STFT256_HOP_SIZE - 1);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.width,
-MAX_FLT_VAL_DB, MAX_FLT_VAL_DB);
for (WORD32 m = 0; m < pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.nb_points;
m++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.gain_points[m]
.x,
-MAX_FLT_VAL_DB, MAX_FLT_VAL_DB);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.gain_points[m]
.y,
-MAX_FLT_VAL_DB, MAX_FLT_VAL_DB);
}
}
for (k = 0; k < pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.band_count -
1;
k++) {
curr_start_subband_idx = pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.start_sub_band_index;
next_start_subband_idx = pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k + 1]
.start_sub_band_index;
/* It is assumed that the start index of a subband is greater than
the start index of its previous subbands for a multiband */
if (next_start_subband_idx <= curr_start_subband_idx) {
return IA_EXHEAACE_EXE_NONFATAL_USAC_INVALID_SUBBAND_INDEX;
}
}
}
}
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config->downmix_instructions_count, 0,
MAX_DOWNMIX_INSTRUCTION_COUNT);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->loudness_info_count, 0,
MAX_LOUDNESS_INFO_COUNT);
for (i = 0; i < pstr_enc_loudness_info_set->loudness_info_count; i++) {
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info[i].sample_peak_level,
MIN_SAMPLE_PEAK_LEVEL, MAX_SAMPLE_PEAK_LEVEL);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info[i].true_peak_level,
MIN_TRUE_PEAK_LEVEL, MAX_TRUE_PEAK_LEVEL);
IMPD_DRC_BOUND_CHECK(
pstr_enc_loudness_info_set->str_loudness_info[i].true_peak_level_measurement_system, 0,
MAX_MEASUREMENT_SYSTEM_TYPE);
IMPD_DRC_BOUND_CHECK(
pstr_enc_loudness_info_set->str_loudness_info[i].true_peak_level_reliability, 0,
MAX_RELIABILITY_TYPE);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info[i].measurement_count, 0,
MAX_MEASUREMENT_COUNT);
for (j = 0; j < pstr_enc_loudness_info_set->str_loudness_info[i].measurement_count; j++) {
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info[i]
.str_loudness_measure[j]
.method_definition,
0, MAX_METHOD_DEFINITION_TYPE);
IMPD_DRC_BOUND_CHECK(
pstr_enc_loudness_info_set->str_loudness_info[i].str_loudness_measure[j].method_value,
MIN_METHOD_VALUE, MAX_METHOD_VALUE);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info[i]
.str_loudness_measure[j]
.measurement_system,
0, MAX_MEASUREMENT_SYSTEM_TYPE);
IMPD_DRC_BOUND_CHECK(
pstr_enc_loudness_info_set->str_loudness_info[i].str_loudness_measure[j].reliability, 0,
MAX_RELIABILITY_TYPE);
}
}
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->loudness_info_album_count, 0,
MAX_LOUDNESS_INFO_COUNT);
for (i = 0; i < pstr_enc_loudness_info_set->loudness_info_album_count; i++) {
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info_album[i].sample_peak_level,
MIN_SAMPLE_PEAK_LEVEL, MAX_SAMPLE_PEAK_LEVEL);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info_album[i].true_peak_level,
MIN_TRUE_PEAK_LEVEL, MAX_TRUE_PEAK_LEVEL);
IMPD_DRC_BOUND_CHECK(
pstr_enc_loudness_info_set->str_loudness_info_album[i].true_peak_level_measurement_system,
0, MAX_MEASUREMENT_SYSTEM_TYPE);
IMPD_DRC_BOUND_CHECK(
pstr_enc_loudness_info_set->str_loudness_info_album[i].true_peak_level_reliability, 0,
MAX_RELIABILITY_TYPE);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info_album[i].measurement_count,
0, MAX_MEASUREMENT_COUNT);
for (j = 0; j < pstr_enc_loudness_info_set->str_loudness_info_album[i].measurement_count;
j++) {
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info_album[i]
.str_loudness_measure[j]
.method_definition,
0, MAX_METHOD_DEFINITION_TYPE);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info_album[i]
.str_loudness_measure[j]
.method_value,
MIN_METHOD_VALUE, MAX_METHOD_VALUE);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info_album[i]
.str_loudness_measure[j]
.measurement_system,
0, MAX_MEASUREMENT_SYSTEM_TYPE);
IMPD_DRC_BOUND_CHECK(pstr_enc_loudness_info_set->str_loudness_info_album[i]
.str_loudness_measure[j]
.reliability,
0, MAX_RELIABILITY_TYPE);
}
}
if (pstr_uni_drc_config->uni_drc_config_ext_present) {
ia_drc_uni_drc_config_ext_struct *pstr_uni_drc_config_ext =
&pstr_uni_drc_config->str_uni_drc_config_ext;
if (pstr_uni_drc_config_ext->downmix_instructions_v1_present) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->downmix_instructions_v1_count, 0,
DOWNMIX_INSTRUCTIONS_COUNT_MAX);
for (i = 0; i < pstr_uni_drc_config_ext->downmix_instructions_v1_count; i++) {
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_downmix_instructions_v1[i].target_layout, 0,
MAX_TARGET_LAYOUT_COUNT);
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_downmix_instructions_v1[i].target_ch_count, 0,
MAX_CHANNEL_COUNT);
}
}
if (pstr_uni_drc_config_ext->drc_coeffs_and_instructions_uni_drc_v1_present) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count, 0,
DRC_COEFFICIENTS_UNIDRC_V1_COUNT_MAX);
for (i = 0; i < pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count; i++) {
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i].gain_set_count, 0,
GAIN_SET_COUNT_MAX);
for (j = 0;
j < pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i].gain_set_count;
j++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_coding_profile,
0, MAX_GAIN_CODING_PROFILE);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.band_count,
0, MAX_BAND_COUNT);
for (k = 0; k < pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.band_count;
k++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.nb_points,
0, MAX_GAIN_POINTS);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.drc_characteristic,
0, MAX_DRC_CHARACTERISTIC_VALUE);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.crossover_freq_index,
0, MAX_CROSSOVER_FREQ_INDEX);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.start_sub_band_index,
0, STFT256_HOP_SIZE - 1);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.width,
-MAX_FLT_VAL_DB, MAX_FLT_VAL_DB);
for (WORD32 m = 0; m < pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.nb_points;
m++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.gain_points[m]
.x,
-MAX_FLT_VAL_DB, MAX_FLT_VAL_DB);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.gain_points[m]
.y,
-MAX_FLT_VAL_DB, MAX_FLT_VAL_DB);
}
}
for (k = 0; k < pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.band_count -
1;
k++) {
curr_start_subband_idx = pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k]
.start_sub_band_index;
next_start_subband_idx = pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[i]
.str_gain_set_params[j]
.gain_params[k + 1]
.start_sub_band_index;
/* It is assumed that the start index of a subband is greater than
the start index of its previous subbands for a multiband */
if (next_start_subband_idx <= curr_start_subband_idx) {
return IA_EXHEAACE_EXE_NONFATAL_USAC_INVALID_SUBBAND_INDEX;
}
}
}
}
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count, 0,
DRC_INSTRUCTIONS_UNIDRC_V1_COUNT_MAX);
for (i = 0; i < pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count; i++) {
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].drc_set_id, 0,
MAX_DRC_SET_ID);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.additional_downmix_id_count,
0, MAX_ADDITIONAL_DOWNMIX_ID);
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].drc_location, 0,
MAX_DRC_LOCATION);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.drc_set_target_loudness_value_upper,
MIN_DRC_TARGET_LOUDNESS, 0);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.drc_set_target_loudness_value_lower,
MIN_DRC_TARGET_LOUDNESS, 0);
for (j = 0; j < MAX_CHANNEL_COUNT; j++) {
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].gain_set_index[j], 0,
GAIN_SET_COUNT_MAX - 1);
}
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].num_drc_channel_groups, 0,
MAX_CHANNEL_GROUP_COUNT);
for (j = 0;
j <
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].num_drc_channel_groups;
j++) {
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.str_gain_modifiers[j]
.attenuation_scaling[0],
0, MAX_ATTENUATION_SCALING);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.str_gain_modifiers[j]
.amplification_scaling[0],
0, MAX_AMPLIFICATION_SCALING);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.str_gain_modifiers[j]
.gain_offset[0],
MIN_DRC_GAIN_OFFSET, MAX_DRC_GAIN_OFFSET);
}
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].limiter_peak_target,
MIN_LIMITER_PEAK_TARGET, 0.0f);
#ifdef LOUDNESS_LEVELING_SUPPORT
if (pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].drc_set_effect &
EFFECT_BIT_DUCK_SELF) {
IMPD_DRC_BOUND_CHECK(
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].leveling_present, 0, 1);
IMPD_DRC_BOUND_CHECK(pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.ducking_only_set_present,
0, 1);
}
#endif
}
}
}
return IA_NO_ERROR;
}
static IA_ERRORCODE impd_drc_validate_drc_instructions(
ia_drc_uni_drc_config_struct *pstr_uni_drc_config) {
LOOPIDX i, j;
WORD32 profile_found = FALSE;
for (i = 0; i < pstr_uni_drc_config->drc_instructions_uni_drc_count; i++) {
profile_found = FALSE;
for (j = 0; j < pstr_uni_drc_config->drc_coefficients_uni_drc_count; j++) {
if (pstr_uni_drc_config->str_drc_coefficients_uni_drc[j].drc_location == 1) {
profile_found = TRUE;
break;
}
}
if (pstr_uni_drc_config->uni_drc_config_ext_present &&
pstr_uni_drc_config->str_uni_drc_config_ext.parametric_drc_present &&
pstr_uni_drc_config->str_uni_drc_config_ext.str_drc_coeff_parametric_drc.drc_location ==
1) {
profile_found = TRUE;
}
if (profile_found == FALSE) {
return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
}
#ifdef LOUDNESS_LEVELING_SUPPORT
if (pstr_uni_drc_config->str_drc_instructions_uni_drc[i].drc_set_effect &
EFFECT_BIT_DUCK_SELF) {
if (pstr_uni_drc_config->str_drc_instructions_uni_drc[i].leveling_present &&
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].ducking_only_set_present) {
if (i < pstr_uni_drc_config->drc_instructions_uni_drc_count - 1) {
if (pstr_uni_drc_config->str_drc_instructions_uni_drc[i + 1].drc_set_effect !=
EFFECT_BIT_DUCK_SELF &&
pstr_uni_drc_config->str_drc_instructions_uni_drc[i + 1].drc_set_effect !=
EFFECT_BIT_DUCK_OTHER) {
pstr_uni_drc_config->str_drc_instructions_uni_drc[i + 1].drc_set_effect =
EFFECT_BIT_DUCK_SELF;
}
pstr_uni_drc_config->str_drc_instructions_uni_drc[i + 1].leveling_present = 0;
pstr_uni_drc_config->str_drc_instructions_uni_drc[i + 1].ducking_only_set_present = 0;
} else {
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].ducking_only_set_present = 0;
}
} else if (!pstr_uni_drc_config->str_drc_instructions_uni_drc[i].leveling_present &&
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].ducking_only_set_present) {
pstr_uni_drc_config->str_drc_instructions_uni_drc[i].ducking_only_set_present = 0;
}
}
#endif
}
#ifdef LOUDNESS_LEVELING_SUPPORT
if (pstr_uni_drc_config->uni_drc_config_ext_present) {
ia_drc_uni_drc_config_ext_struct *pstr_uni_drc_config_ext =
&pstr_uni_drc_config->str_uni_drc_config_ext;
for (i = 0; i < pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count; i++) {
if (pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].drc_set_effect &
EFFECT_BIT_DUCK_SELF) {
if (pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].leveling_present &&
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.ducking_only_set_present) {
if (i < pstr_uni_drc_config_ext->drc_instructions_uni_drc_v1_count - 1) {
if (pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i + 1].drc_set_effect !=
EFFECT_BIT_DUCK_SELF &&
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i + 1].drc_set_effect !=
EFFECT_BIT_DUCK_OTHER) {
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i + 1].drc_set_effect =
EFFECT_BIT_DUCK_SELF;
}
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i + 1].leveling_present = 0;
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i + 1]
.ducking_only_set_present = 0;
} else {
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].ducking_only_set_present =
0;
}
} else if (!pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.leveling_present &&
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i]
.ducking_only_set_present) {
pstr_uni_drc_config_ext->str_drc_instructions_uni_drc_v1[i].ducking_only_set_present =
0;
}
}
}
}
#endif
return IA_NO_ERROR;
}
IA_ERRORCODE impd_drc_enc_init(VOID *pstr_drc_state, VOID *ptr_drc_scratch,
ia_drc_input_config *pstr_inp_config) {
IA_ERRORCODE err_code = IA_NO_ERROR;
WORD32 bit_count = 0;
ia_drc_enc_state *pstr_drc_state_local = pstr_drc_state;
pstr_drc_state_local->drc_scratch_mem = ptr_drc_scratch;
pstr_drc_state_local->drc_scratch_used = 0;
iusace_create_bit_buffer(&pstr_drc_state_local->str_bit_buf_cfg,
pstr_drc_state_local->bit_buf_base_cfg,
sizeof(pstr_drc_state_local->bit_buf_base_cfg), 1);
iusace_create_bit_buffer(&pstr_drc_state_local->str_bit_buf_cfg_ext,
pstr_drc_state_local->bit_buf_base_cfg_ext,
sizeof(pstr_drc_state_local->bit_buf_base_cfg_ext), 1);
iusace_create_bit_buffer(&pstr_drc_state_local->str_bit_buf_cfg_tmp,
pstr_drc_state_local->bit_buf_base_cfg_tmp,
sizeof(pstr_drc_state_local->bit_buf_base_cfg_tmp), 1);
iusace_create_bit_buffer(&pstr_drc_state_local->str_bit_buf_out,
pstr_drc_state_local->bit_buf_base_out,
sizeof(pstr_drc_state_local->bit_buf_base_out), 1);
err_code = impd_drc_gain_enc_init(
&pstr_drc_state_local->str_gain_enc, &pstr_inp_config->str_uni_drc_config,
&pstr_inp_config->str_enc_loudness_info_set, pstr_inp_config->str_enc_params.frame_size,
pstr_inp_config->str_enc_params.sample_rate, pstr_inp_config->str_enc_params.delay_mode,
pstr_inp_config->str_enc_params.domain);
if (err_code) {
return err_code;
}
#ifdef LOUDNESS_LEVELING_SUPPORT
err_code = impd_drc_validate_drc_instructions(&pstr_inp_config->str_uni_drc_config);
if (err_code & IA_FATAL_ERROR) {
return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
}
pstr_drc_state_local->str_enc_params = pstr_inp_config->str_enc_params;
pstr_drc_state_local->str_uni_drc_config = pstr_inp_config->str_uni_drc_config;
pstr_drc_state_local->str_enc_gain_extension = pstr_inp_config->str_enc_gain_extension;
pstr_drc_state_local->str_gain_enc.str_uni_drc_config = pstr_inp_config->str_uni_drc_config;
#else
pstr_drc_state_local->str_enc_params = pstr_inp_config->str_enc_params;
pstr_drc_state_local->str_uni_drc_config = pstr_inp_config->str_uni_drc_config;
pstr_drc_state_local->str_enc_gain_extension = pstr_inp_config->str_enc_gain_extension;
err_code = impd_drc_validate_drc_instructions(&pstr_inp_config->str_uni_drc_config);
if (err_code & IA_FATAL_ERROR) {
return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
}
#endif
err_code = impd_drc_write_uni_drc_config(pstr_drc_state_local, &bit_count, 1);
if (err_code & IA_FATAL_ERROR) {
return err_code;
}
pstr_drc_state_local->drc_config_data_size_bit = bit_count;
// Loudness info set
if (pstr_drc_state_local->str_gain_enc.str_uni_drc_config.loudness_info_set_present == 1) {
bit_count = 0;
iusace_reset_bit_buffer(&pstr_drc_state_local->str_bit_buf_cfg_ext);
err_code = impd_drc_write_loudness_info_set(
pstr_drc_state, &pstr_drc_state_local->str_bit_buf_cfg_ext, &bit_count, 1);
if (err_code & IA_FATAL_ERROR) {
return (err_code);
}
pstr_drc_state_local->drc_config_ext_data_size_bit = bit_count;
}
return err_code;
}
IA_ERRORCODE impd_loudness_info_init(VOID *pstr_drc_state, ia_drc_input_config *pstr_inp_config) {
IA_ERRORCODE err_code = IA_NO_ERROR;
ia_drc_enc_state *pstr_drc_state_local = pstr_drc_state;
iusace_create_bit_buffer(&pstr_drc_state_local->str_bit_buf_cfg_ext,
pstr_drc_state_local->bit_buf_base_cfg_ext,
sizeof(pstr_drc_state_local->bit_buf_base_cfg_ext), 1);
memcpy(&pstr_drc_state_local->str_gain_enc.str_loudness_info_set,
&pstr_inp_config->str_enc_loudness_info_set, sizeof(ia_drc_loudness_info_set_struct));
err_code = impd_drc_write_measured_loudness_info(pstr_drc_state_local);
return err_code;
}
IA_ERRORCODE impd_drc_enc(VOID *pstr_drc_state, FLOAT32 **pptr_input, UWORD32 inp_offset,
WORD32 *ptr_bits_written, VOID *pstr_scratch) {
LOOPIDX i, j, k;
WORD32 band_count = 0;
WORD32 stop_sub_band_index;
WORD32 num_bits_payload = 0;
UWORD8 is_fft_ready[MAX_NUM_CHANNELS] = {0};
ia_drc_enc_state *pstr_drc_state_local = pstr_drc_state;
ia_drc_gain_enc_struct *pstr_gain_enc = &pstr_drc_state_local->str_gain_enc;
ia_drc_uni_drc_config_struct *pstr_uni_drc_config = &pstr_drc_state_local->str_uni_drc_config;
ia_drc_compand_struct *pstr_drc_compand;
ia_drc_stft_gain_calc_struct *pstr_drc_stft_gain_calc;
IA_ERRORCODE err_code = IA_NO_ERROR;
if (pstr_drc_state_local->str_enc_params.gain_sequence_present) {
for (i = 0; i < MAX_DRC_COEFF_COUNT; i++) {
for (j = 0; j < GAIN_SET_COUNT_MAX; j++) {
pstr_drc_stft_gain_calc = &pstr_gain_enc->str_drc_stft_gain_handle[i][j][0];
pstr_drc_compand = &pstr_gain_enc->str_drc_compand[i][j];
if ((pstr_drc_compand->is_valid == 0) && (pstr_drc_stft_gain_calc->is_valid == 0)) {
break;
}
if (pstr_drc_compand->is_valid == 0) {
if (is_fft_ready[pstr_drc_stft_gain_calc->ch_idx] == 0) {
impd_drc_stft_drc_convert_to_fd(
pstr_gain_enc, &pptr_input[pstr_drc_stft_gain_calc->ch_idx][inp_offset],
pstr_drc_stft_gain_calc->ch_idx, pstr_drc_state_local->str_enc_params.frame_size,
pstr_gain_enc->complex_fft_ptr[pstr_drc_stft_gain_calc->ch_idx], pstr_scratch);
is_fft_ready[pstr_drc_stft_gain_calc->ch_idx] = 1;
}
for (k = 0; k < pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.band_count;
k++) {
if (k == pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.band_count -
1) {
stop_sub_band_index = STFT256_HOP_SIZE - 1;
} else {
stop_sub_band_index = pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k + 1]
.start_sub_band_index -
1;
}
impd_drc_stft_drc_gain_calc_process(
pstr_gain_enc, i, j, k,
pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.gain_params[k]
.start_sub_band_index,
stop_sub_band_index, pstr_drc_state_local->str_enc_params.frame_size,
pstr_gain_enc->complex_fft_ptr[pstr_drc_stft_gain_calc->ch_idx],
pstr_drc_state_local->gain_buffer[band_count + k]);
}
} else {
impd_drc_td_drc_gain_calc_process(pstr_gain_enc, i, j,
pstr_drc_state_local->str_enc_params.frame_size,
&pptr_input[pstr_drc_compand->ch_idx][inp_offset],
pstr_drc_state_local->gain_buffer[band_count]);
}
band_count += pstr_uni_drc_config->str_drc_coefficients_uni_drc[i]
.str_gain_set_params[j]
.band_count;
}
}
}
err_code = impd_drc_encode_uni_drc_gain(pstr_gain_enc, pstr_drc_state_local->gain_buffer[0],
pstr_scratch);
if (err_code) {
return err_code;
}
if (pstr_drc_state_local->is_first_drc_process_complete == 1) {
impd_drc_write_uni_drc_gain(pstr_drc_state_local, &num_bits_payload);
}
*ptr_bits_written = num_bits_payload;
return err_code;
}