/****************************************************************************** * * * Copyright (C) 2024 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 #include #include #include "ixheaac_type_def.h" #include "ixheaac_error_standards.h" #include "ixheaace_error_codes.h" #include "ixheaace_api.h" #include "ixheaace_loudness_measurement.h" #include "iusace_cnst.h" #include "ixheaac_constants.h" FLOAT64 a_coeff_pre_flt[12][3] = { {0, -1.84460946989011, 0.85584332293064}, /* 96000Hz sample_rate*/ {0, -1.83091998796233, 0.84414226108785}, /* 88200Hz sample_rate*/ {0, -1.76738637827624, 0.79175893605869}, /* 64000Hz sample_rate*/ {0, -1.69065929318241, 0.73248077421585}, /* 48000Hz sample_rate*/ {0, -1.66365511325602, 0.71259542807323}, /* 44100Hz sample_rate*/ {0, -1.53904509625064, 0.62696685598156}, /* 32000Hz sample_rate*/ {0, -1.39023460519282, 0.53683848126040}, /* 24000Hz sample_rate*/ {0, -1.33830533606613, 0.50824455891360}, /* 22050Hz sample_rate*/ {0, -1.10153376910699, 0.39491236874986}, /* 16000Hz sample_rate*/ {0, -0.82398044060334, 0.29429059828526}, /* 12000Hz sample_rate*/ {0, -0.73075690963163, 0.26764083061798}, /* 11025Hz sample_rate*/ {0, -0.29338078241492, 0.18687510604541}}; /* 8000Hz sample_rate*/ FLOAT64 b_coeff_pre_flt[12][3] = { {1.55971422897580, -2.92674157825108, 1.37826120231582}, /* 96000Hz sample_rate*/ {1.55751537557965, -2.90562707992635, 1.36133397747221}, /* 88200Hz sample_rate*/ {1.54734277602520, -2.80819560855113, 1.28522539030837}, /* 64000Hz sample_rate*/ {1.53512485958697, -2.69169618940638, 1.19839281085285}, /* 48000Hz sample_rate*/ {1.53084123005034, -2.65097999515473, 1.16907907992158}, /* 44100Hz sample_rate*/ {1.51117789956876, -2.46488941336014, 1.04163327352229}, /* 32000Hz sample_rate*/ {1.48790022096228, -2.24620546814114, 0.90490912324644}, /* 24000Hz sample_rate*/ {1.47982535097775, -2.17072861285683, 0.86084248472655}, /* 22050Hz sample_rate*/ {1.44329522349136, -1.83157538126046, 0.68165875741197}, /* 16000Hz sample_rate*/ {1.40101638596118, -1.44343141964020, 0.51272519136094}, /* 12000Hz sample_rate*/ {1.38693639705635, -1.31515305817747, 0.46510058210747}, /* 11025Hz sample_rate*/ {1.32162356892998, -0.72625549131569, 0.29812624601620}}; /* 8000Hz sample_rate*/ FLOAT64 a_coeff_RLB_flt[12][3] = { {0, -1.99501754472472, 0.99502375904092}, /* 96000Hz sample_rate*/ {0, -1.99457751545034, 0.99458487587805}, /* 88200Hz sample_rate*/ {0, -1.99253095794890, 0.99254492277827}, /* 64000Hz sample_rate*/ {0, -1.99004745483398, 0.99007225036621}, /* 48000Hz sample_rate*/ {0, -1.98916967362979, 0.98919903578704}, /* 44100Hz sample_rate*/ {0, -1.98508966898868, 0.98514532066955}, /* 32000Hz sample_rate*/ {0, -1.98014412622893, 0.98024281785928}, /* 24000Hz sample_rate*/ {0, -1.97839760259012, 0.97851441950325}, /* 22050Hz sample_rate*/ {0, -1.97028952800443, 0.97051049053584}, /* 16000Hz sample_rate*/ {0, -1.96048317995201, 0.96087407552357}, /* 12000Hz sample_rate*/ {0, -1.95712192483092, 0.95758214578578}, /* 11025Hz sample_rate*/ {0, -1.94101334282922, 0.94188430416850}}; /* 8000Hz sample_rate*/ FLOAT64 b_coeff_RLB_flt[12][3] = { {1.00247575433736, -2.00497008989074, 1.00247575433736}, /* 96000Hz sample_rate*/ {1.00225631275593, -2.00453006061636, 1.00225631275593}, /* 88200Hz sample_rate*/ {1.00123633620603, -2.00248350311492, 1.00123633620603}, /* 64000Hz sample_rate*/ {1.0, -2.0, 1.0}, /* 48000Hz sample_rate*/ {0.99956006454251, -1.9991201290850, 0.99956006454251}, /* 44100Hz sample_rate*/ {0.99751647782627, -1.9950329556525, 0.99751647782627}, /* 32000Hz sample_rate*/ {0.99508528374654, -1.99009667139495, 0.99508528374654}, /* 24000Hz sample_rate*/ {0.99422108456853, -1.98835014775614, 0.99422108456853}, /* 22050Hz sample_rate*/ {0.99021912008482, -1.98024207317045, 0.99021912008482}, /* 16000Hz sample_rate*/ {0.98540091257869, -1.97043572511803, 0.98540091257869}, /* 12000Hz sample_rate*/ {0.98375494770979, -1.96707446999694, 0.98375494770979}, /* 11025Hz sample_rate*/ {0.97590602690115, -1.95096588799524, 0.97590602690115}}; /* 8000Hz sample_rate*/ static WORD32 ixheaace_map_sample_rate(WORD32 sample_rate, ixheaace_loudness_struct *pstr_loudness_hdl) { WORD32 mapped_sample_rate = sample_rate; if ((mapped_sample_rate >= 0) && (mapped_sample_rate < 9391)) { mapped_sample_rate = 8000; pstr_loudness_hdl->sample_rate_idx = 11; } else if ((mapped_sample_rate >= 9391) && (mapped_sample_rate < 11502)) { mapped_sample_rate = 11025; pstr_loudness_hdl->sample_rate_idx = 10; } else if ((mapped_sample_rate >= 11502) && (mapped_sample_rate < 13856)) { mapped_sample_rate = 12000; pstr_loudness_hdl->sample_rate_idx = 9; } else if ((mapped_sample_rate >= 13856) && (mapped_sample_rate < 18783)) { mapped_sample_rate = 16000; pstr_loudness_hdl->sample_rate_idx = 8; } else if ((mapped_sample_rate >= 18783) && (mapped_sample_rate < 23004)) { mapped_sample_rate = 22050; pstr_loudness_hdl->sample_rate_idx = 7; } else if ((mapped_sample_rate >= 23004) && (mapped_sample_rate < 27713)) { mapped_sample_rate = 24000; pstr_loudness_hdl->sample_rate_idx = 6; } else if ((mapped_sample_rate >= 27713) && (mapped_sample_rate < 37566)) { mapped_sample_rate = 32000; pstr_loudness_hdl->sample_rate_idx = 5; } else if ((mapped_sample_rate >= 37566) && (mapped_sample_rate < 46009)) { mapped_sample_rate = 44100; pstr_loudness_hdl->sample_rate_idx = 4; } else if ((mapped_sample_rate >= 46009) && (mapped_sample_rate < 55426)) { mapped_sample_rate = 48000; pstr_loudness_hdl->sample_rate_idx = 3; } else if ((mapped_sample_rate >= 55426) && (mapped_sample_rate < 75132)) { mapped_sample_rate = 64000; pstr_loudness_hdl->sample_rate_idx = 2; } else if ((mapped_sample_rate >= 75132) && (mapped_sample_rate < 92017)) { mapped_sample_rate = 88200; pstr_loudness_hdl->sample_rate_idx = 1; } else if (mapped_sample_rate >= 92017) { mapped_sample_rate = 96000; pstr_loudness_hdl->sample_rate_idx = 0; } else { mapped_sample_rate = 48000; pstr_loudness_hdl->sample_rate_idx = 3; } return mapped_sample_rate; } WORD32 ixheaace_loudness_info_get_handle_size() { return IXHEAAC_GET_SIZE_ALIGNED(sizeof(ixheaace_loudness_struct), BYTE_ALIGN_8); } IA_ERRORCODE ixheaace_loudness_init_params(pVOID loudness_handle, ixheaace_input_config *pstr_input_config, ixheaace_output_config *pstr_output_config) { UWORD32 count = 0; UWORD8 temp_count = 0; IA_ERRORCODE err_code = IA_NO_ERROR; ixheaace_loudness_struct *pstr_loudness_hdl = (ixheaace_loudness_struct *)loudness_handle; memset(pstr_loudness_hdl, 0, sizeof(ixheaace_loudness_struct)); pstr_loudness_hdl->sample_rate = ixheaace_map_sample_rate(pstr_input_config->i_samp_freq, pstr_loudness_hdl); pstr_output_config->samp_freq = pstr_loudness_hdl->sample_rate; pstr_loudness_hdl->length = pstr_input_config->aac_config.length; pstr_loudness_hdl->pcm_sz = pstr_input_config->ui_pcm_wd_sz; if (pstr_loudness_hdl->pcm_sz != 16) { return (IA_EXHEAACE_CONFIG_FATAL_PCM_WDSZ); } pstr_loudness_hdl->n_channels = pstr_input_config->i_channels; if (pstr_loudness_hdl->n_channels > 2 || pstr_loudness_hdl->n_channels < 1) { return (IA_EXHEAACE_CONFIG_FATAL_NUM_CHANNELS); } pstr_loudness_hdl->num_samples_per_ch = (pstr_loudness_hdl->sample_rate / 10); pstr_loudness_hdl->sum_square = 0; pstr_loudness_hdl->mom_loudness_first_time_flag = 1; pstr_loudness_hdl->count_fn_call_mmstl = 0; pstr_loudness_hdl->sl_first_time_flag = 1; pstr_loudness_hdl->local_sl_count = 0; pstr_loudness_hdl->short_term_loudness_overlap = IXHEAACE_SL_OVERLAP; pstr_loudness_hdl->no_of_mf = IXHEAACE_SEC_TO_100MS_FACTOR; pstr_loudness_hdl->no_of_mf -= IXHEAACE_MOMENTARY_LOUDNESS_OVERLAP; pstr_loudness_hdl->no_of_stf = (((pstr_loudness_hdl->no_of_mf + IXHEAACE_MOMENTARY_LOUDNESS_OVERLAP) - 30) / (30 - pstr_loudness_hdl->short_term_loudness_overlap)) + 1; pstr_loudness_hdl->tot_int_val_stf_passing_abs_gate = 0; pstr_loudness_hdl->curr_stf_no = 0; pstr_loudness_hdl->loop_curr_stf_no = 0; pstr_loudness_hdl->no_of_stf_passing_abs_gate = 0; pstr_loudness_hdl->max_lra_count = pstr_loudness_hdl->no_of_stf; pstr_loudness_hdl->loop_ml_count_fn_call = 0; pstr_loudness_hdl->ml_count_fn_call = 0; pstr_loudness_hdl->max_il_buf_size = pstr_loudness_hdl->no_of_mf; pstr_loudness_hdl->get_intergrated_loudness = 1; pstr_loudness_hdl->max_sample_val = FLT_EPSILON; for (count = 0; count < pstr_loudness_hdl->n_channels; count++) { for (temp_count = 0; temp_count < IXHEAACE_LOUDNESS_NUM_TAPS; temp_count++) { pstr_loudness_hdl->w[0][count][temp_count] = 0; pstr_loudness_hdl->w[1][count][temp_count] = 0; } } for (count = 0; count < 4; count++) { pstr_loudness_hdl->prev_four_sum_square[count] = 0; } for (count = 0; count < 30; count++) { pstr_loudness_hdl->prev_thirty_sum_square[count] = 0; } count = 0; while (count < (pstr_loudness_hdl->no_of_stf)) { pstr_loudness_hdl->temp_stf_instances_loudness[count] = 0; count++; } count = 0; while (count < (pstr_loudness_hdl->no_of_stf)) { pstr_loudness_hdl->stf_instances[count].short_term_loudness = IXHEAACE_DEFAULT_SHORT_TERM_LOUDENSS; pstr_loudness_hdl->stf_instances[count].int_val = 0; pstr_loudness_hdl->stf_instances[count].passes_abs_gate = FALSE; count++; } count = 0; while (count < pstr_loudness_hdl->no_of_mf) { pstr_loudness_hdl->mf_instances[count].momentary_loudness = IXHEAACE_DEFAULT_MOMENTARY_LOUDENSS; pstr_loudness_hdl->mf_instances[count].int_val = 0.0; pstr_loudness_hdl->mf_instances[count].passes_abs_gate = FALSE; count++; } return err_code; } static FLOAT64 ixheaace_loudness_gen_flt(FLOAT64 *a, FLOAT64 *b, FLOAT64 *w, FLOAT64 input) { FLOAT64 output = 0; UWORD8 count; for (count = 0; count <= IXHEAACE_LOUDNESS_NUM_TAPS - 2; count++) { w[count] = w[count + 1]; } w[IXHEAACE_LOUDNESS_NUM_TAPS - 1] = 0; for (count = 1; count <= IXHEAACE_LOUDNESS_NUM_TAPS - 1; count++) { w[IXHEAACE_LOUDNESS_NUM_TAPS - 1] += a[count] * w[IXHEAACE_LOUDNESS_NUM_TAPS - count - 1]; } w[IXHEAACE_LOUDNESS_NUM_TAPS - 1] = input - w[IXHEAACE_LOUDNESS_NUM_TAPS - 1]; for (count = 0; count <= IXHEAACE_LOUDNESS_NUM_TAPS - 1; count++) { output += b[count] * w[IXHEAACE_LOUDNESS_NUM_TAPS - count - 1]; } return output; } static FLOAT64 ixheaace_loudness_k_flt(FLOAT64 input, ixheaace_loudness_struct *pstr_loudness_hdl, UWORD8 channel_no) { FLOAT64 temp; temp = ixheaace_loudness_gen_flt(a_coeff_pre_flt[pstr_loudness_hdl->sample_rate_idx], b_coeff_pre_flt[pstr_loudness_hdl->sample_rate_idx], pstr_loudness_hdl->w[IXHEAACE_LOUDNESS_PRE_FLT][channel_no], input); temp = ixheaace_loudness_gen_flt(a_coeff_RLB_flt[pstr_loudness_hdl->sample_rate_idx], b_coeff_RLB_flt[pstr_loudness_hdl->sample_rate_idx], pstr_loudness_hdl->w[IXHEAACE_LOUDNESS_RLB_FLT][channel_no], temp); return temp; } static VOID ixheaace_measure_sum_square(WORD16 **input, ixheaace_loudness_struct *pstr_loudness_hdl) { FLOAT64 tot_one_channel = 0; FLOAT64 sum_square = 0; UWORD32 count = 0; FLOAT64 temp = 0; UWORD8 channel_no = 0; FLOAT64 input_sample; for (channel_no = 0; channel_no < pstr_loudness_hdl->n_channels; channel_no++) { tot_one_channel = 0; for (count = 0; count < pstr_loudness_hdl->num_samples_per_ch; count++) { input_sample = (FLOAT64)input[channel_no][count] / 32768.0; pstr_loudness_hdl->max_sample_val = MAX(fabs(input_sample), pstr_loudness_hdl->max_sample_val); temp = ixheaace_loudness_k_flt(input_sample, pstr_loudness_hdl, channel_no); tot_one_channel = tot_one_channel + (temp * temp); } sum_square += tot_one_channel; } pstr_loudness_hdl->sum_square = sum_square; } static FLOAT64 ixheaace_measure_momentary_loudness(ixheaace_loudness_struct *pstr_loudness_hdl) { FLOAT64 sum = 0; FLOAT64 momentary_loudness; UWORD32 count = 0; FLOAT64 old_ml_val, db_old_ml_val; { for (count = 0; count <= 2; count++) { pstr_loudness_hdl->prev_four_sum_square[count] = pstr_loudness_hdl->prev_four_sum_square[count + 1]; sum += pstr_loudness_hdl->prev_four_sum_square[count]; } pstr_loudness_hdl->prev_four_sum_square[3] = pstr_loudness_hdl->sum_square; sum += pstr_loudness_hdl->prev_four_sum_square[3]; if ((pstr_loudness_hdl->mom_loudness_first_time_flag == 1) && (pstr_loudness_hdl->count_fn_call_mmstl <= 2)) { momentary_loudness = IXHEAACE_LOUDNESS_DONT_PASS; } else { pstr_loudness_hdl->mom_loudness_first_time_flag = 0; momentary_loudness = -0.691 + 10 * log10(sum / ((FLOAT64)(4 * pstr_loudness_hdl->num_samples_per_ch))); if (pstr_loudness_hdl->get_intergrated_loudness == 1) { old_ml_val = pstr_loudness_hdl->mf_instances[pstr_loudness_hdl->loop_ml_count_fn_call].int_val; pstr_loudness_hdl->mf_instances[pstr_loudness_hdl->loop_ml_count_fn_call].int_val = sum / ((FLOAT64)(4 * pstr_loudness_hdl->num_samples_per_ch)); db_old_ml_val = pstr_loudness_hdl->mf_instances[pstr_loudness_hdl->loop_ml_count_fn_call] .momentary_loudness; pstr_loudness_hdl->mf_instances[pstr_loudness_hdl->loop_ml_count_fn_call] .momentary_loudness = momentary_loudness; if (pstr_loudness_hdl->mf_instances[pstr_loudness_hdl->loop_ml_count_fn_call] .momentary_loudness >= IXHEAACE_ABS_GATE) { if (db_old_ml_val < IXHEAACE_ABS_GATE) { pstr_loudness_hdl->no_of_mf_passing_abs_gate++; old_ml_val = 0; } pstr_loudness_hdl->tot_int_val_mf_passing_abs_gate = pstr_loudness_hdl->tot_int_val_mf_passing_abs_gate + (pstr_loudness_hdl->mf_instances[pstr_loudness_hdl->loop_ml_count_fn_call].int_val - old_ml_val); } else { if (db_old_ml_val >= IXHEAACE_ABS_GATE) { pstr_loudness_hdl->no_of_mf_passing_abs_gate--; pstr_loudness_hdl->tot_int_val_mf_passing_abs_gate = pstr_loudness_hdl->tot_int_val_mf_passing_abs_gate - old_ml_val; } } pstr_loudness_hdl->loop_ml_count_fn_call++; if (pstr_loudness_hdl->ml_count_fn_call < pstr_loudness_hdl->max_il_buf_size) pstr_loudness_hdl->ml_count_fn_call++; pstr_loudness_hdl->loop_ml_count_fn_call = pstr_loudness_hdl->loop_ml_count_fn_call % pstr_loudness_hdl->max_il_buf_size; } } } return (momentary_loudness); } FLOAT64 ixheaace_measure_integrated_loudness(pVOID loudness_handle) { UWORD32 count = 0; FLOAT64 avg = 0; FLOAT64 loudness = 0; ixheaace_loudness_struct *pstr_loudness_hdl = (ixheaace_loudness_struct *)loudness_handle; pstr_loudness_hdl->no_of_mf_passing_rel_gate = 0; pstr_loudness_hdl->tot_int_val_mf_passing_rel_gate = 0; avg = (pstr_loudness_hdl->tot_int_val_mf_passing_abs_gate / pstr_loudness_hdl->no_of_mf_passing_abs_gate); pstr_loudness_hdl->rel_gate = -0.691 + 10 * log10(avg) - 10; while (count < pstr_loudness_hdl->ml_count_fn_call) { if (pstr_loudness_hdl->mf_instances[count].momentary_loudness >= pstr_loudness_hdl->rel_gate) { pstr_loudness_hdl->no_of_mf_passing_rel_gate++; pstr_loudness_hdl->tot_int_val_mf_passing_rel_gate += pstr_loudness_hdl->mf_instances[count].int_val; } count++; } loudness = -0.691 + 10 * log10((pstr_loudness_hdl->tot_int_val_mf_passing_rel_gate / (FLOAT64)pstr_loudness_hdl->no_of_mf_passing_rel_gate)); return loudness; } FLOAT64 ixheaace_measure_loudness(pVOID loudness_handle, WORD16 **samples) { FLOAT64 loudness_value; ixheaace_loudness_struct *pstr_loudness_hdl = (ixheaace_loudness_struct *)loudness_handle; ixheaace_measure_sum_square(samples, pstr_loudness_hdl); loudness_value = ixheaace_measure_momentary_loudness(pstr_loudness_hdl); pstr_loudness_hdl->count_fn_call_mmstl++; return loudness_value; } FLOAT32 ixheaace_measure_sample_peak_value(pVOID loudness_handle) { FLOAT32 sample_peak_value; ixheaace_loudness_struct *pstr_loudness_hdl = (ixheaace_loudness_struct *)loudness_handle; sample_peak_value = (FLOAT32)(20 * log10(pstr_loudness_hdl->max_sample_val)); return sample_peak_value; }