/****************************************************************************** * * * 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 "ixheaac_type_def.h" #include "ixheaac_constants.h" #include "ixheaace_aac_constants.h" #include "ixheaace_psy_const.h" #include "ixheaace_tns.h" #include "ixheaace_tns_params.h" #include "ixheaace_rom.h" #include "ixheaace_common_rom.h" #include "ixheaace_bitbuffer.h" #include "ixheaac_basic_ops32.h" #include "ixheaac_basic_ops40.h" #include "ixheaac_basic_ops.h" #include "ixheaace_block_switch.h" #include "iusace_block_switch_struct_def.h" #include static FLOAT32 iaace_fmult(FLOAT32 a, FLOAT32 b) { return (a * b); } static FLOAT32 iaace_fadd(FLOAT32 a, FLOAT32 b) { return (a + b); } VOID iaace_init_block_switching(ixheaace_block_switch_control *pstr_blk_switch_ctrl, const WORD32 bit_rate, const WORD32 num_chans) { if ((num_chans == 1 && bit_rate > BLK_SWITCH_HIGH_BR_MONO) || (num_chans > 1 && bit_rate / num_chans > BLK_SWITCH_HIGH_BR_STEREO)) { pstr_blk_switch_ctrl->inv_attack_ratio = INV_ATTACK_RATIO_HIGH_BR; } else { pstr_blk_switch_ctrl->inv_attack_ratio = INV_ATTACK_RATIO_LOW_BR; } memset(pstr_blk_switch_ctrl->iir_states, 0, BLK_SWITCH_FILT_LEN * sizeof(pstr_blk_switch_ctrl->iir_states[0])); /* Clear Filtered Window Energies */ memset(pstr_blk_switch_ctrl->win_energy_filt, 0, BLK_SWITCH_WIN * sizeof(pstr_blk_switch_ctrl->win_energy_filt[0][0])); memset(pstr_blk_switch_ctrl->win_energy, 0, BLK_SWITCH_WIN * sizeof(pstr_blk_switch_ctrl->win_energy[0][0])); pstr_blk_switch_ctrl->acc_win_energy = 0; pstr_blk_switch_ctrl->win_seq = LONG_WINDOW; pstr_blk_switch_ctrl->nxt_win_seq = LONG_WINDOW; pstr_blk_switch_ctrl->attack = 0; pstr_blk_switch_ctrl->lastattack = 0; pstr_blk_switch_ctrl->attack_idx = 0; pstr_blk_switch_ctrl->last_attack_idx = 0; } static FLOAT32 iaace_search_max_with_idx(const FLOAT32 *ptr_in, WORD32 *ptr_index, WORD32 len) { FLOAT32 max = 0; WORD32 i = 0, idx = 0; do { if (ptr_in[i + 1] > max) { max = ptr_in[i + 1]; idx = i; } i++; } while (i < len); *ptr_index = idx; return max; } static FLOAT32 iaace_blk_switch_iir_filt(const FLOAT32 input, const FLOAT32 *ptr_iir_coeff, FLOAT32 *ptr_iir_states) { FLOAT32 accu_1, accu_2; FLOAT32 out; accu_1 = ptr_iir_coeff[1] * (input - ptr_iir_states[0]); accu_2 = ptr_iir_coeff[0] * ptr_iir_states[1]; out = accu_1 - accu_2; ptr_iir_states[0] = input; ptr_iir_states[1] = out; return out; } static VOID iaace_calc_window_energy(ixheaace_block_switch_control *pstr_blk_switch_ctrl, const FLOAT32 *ptr_time_signal, WORD32 ch_increment, WORD32 win_len) { WORD32 i, w; FLOAT32 acc_nrg_unfilt, acc_nrg_filt; FLOAT32 tmp_nrg_unfilt, tmp_nrg_filt; for (w = 0; w < BLK_SWITCH_WIN; w++) { acc_nrg_unfilt = 0.0f; acc_nrg_filt = 0.0f; for (i = 0; i < win_len; i++) { tmp_nrg_unfilt = ptr_time_signal[(win_len * w + i) * ch_increment]; tmp_nrg_filt = iaace_blk_switch_iir_filt(tmp_nrg_unfilt, iaace_iir_hipass_coeffs, pstr_blk_switch_ctrl->iir_states); acc_nrg_unfilt += (tmp_nrg_unfilt * tmp_nrg_unfilt); acc_nrg_filt += (tmp_nrg_filt * tmp_nrg_filt); } pstr_blk_switch_ctrl->win_energy[1][w] = acc_nrg_unfilt; pstr_blk_switch_ctrl->win_energy_filt[1][w] = acc_nrg_filt; } } VOID iaace_block_switching(ixheaace_block_switch_control *pstr_blk_switch_ctrl, const FLOAT32 *ptr_time_signal, WORD32 frame_length, WORD32 num_chans) { WORD32 win_idx; FLOAT32 tmp_nrg_1, tmp_nrg_2; FLOAT32 prev_win_nrg, max_nrg; memset(pstr_blk_switch_ctrl->group_len, 0, TRANS_FAC * sizeof(pstr_blk_switch_ctrl->group_len[0])); pstr_blk_switch_ctrl->max_win_energy = iaace_search_max_with_idx(&pstr_blk_switch_ctrl->win_energy[0][BLK_SWITCH_WIN - 1], &pstr_blk_switch_ctrl->attack_idx, BLK_SWITCH_WIN); pstr_blk_switch_ctrl->attack_idx = pstr_blk_switch_ctrl->last_attack_idx; pstr_blk_switch_ctrl->total_groups_cnt = MAXIMUM_NO_OF_GROUPS; memcpy(pstr_blk_switch_ctrl->group_len, iaace_suggested_grouping_table[pstr_blk_switch_ctrl->attack_idx], MAXIMUM_NO_OF_GROUPS * sizeof(pstr_blk_switch_ctrl->group_len[0])); memcpy(pstr_blk_switch_ctrl->win_energy[0], pstr_blk_switch_ctrl->win_energy[1], BLK_SWITCH_WIN * sizeof(pstr_blk_switch_ctrl->win_energy[0][0])); memcpy(pstr_blk_switch_ctrl->win_energy_filt[0], pstr_blk_switch_ctrl->win_energy_filt[1], BLK_SWITCH_WIN * sizeof(pstr_blk_switch_ctrl->win_energy_filt[0][0])); iaace_calc_window_energy( pstr_blk_switch_ctrl, ptr_time_signal, num_chans, (frame_length == FRAME_LEN_960 ? FRAME_LEN_SHORT_120 : FRAME_LEN_SHORT_128)); pstr_blk_switch_ctrl->attack = FALSE; max_nrg = 0.0f; prev_win_nrg = pstr_blk_switch_ctrl->win_energy_filt[0][BLK_SWITCH_WIN - 1]; for (win_idx = 0; win_idx < BLK_SWITCH_WIN; win_idx++) { tmp_nrg_1 = iaace_fmult(ONE_MINUS_ACC_WINDOW_NRG_FAC, pstr_blk_switch_ctrl->acc_win_energy); tmp_nrg_2 = iaace_fmult(ACC_WINDOW_NRG_FAC, prev_win_nrg); pstr_blk_switch_ctrl->acc_win_energy = iaace_fadd(tmp_nrg_1, tmp_nrg_2); tmp_nrg_1 = iaace_fmult(pstr_blk_switch_ctrl->win_energy_filt[1][win_idx], pstr_blk_switch_ctrl->inv_attack_ratio); if (tmp_nrg_1 > pstr_blk_switch_ctrl->acc_win_energy) { pstr_blk_switch_ctrl->attack = TRUE; pstr_blk_switch_ctrl->last_attack_idx = win_idx; } prev_win_nrg = pstr_blk_switch_ctrl->win_energy_filt[1][win_idx]; max_nrg = MAX(prev_win_nrg, max_nrg); } if (max_nrg < MIN_ATTACK_NRG) { pstr_blk_switch_ctrl->attack = FALSE; } if ((!pstr_blk_switch_ctrl->attack) && (pstr_blk_switch_ctrl->lastattack)) { if (pstr_blk_switch_ctrl->attack_idx == (TRANS_FAC - 1)) { pstr_blk_switch_ctrl->attack = TRUE; } pstr_blk_switch_ctrl->lastattack = FALSE; } else { pstr_blk_switch_ctrl->lastattack = pstr_blk_switch_ctrl->attack; } pstr_blk_switch_ctrl->win_seq = pstr_blk_switch_ctrl->nxt_win_seq; pstr_blk_switch_ctrl->nxt_win_seq = (pstr_blk_switch_ctrl->attack == 1) ? SHORT_WINDOW : LONG_WINDOW; if (pstr_blk_switch_ctrl->nxt_win_seq == SHORT_WINDOW) { if (pstr_blk_switch_ctrl->win_seq == LONG_WINDOW) { pstr_blk_switch_ctrl->win_seq = START_WINDOW; } else if (pstr_blk_switch_ctrl->win_seq == STOP_WINDOW) { pstr_blk_switch_ctrl->win_seq = SHORT_WINDOW; pstr_blk_switch_ctrl->total_groups_cnt = 3; pstr_blk_switch_ctrl->group_len[0] = 3; pstr_blk_switch_ctrl->group_len[1] = 3; pstr_blk_switch_ctrl->group_len[2] = 2; } } if (pstr_blk_switch_ctrl->nxt_win_seq == LONG_WINDOW && pstr_blk_switch_ctrl->win_seq == SHORT_WINDOW) { pstr_blk_switch_ctrl->nxt_win_seq = STOP_WINDOW; } } VOID iaace_sync_block_switching(ixheaace_block_switch_control *pstr_blk_switch_left_ctrl, ixheaace_block_switch_control *pstr_blk_switch_right_ctrl, const WORD32 num_channels) { WORD32 i; WORD32 patch_type = LONG_WINDOW; if (num_channels == 1) { if (pstr_blk_switch_left_ctrl->win_seq != SHORT_WINDOW) { pstr_blk_switch_left_ctrl->total_groups_cnt = 1; pstr_blk_switch_left_ctrl->group_len[0] = 1; for (i = 1; i < TRANS_FAC; i++) { pstr_blk_switch_left_ctrl->group_len[i] = 0; } } } else { /* Stereo */ patch_type = iaace_synchronized_block_types[patch_type][pstr_blk_switch_left_ctrl->win_seq]; patch_type = iaace_synchronized_block_types[patch_type][pstr_blk_switch_right_ctrl->win_seq]; pstr_blk_switch_left_ctrl->win_seq = patch_type; pstr_blk_switch_right_ctrl->win_seq = patch_type; if (patch_type != SHORT_WINDOW) { /* tns_data_long Blocks */ pstr_blk_switch_left_ctrl->total_groups_cnt = 1; pstr_blk_switch_right_ctrl->total_groups_cnt = 1; pstr_blk_switch_left_ctrl->group_len[0] = 1; pstr_blk_switch_right_ctrl->group_len[0] = 1; for (i = 1; i < TRANS_FAC; i++) { pstr_blk_switch_left_ctrl->group_len[i] = 0; pstr_blk_switch_right_ctrl->group_len[i] = 0; } } else { /* tns_data_short Blocks */ if (pstr_blk_switch_left_ctrl->max_win_energy > pstr_blk_switch_right_ctrl->max_win_energy) { pstr_blk_switch_right_ctrl->total_groups_cnt = pstr_blk_switch_left_ctrl->total_groups_cnt; for (i = 0; i < TRANS_FAC; i++) { pstr_blk_switch_right_ctrl->group_len[i] = pstr_blk_switch_left_ctrl->group_len[i]; } } else { pstr_blk_switch_left_ctrl->total_groups_cnt = pstr_blk_switch_right_ctrl->total_groups_cnt; for (i = 0; i < TRANS_FAC; i++) { pstr_blk_switch_left_ctrl->group_len[i] = pstr_blk_switch_right_ctrl->group_len[i]; } } } } }