/****************************************************************************** * * * 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 #include "ixheaac_type_def.h" #include "ixheaac_error_standards.h" #include "ixheaace_error_codes.h" #include "iusace_bitbuffer.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" static VOID impd_drc_util_stft_read_gain_config( ia_drc_stft_gain_calc_struct *pstr_stft_drc_gain_handle, WORD32 band_count, ia_drc_gain_set_params_struct *str_gain_set_params) { LOOPIDX i, j; WORD32 num_points; for (i = 0; i < band_count; i++) { num_points = str_gain_set_params->gain_params[i].nb_points; pstr_stft_drc_gain_handle[i].nb_points = num_points; for (j = 0; j < num_points; j++) { pstr_stft_drc_gain_handle[i].str_segment[2 * (j + 1)].x = str_gain_set_params->gain_params[i].gain_points[j].x; pstr_stft_drc_gain_handle[i].str_segment[2 * (j + 1)].y = str_gain_set_params->gain_params[i].gain_points[j].y; } pstr_stft_drc_gain_handle[i].width_db = str_gain_set_params->gain_params[i].width; pstr_stft_drc_gain_handle[i].attack_ms = str_gain_set_params->gain_params[i].attack; pstr_stft_drc_gain_handle[i].release_ms = str_gain_set_params->gain_params[i].decay; } } static VOID impd_drc_util_td_read_gain_config( ia_drc_compand_struct *pstr_drc_compand, ia_drc_gain_set_params_struct *str_gain_set_params) { LOOPIDX idx; WORD32 num_points; num_points = str_gain_set_params->gain_params[0].nb_points; pstr_drc_compand->nb_points = num_points; for (idx = 0; idx < num_points; idx++) { pstr_drc_compand->str_segment[2 * (idx + 1)].x = str_gain_set_params->gain_params[0].gain_points[idx].x; pstr_drc_compand->str_segment[2 * (idx + 1)].y = str_gain_set_params->gain_params[0].gain_points[idx].y; } pstr_drc_compand->width_db = str_gain_set_params->gain_params[0].width; pstr_drc_compand->str_channel_param.attack = str_gain_set_params->gain_params[0].attack; pstr_drc_compand->str_channel_param.decay = str_gain_set_params->gain_params[0].decay; pstr_drc_compand->str_channel_param.attack /= 1000.0; pstr_drc_compand->str_channel_param.decay /= 1000.0; } IA_ERRORCODE impd_drc_gain_enc_init(ia_drc_gain_enc_struct *pstr_gain_enc, ia_drc_uni_drc_config_struct *pstr_uni_drc_config, ia_drc_loudness_info_set_struct *pstr_loudness_info_set, const WORD32 frame_size, const WORD32 sample_rate, const WORD32 delay_mode, const WORD32 domain) { IA_ERRORCODE err_code = IA_NO_ERROR; LOOPIDX i, j, k, l, m, ch; WORD32 num_gain_values_max; WORD32 params_found; UWORD8 found_ch_idx; UWORD32 ch_idx; ia_drc_uni_drc_config_ext_struct *pstr_uni_drc_config_ext = &pstr_uni_drc_config->str_uni_drc_config_ext; ia_drc_coefficients_uni_drc_struct *pstr_drc_coefficients_uni_drc = &pstr_uni_drc_config->str_drc_coefficients_uni_drc[0]; ia_drc_coefficients_uni_drc_struct *pstr_drc_coefficients_uni_drc_v1 = &pstr_uni_drc_config_ext->str_drc_coefficients_uni_drc_v1[0]; if (pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count <= 0) { WORD32 all_band_gain_count = 0; WORD32 gain_set_count = pstr_drc_coefficients_uni_drc->gain_set_count; for (i = 0; i < gain_set_count; i++) { all_band_gain_count += pstr_drc_coefficients_uni_drc->str_gain_set_params[i].band_count; } pstr_gain_enc->n_sequences = all_band_gain_count; } else { for (i = 0; i < pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count; i++) { WORD32 all_band_gain_count = 0; for (j = 0; j < pstr_drc_coefficients_uni_drc_v1[i].gain_set_count; j++) { all_band_gain_count += pstr_drc_coefficients_uni_drc_v1[i].str_gain_set_params[j].band_count; } pstr_drc_coefficients_uni_drc_v1[i].gain_sequence_count = all_band_gain_count; pstr_gain_enc->n_sequences += all_band_gain_count; } } if (pstr_gain_enc->n_sequences > IMPD_DRCMAX_NSEQ) { return IA_EXHEAACE_CONFIG_FATAL_DRC_PARAM_OUT_OF_RANGE; } if ((pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count > 0) && (pstr_drc_coefficients_uni_drc_v1->drc_frame_size_present)) { pstr_gain_enc->drc_frame_size = pstr_drc_coefficients_uni_drc_v1->drc_frame_size; } else if ((pstr_uni_drc_config->drc_coefficients_uni_drc_count > 0) && (pstr_drc_coefficients_uni_drc->drc_frame_size_present)) { pstr_gain_enc->drc_frame_size = pstr_drc_coefficients_uni_drc->drc_frame_size; } else { pstr_gain_enc->drc_frame_size = frame_size; } if (pstr_gain_enc->drc_frame_size > IMPD_DRCMAX_FRAMESIZE) { return IA_EXHEAACE_CONFIG_FATAL_DRC_PARAM_OUT_OF_RANGE; } if (pstr_gain_enc->drc_frame_size < 1) { return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG; } if (!pstr_uni_drc_config->sample_rate_present) { pstr_gain_enc->sample_rate = sample_rate; } else { pstr_gain_enc->sample_rate = pstr_uni_drc_config->sample_rate; } pstr_gain_enc->domain = domain; pstr_gain_enc->delay_mode = delay_mode; pstr_gain_enc->delta_tmin_default = impd_drc_get_delta_t_min(pstr_gain_enc->sample_rate); if ((pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count > 0) && (pstr_drc_coefficients_uni_drc_v1->str_gain_set_params[0].time_delta_min_present == 1)) { pstr_gain_enc->delta_tmin = pstr_drc_coefficients_uni_drc_v1->str_gain_set_params[0].delta_tmin; } else if ((pstr_uni_drc_config->drc_coefficients_uni_drc_count > 0) && (pstr_drc_coefficients_uni_drc->str_gain_set_params[0].time_delta_min_present == 1)) { pstr_gain_enc->delta_tmin = pstr_drc_coefficients_uni_drc->str_gain_set_params[0].delta_tmin; } else { pstr_gain_enc->delta_tmin = impd_drc_get_delta_t_min(pstr_gain_enc->sample_rate); } num_gain_values_max = pstr_gain_enc->drc_frame_size / pstr_gain_enc->delta_tmin; pstr_gain_enc->base_ch_count = pstr_uni_drc_config->str_channel_layout.base_ch_count; memcpy(&pstr_gain_enc->str_uni_drc_config, pstr_uni_drc_config, sizeof(ia_drc_uni_drc_config_struct)); memcpy(&pstr_gain_enc->str_loudness_info_set, pstr_loudness_info_set, sizeof(ia_drc_loudness_info_set_struct)); k = 0; if (pstr_uni_drc_config->drc_coefficients_uni_drc_count > 0) { for (j = 0; j < pstr_drc_coefficients_uni_drc->gain_set_count; j++) { ch_idx = 0; found_ch_idx = 0; ia_drc_gain_set_params_struct *pstr_gain_set_params = &pstr_drc_coefficients_uni_drc->str_gain_set_params[j]; for (m = 0; m < pstr_uni_drc_config->drc_instructions_uni_drc_count; m++) { if (pstr_uni_drc_config->str_drc_instructions_uni_drc[m].drc_location == pstr_drc_coefficients_uni_drc->drc_location) { for (ch = 0; ch < MAX_CHANNEL_COUNT; ch++) { if (pstr_uni_drc_config->str_drc_instructions_uni_drc[m].gain_set_index[ch] == j) { ch_idx = ch; found_ch_idx = 1; break; } } } if (found_ch_idx) { break; } } if (ch_idx >= (UWORD32)pstr_gain_enc->base_ch_count) { return IA_EXHEAACE_INIT_FATAL_DRC_INVALID_CHANNEL_INDEX; } if (pstr_gain_set_params->band_count > 1) { impd_drc_util_stft_read_gain_config(pstr_gain_enc->str_drc_stft_gain_handle[0][j], pstr_gain_set_params->band_count, pstr_gain_set_params); for (l = 0; l < pstr_gain_set_params->band_count; l++) { err_code = impd_drc_stft_drc_gain_calc_init(pstr_gain_enc, 0, j, l); if (err_code) { return err_code; } pstr_gain_enc->str_drc_stft_gain_handle[0][j][l].ch_idx = ch_idx; pstr_gain_enc->str_drc_stft_gain_handle[0][j][l].is_valid = 1; } } else if (pstr_gain_set_params->band_count == 1) { impd_drc_util_td_read_gain_config(&pstr_gain_enc->str_drc_compand[0][j], pstr_gain_set_params); pstr_gain_enc->str_drc_compand[0][j].initial_volume = 0.0f; err_code = impd_drc_td_drc_gain_calc_init(pstr_gain_enc, 0, j); if (err_code) { return err_code; } pstr_gain_enc->str_drc_compand[0][j].ch_idx = ch_idx; pstr_gain_enc->str_drc_compand[0][j].is_valid = 1; } for (l = 0; l < pstr_gain_set_params->band_count; l++) { pstr_gain_enc->str_drc_gain_seq_buf[k].str_drc_group.n_gain_values = 1; pstr_gain_enc->str_drc_gain_seq_buf[k].str_gain_set_params = pstr_drc_coefficients_uni_drc->str_gain_set_params[j]; k++; } } } if (pstr_uni_drc_config_ext->drc_coefficients_uni_drc_v1_count > 0) { for (i = 0; i < pstr_gain_enc->n_sequences; i++) { params_found = 0; for (j = 0; j < pstr_drc_coefficients_uni_drc_v1->gain_set_count; j++) { for (l = 0; l < pstr_drc_coefficients_uni_drc_v1->str_gain_set_params[j].band_count; l++) { if (i == pstr_drc_coefficients_uni_drc_v1->str_gain_set_params[j] .gain_params[l] .gain_sequence_index) { pstr_gain_enc->str_drc_gain_seq_buf[i].str_drc_group.n_gain_values = 1; pstr_gain_enc->str_drc_gain_seq_buf[i].str_gain_set_params = pstr_drc_coefficients_uni_drc_v1->str_gain_set_params[j]; params_found = 1; } if (params_found == 1) { break; } } if (params_found == 1) { break; } } } } impd_drc_generate_delta_time_code_table(num_gain_values_max, pstr_gain_enc->str_delta_time_code_table); for (i = num_gain_values_max - 1; i >= 0; i--) { pstr_gain_enc->delta_time_quant_table[i] = pstr_gain_enc->delta_tmin * (i + 1); } return err_code; } IA_ERRORCODE impd_drc_encode_uni_drc_gain(ia_drc_gain_enc_struct *pstr_gain_enc, FLOAT32 *ptr_gain_buffer, VOID *pstr_scratch) { LOOPIDX idx; IA_ERRORCODE err_code = IA_NO_ERROR; for (idx = 0; idx < pstr_gain_enc->n_sequences; idx++) { err_code = impd_drc_quantize_and_encode_drc_gain( pstr_gain_enc, &ptr_gain_buffer[idx * MAX_DRC_FRAME_SIZE], &(pstr_gain_enc->drc_gain_per_sample_with_prev_frame[idx][0]), pstr_gain_enc->str_delta_time_code_table, &(pstr_gain_enc->str_drc_gain_seq_buf[idx]), pstr_scratch); if (err_code) { return err_code; } } return err_code; } WORD32 impd_drc_get_delta_t_min(const WORD32 sample_rate) { WORD32 lower_bound; WORD32 result = 1; WORD32 sample_rate_local = sample_rate; if (sample_rate_local < 1000) { sample_rate_local = 1000; } lower_bound = (WORD32)((0.0005f * sample_rate_local) + 0.5f); while (result <= lower_bound) { result = result << 1; } return result; }