| /****************************************************************************** |
| * * |
| * 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 "iusace_type_def.h" |
| #include "ixheaace_mps_common_define.h" |
| #include "iusace_cnst.h" |
| #include "iusace_block_switch_const.h" |
| #include "iusace_block_switch_struct_def.h" |
| #include "iusace_rom.h" |
| |
| static FLOAT32 iusace_fmult(FLOAT32 a, FLOAT32 b) { return (a * b); } |
| |
| static FLOAT32 iusace_fadd(FLOAT32 a, FLOAT32 b) { return (a + b); } |
| |
| VOID iusace_init_block_switching(ia_block_switch_ctrl *pstr_blk_switch_ctrl, |
| const WORD32 bit_rate, const WORD32 num_chans) { |
| WORD32 i, w; |
| |
| if ((num_chans == 1 && bit_rate > 24000) || (num_chans > 1 && bit_rate / num_chans > 16000)) { |
| 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; |
| } |
| |
| for (i = 0; i < BLK_SWITCH_FILT_LEN; i++) { |
| pstr_blk_switch_ctrl->iir_states[i] = 0; |
| } |
| |
| /* Clear Filtered Window Energies */ |
| for (w = 0; w < MAX_SHORT_WINDOWS; w++) { |
| pstr_blk_switch_ctrl->win_energy_filt[0][w] = 0; |
| pstr_blk_switch_ctrl->win_energy_filt[1][w] = 0; |
| pstr_blk_switch_ctrl->win_energy[0][w] = 0; |
| pstr_blk_switch_ctrl->win_energy[1][w] = 0; |
| } |
| pstr_blk_switch_ctrl->acc_win_energy = 0; |
| |
| pstr_blk_switch_ctrl->window_seq = ONLY_LONG_SEQUENCE; |
| pstr_blk_switch_ctrl->next_win_seq = ONLY_LONG_SEQUENCE; |
| |
| 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; |
| |
| return; |
| } |
| |
| static FLOAT32 iusace_srch_max_with_idx(const FLOAT32 *ptr_in, WORD32 *index) { |
| FLOAT32 max; |
| WORD32 i, idx; |
| |
| max = 0; |
| idx = 0; |
| |
| for (i = 0; i < MAX_SHORT_WINDOWS; i++) { |
| if (ptr_in[i + 1] > max) { |
| max = ptr_in[i + 1]; |
| idx = i; |
| } |
| } |
| *index = idx; |
| |
| return max; |
| } |
| |
| static VOID iusace_blk_switch_iir_filt(const FLOAT32 *ptr_in, const FLOAT32 *ptr_iir_coeff, |
| const WORD32 w, FLOAT32 *ptr_iir_states, |
| FLOAT32 *energy_accu, WORD32 block_len) { |
| FLOAT32 accu1; |
| |
| WORD32 i; |
| |
| FLOAT32 accu_unfilt = 0.0f; |
| FLOAT32 accu_filt = 0.0f; |
| FLOAT32 accu2, temp2, temp1; |
| |
| FLOAT32 state0 = ptr_iir_states[0]; |
| FLOAT32 state1 = ptr_iir_states[1]; |
| |
| FLOAT32 coeff0 = ptr_iir_coeff[0]; |
| FLOAT32 coeff1 = ptr_iir_coeff[1]; |
| |
| const FLOAT32 *p_time_signal = &ptr_in[(block_len * w)]; |
| |
| for (i = 0; i < block_len; i++) { |
| accu2 = iusace_fmult(state0, coeff1); |
| accu1 = iusace_fmult(state1, coeff0); |
| accu1 += accu2; |
| |
| state0 = p_time_signal[i]; |
| state1 = iusace_fmult(state0, coeff1); |
| state1 = (state1 - accu1); |
| |
| temp1 = iusace_fmult(state0, state0); |
| temp2 = iusace_fmult(state1, state1); |
| |
| accu_unfilt = iusace_fadd(accu_unfilt, temp1); |
| accu_filt = iusace_fadd(accu_filt, temp2); |
| } |
| |
| energy_accu[0] = accu_unfilt; |
| energy_accu[1] = accu_filt; |
| |
| ptr_iir_states[0] = state0; |
| ptr_iir_states[1] = state1; |
| |
| return; |
| } |
| |
| static VOID iusace_calc_window_energy(ia_block_switch_ctrl *ptr_blk_switch_ctrl, |
| const FLOAT32 *ptr_in, FLOAT32 *max, WORD32 ccfl) { |
| WORD32 w; |
| |
| FLOAT32 energy_accu[2]; |
| *max = 0.0f; |
| |
| for (w = 0; w < MAX_SHORT_WINDOWS; w++) { |
| // block length for calculating energy is corecoder frame length / MAX_SHORT_WINDOWS |
| iusace_blk_switch_iir_filt(ptr_in, iusace_iir_hipass_coeffs, w, |
| ptr_blk_switch_ctrl->iir_states, &energy_accu[0], ccfl >> 3); |
| |
| ptr_blk_switch_ctrl->win_energy[1][w] = energy_accu[0]; |
| ptr_blk_switch_ctrl->win_energy_filt[1][w] = energy_accu[1]; |
| |
| if (ptr_blk_switch_ctrl->win_energy_filt[1][w] > *max) |
| *max = ptr_blk_switch_ctrl->win_energy_filt[1][w]; |
| } |
| return; |
| } |
| |
| VOID iusace_block_switching(ia_block_switch_ctrl *ptr_blk_switch_ctrl, const FLOAT32 *ptr_in, |
| WORD32 ccfl) { |
| WORD32 i; |
| |
| FLOAT32 temp1, temp2; |
| FLOAT32 max; |
| FLOAT32 energy, energy_max; |
| |
| for (i = 0; i < MAX_SHORT_WINDOWS; i++) { |
| ptr_blk_switch_ctrl->group_len[i] = 0; |
| } |
| |
| ptr_blk_switch_ctrl->max_win_energy = |
| iusace_srch_max_with_idx(&ptr_blk_switch_ctrl->win_energy[0][MAX_SHORT_WINDOWS - 1], |
| &ptr_blk_switch_ctrl->attack_idx); |
| |
| ptr_blk_switch_ctrl->attack_idx = ptr_blk_switch_ctrl->last_attack_idx; |
| ptr_blk_switch_ctrl->tot_grps_cnt = MAXIMUM_NO_OF_GROUPS; |
| |
| for (i = 0; i < MAXIMUM_NO_OF_GROUPS; i++) { |
| ptr_blk_switch_ctrl->group_len[i] = |
| iusace_suggested_grouping_table[ptr_blk_switch_ctrl->attack_idx][i]; |
| } |
| |
| for (i = 0; i < MAX_SHORT_WINDOWS; i++) { |
| ptr_blk_switch_ctrl->win_energy[0][i] = ptr_blk_switch_ctrl->win_energy[1][i]; |
| ptr_blk_switch_ctrl->win_energy_filt[0][i] = ptr_blk_switch_ctrl->win_energy_filt[1][i]; |
| } |
| |
| iusace_calc_window_energy(ptr_blk_switch_ctrl, ptr_in, &max, ccfl); |
| |
| ptr_blk_switch_ctrl->attack = FALSE; |
| |
| energy_max = 0.0f; |
| |
| energy = ptr_blk_switch_ctrl->win_energy_filt[0][MAX_SHORT_WINDOWS - 1]; |
| |
| for (i = 0; i < MAX_SHORT_WINDOWS; i++) { |
| temp1 = iusace_fmult(ONE_MINUS_ACC_WINDOW_NRG_FAC, ptr_blk_switch_ctrl->acc_win_energy); |
| temp2 = iusace_fmult(ACC_WINDOW_NRG_FAC, energy); |
| ptr_blk_switch_ctrl->acc_win_energy = iusace_fadd(temp1, temp2); |
| |
| temp1 = iusace_fmult(ptr_blk_switch_ctrl->win_energy_filt[1][i], |
| ptr_blk_switch_ctrl->inv_attack_ratio); |
| if (temp1 > ptr_blk_switch_ctrl->acc_win_energy) { |
| ptr_blk_switch_ctrl->attack = TRUE; |
| ptr_blk_switch_ctrl->last_attack_idx = i; |
| } |
| |
| energy = ptr_blk_switch_ctrl->win_energy_filt[1][i]; |
| if (energy_max < energy) energy_max = energy; |
| } |
| |
| if (ccfl == LEN_SUPERFRAME_768) { |
| energy_max = (energy_max * 4) / 3.0f; |
| } |
| if (energy_max < USAC_MIN_ATTACK_NRG) { |
| ptr_blk_switch_ctrl->attack = FALSE; |
| } |
| |
| if ((!ptr_blk_switch_ctrl->attack) && (ptr_blk_switch_ctrl->lastattack)) { |
| if (ptr_blk_switch_ctrl->attack_idx == MAX_SHORT_WINDOWS - 1) { |
| ptr_blk_switch_ctrl->attack = TRUE; |
| } |
| ptr_blk_switch_ctrl->lastattack = FALSE; |
| } else { |
| ptr_blk_switch_ctrl->lastattack = ptr_blk_switch_ctrl->attack; |
| } |
| ptr_blk_switch_ctrl->window_seq = ptr_blk_switch_ctrl->next_win_seq; |
| |
| if (ptr_blk_switch_ctrl->attack) { |
| ptr_blk_switch_ctrl->next_win_seq = EIGHT_SHORT_SEQUENCE; |
| } else { |
| ptr_blk_switch_ctrl->next_win_seq = ONLY_LONG_SEQUENCE; |
| } |
| if (ptr_blk_switch_ctrl->next_win_seq == EIGHT_SHORT_SEQUENCE) { |
| if (ptr_blk_switch_ctrl->window_seq == ONLY_LONG_SEQUENCE) { |
| ptr_blk_switch_ctrl->window_seq = LONG_START_SEQUENCE; |
| } |
| |
| if (ptr_blk_switch_ctrl->window_seq == LONG_STOP_SEQUENCE) { |
| ptr_blk_switch_ctrl->window_seq = EIGHT_SHORT_SEQUENCE; |
| ptr_blk_switch_ctrl->tot_grps_cnt = 3; |
| ptr_blk_switch_ctrl->group_len[0] = 3; |
| ptr_blk_switch_ctrl->group_len[1] = 3; |
| ptr_blk_switch_ctrl->group_len[2] = 2; |
| } |
| } |
| |
| if (ptr_blk_switch_ctrl->next_win_seq == ONLY_LONG_SEQUENCE) { |
| if (ptr_blk_switch_ctrl->window_seq == EIGHT_SHORT_SEQUENCE) { |
| ptr_blk_switch_ctrl->next_win_seq = LONG_STOP_SEQUENCE; |
| } |
| } |
| return; |
| } |
| |
| VOID iusace_sync_block_switching(ia_block_switch_ctrl *ptr_blk_switch_left_ctrl, |
| ia_block_switch_ctrl *ptr_blk_switch_right_ctrl) { |
| WORD32 i; |
| WORD32 patch_type = ONLY_LONG_SEQUENCE; |
| |
| patch_type = iusace_synchronized_block_types[patch_type][ptr_blk_switch_left_ctrl->window_seq]; |
| patch_type = iusace_synchronized_block_types[patch_type][ptr_blk_switch_right_ctrl->window_seq]; |
| |
| ptr_blk_switch_left_ctrl->window_seq = patch_type; |
| ptr_blk_switch_right_ctrl->window_seq = patch_type; |
| |
| if (patch_type != EIGHT_SHORT_SEQUENCE) { /* tns_data_long Blocks */ |
| ptr_blk_switch_left_ctrl->tot_grps_cnt = 1; |
| ptr_blk_switch_right_ctrl->tot_grps_cnt = 1; |
| ptr_blk_switch_left_ctrl->group_len[0] = 1; |
| ptr_blk_switch_right_ctrl->group_len[0] = 1; |
| |
| for (i = 1; i < MAX_SHORT_WINDOWS; i++) { |
| ptr_blk_switch_left_ctrl->group_len[i] = 0; |
| ptr_blk_switch_right_ctrl->group_len[i] = 0; |
| } |
| } else { /* tns_data_short Blocks */ |
| if (ptr_blk_switch_left_ctrl->max_win_energy > ptr_blk_switch_right_ctrl->max_win_energy) { |
| ptr_blk_switch_right_ctrl->tot_grps_cnt = ptr_blk_switch_left_ctrl->tot_grps_cnt; |
| for (i = 0; i < ptr_blk_switch_right_ctrl->tot_grps_cnt; i++) { |
| ptr_blk_switch_right_ctrl->group_len[i] = ptr_blk_switch_left_ctrl->group_len[i]; |
| } |
| } else { |
| ptr_blk_switch_left_ctrl->tot_grps_cnt = ptr_blk_switch_right_ctrl->tot_grps_cnt; |
| for (i = 0; i < ptr_blk_switch_left_ctrl->tot_grps_cnt; i++) { |
| ptr_blk_switch_left_ctrl->group_len[i] = ptr_blk_switch_right_ctrl->group_len[i]; |
| } |
| } |
| } |
| |
| return; |
| } |