/****************************************************************************** * * * Copyright (C) 2018 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 "ixheaacd_sbr_common.h" #include #include "ixheaacd_constants.h" #include #include #include #include "ixheaacd_basic_ops.h" #include #include "ixheaacd_intrinsics.h" #include "ixheaacd_common_rom.h" #include "ixheaacd_basic_funcs.h" #include "ixheaacd_sbr_scale.h" #include "ixheaacd_sbrdecsettings.h" #include "ixheaacd_lpp_tran.h" #include "ixheaacd_bitbuffer.h" #include "ixheaacd_defines.h" #include "ixheaacd_pns.h" #include #include "ixheaacd_pulsedata.h" #include "ixheaacd_drc_data_struct.h" #include "ixheaacd_lt_predict.h" #include "ixheaacd_channelinfo.h" #include "ixheaacd_drc_dec.h" #include "ixheaacd_sbrdecoder.h" #include "ixheaacd_sbr_scale.h" #include "ixheaacd_lpp_tran.h" #include "ixheaacd_env_extr_part.h" #include #include "ixheaacd_hybrid.h" #include "ixheaacd_ps_dec.h" #include "ixheaacd_env_extr.h" #include "ixheaacd_intrinsics.h" #include "ixheaacd_basic_funcs.h" #include "ixheaacd_qmf_dec.h" #include "ixheaacd_env_calc.h" #include "ixheaacd_sbr_const.h" #include "ixheaacd_pvc_dec.h" #include "ixheaacd_sbr_dec.h" #include "ixheaacd_function_selector.h" #include "ixheaacd_audioobjtypes.h" #define LPC_SCALE_FACTOR 2 #define SHIFT 5 static PLATFORM_INLINE WORD32 ixheaacd_mult32x16hin32(WORD32 a, WORD32 b) { WORD32 result; WORD64 temp_result; temp_result = (WORD64)(a) * (WORD64)(b >> 16); result = (WORD32)(temp_result >> 16); return (result); } static PLATFORM_INLINE WORD32 ixheaacd_mac32x16hin32(WORD32 a, WORD32 b, WORD32 c) { WORD32 result; result = a + ixheaacd_mult32x16hin32(b, c); return (result); } static PLATFORM_INLINE WORD32 ixheaacd_macn32x16hin32(WORD32 a, WORD32 b, WORD32 c) { WORD32 result; result = a - ixheaacd_mult32x16hin32(b, c); return (result); } VOID ixheaacd_filterstep3(WORD16 a0r, WORD16 a0i, WORD16 a1r, WORD16 a1i, WORD32 start_indx, WORD32 stop_idx, WORD32 low_band, WORD32 high_band, WORD32 *qmf_buffer) { WORD32 i; WORD32 prev1r, prev1i; WORD32 prev2r, prev2i; WORD16 coef1r = (a0r); WORD16 coef1i = (a0i); WORD16 coef2r = (a1r); WORD16 coef2i = (a1i); WORD32 *p_src, *p_dst; WORD32 qmf_real, qmf_imag; WORD32 curr, curi; p_src = qmf_buffer + low_band + ((start_indx) << 7); prev2r = *p_src; p_src += 64; prev2i = *p_src; p_src += 64; prev1r = *p_src; p_src += 64; prev1i = *p_src; p_src += 64; p_dst = qmf_buffer + high_band + ((start_indx + 2) << 7); for (i = stop_idx - start_indx; i != 0; i--) { WORD32 accu; curr = *p_src; p_src += 64; curi = *p_src; p_src += 64; qmf_real = (curr >> LPC_SCALE_FACTOR); qmf_imag = (curi >> LPC_SCALE_FACTOR); accu = ixheaacd_sub32( ixheaacd_add32(ixheaacd_sub32(ixheaacd_mult32x16in32(prev1r, coef1r), ixheaacd_mult32x16in32(prev1i, coef1i)), ixheaacd_mult32x16in32(prev2r, coef2r)), ixheaacd_mult32x16in32(prev2i, coef2i)); *p_dst = ixheaacd_add32(qmf_real, (accu << 1)); p_dst += 64; accu = ixheaacd_add32( ixheaacd_add32_sat( ixheaacd_add32_sat(ixheaacd_mult32x16in32(prev1r, coef1i), ixheaacd_mult32x16in32(prev1i, coef1r)), ixheaacd_mult32x16in32(prev2r, coef2i)), ixheaacd_mult32x16in32(prev2i, coef2r)); *p_dst = ixheaacd_add32(qmf_imag, (accu << 1)); p_dst += 64; prev2r = prev1r; prev1r = curr; prev2i = prev1i; prev1i = curi; } } VOID ixheaacd_covariance_matrix_calc_dec( WORD32 *sub_sign_xlow, ixheaacd_lpp_trans_cov_matrix *cov_matrix, WORD32 count) { WORD32 j, k; WORD32 ixheaacd_drc_offset = 2; WORD32 len = 38; WORD32 factor; WORD32 max_val, q_factor; WORD32 temp1, temp2, temp3, temp4; WORD32 *temp_buf_ptr = sub_sign_xlow; for (k = count; k > 0; k--) { WORD32 t_phi_01 = 0, t_phi_02 = 0, t_phi_11 = 0; WORD32 t_phi_12 = 0, t_phi_22 = 0; factor = -3; j = ixheaacd_drc_offset; sub_sign_xlow = temp_buf_ptr; temp1 = ixheaacd_shl32_dir(*sub_sign_xlow, factor); sub_sign_xlow += 64; temp2 = ixheaacd_shl32_dir(*sub_sign_xlow, factor); sub_sign_xlow += 64; for (; (j = j + 3) < ixheaacd_drc_offset + len;) { temp3 = ixheaacd_shl32_dir(*sub_sign_xlow, factor); sub_sign_xlow += 64; t_phi_01 += ixheaacd_mult32x16hin32(temp3, temp2); t_phi_02 += ixheaacd_mult32x16hin32(temp3, temp1); t_phi_11 += ixheaacd_mult32x16hin32(temp2, temp2); temp1 = ixheaacd_shl32_dir(*sub_sign_xlow, factor); sub_sign_xlow += 64; t_phi_01 += ixheaacd_mult32x16hin32(temp1, temp3); t_phi_02 += ixheaacd_mult32x16hin32(temp1, temp2); t_phi_11 += ixheaacd_mult32x16hin32(temp3, temp3); temp2 = ixheaacd_shl32_dir(*sub_sign_xlow, factor); sub_sign_xlow += 64; t_phi_01 += ixheaacd_mult32x16hin32(temp2, temp1); t_phi_02 += ixheaacd_mult32x16hin32(temp2, temp3); t_phi_11 += ixheaacd_mult32x16hin32(temp1, temp1); } temp3 = ixheaacd_shl32_dir(*sub_sign_xlow, factor); sub_sign_xlow += 64; t_phi_01 += ixheaacd_mult32x16hin32(temp3, temp2); t_phi_02 += ixheaacd_mult32x16hin32(temp3, temp1); t_phi_11 += ixheaacd_mult32x16hin32(temp2, temp2); temp1 = ixheaacd_shl32_dir(*sub_sign_xlow, factor); sub_sign_xlow += 64; t_phi_01 += ixheaacd_mult32x16hin32(temp1, temp3); t_phi_02 += ixheaacd_mult32x16hin32(temp1, temp2); t_phi_11 += ixheaacd_mult32x16hin32(temp3, temp3); temp2 = ixheaacd_shl32_dir(*temp_buf_ptr, factor); temp4 = ixheaacd_shl32_dir(*(temp_buf_ptr + 64), factor); t_phi_12 = (t_phi_01 - ixheaacd_mult32x16hin32(temp1, temp3) + ixheaacd_mult32x16hin32(temp4, temp2)); t_phi_22 = (t_phi_11 - ixheaacd_mult32x16hin32(temp3, temp3) + ixheaacd_mult32x16hin32(temp2, temp2)); max_val = ixheaacd_abs32_nrm(t_phi_01); max_val = max_val | ixheaacd_abs32_nrm(t_phi_02); max_val = max_val | ixheaacd_abs32_nrm(t_phi_12); max_val = max_val | (t_phi_11); max_val = max_val | (t_phi_22); q_factor = ixheaacd_pnorm32(max_val); cov_matrix->phi_11 = (t_phi_11 << q_factor); cov_matrix->phi_22 = (t_phi_22 << q_factor); cov_matrix->phi_01 = (t_phi_01 << q_factor); cov_matrix->phi_02 = (t_phi_02 << q_factor); cov_matrix->phi_12 = (t_phi_12 << q_factor); cov_matrix->d = ixheaacd_sub32_sat( ixheaacd_mult32(cov_matrix->phi_22, cov_matrix->phi_11), ixheaacd_mult32(cov_matrix->phi_12, cov_matrix->phi_12)); cov_matrix++; temp_buf_ptr++; } return; } VOID ixheaacd_covariance_matrix_calc_2_dec( ixheaacd_lpp_trans_cov_matrix *cov_matrix, WORD32 *real_buffer, WORD32 num_bands, WORD16 slots) { WORD32 k; WORD32 *img_buffer; WORD32 *ptr_real = real_buffer; ixheaacd_lpp_trans_cov_matrix *pac_arr = cov_matrix; for (k = 0; k < num_bands; k++) { WORD32 t_phi_11 = 0, t_phi_01 = 0, t_phi_01_i = 0; WORD32 prev_real, prev_imag, curr_real, curr_imag; real_buffer = ptr_real; img_buffer = real_buffer + 64; cov_matrix = pac_arr; prev_real = real_buffer[-128]; prev_imag = img_buffer[-128]; curr_real = real_buffer[0]; curr_imag = img_buffer[0]; curr_real = ixheaacd_shr32(curr_real, 3); curr_imag = ixheaacd_shr32(curr_imag, 3); prev_real = ixheaacd_shr32(prev_real, 3); prev_imag = ixheaacd_shr32(prev_imag, 3); t_phi_01 = ixheaacd_mult32x16hin32(curr_real, prev_real); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, curr_imag, prev_imag); t_phi_01_i = ixheaacd_mult32x16hin32(curr_imag, prev_real); t_phi_01_i = ixheaacd_macn32x16hin32(t_phi_01_i, curr_real, prev_imag); t_phi_11 = ixheaacd_mult32x16hin32(prev_real, prev_real); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, prev_imag, prev_imag); { WORD n; WORD32 *real1 = &real_buffer[128]; WORD32 *imag1 = &img_buffer[128]; prev_real = curr_real; prev_imag = curr_imag; for (n = ((slots - 2) >> 1); n; n--) { curr_real = *real1; real1 += 128; curr_imag = *imag1; imag1 += 128; curr_real = ixheaacd_shr32(curr_real, 3); curr_imag = ixheaacd_shr32(curr_imag, 3); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, curr_real, prev_real); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, curr_imag, prev_imag); t_phi_01_i = ixheaacd_mac32x16hin32(t_phi_01_i, curr_imag, prev_real); t_phi_01_i = ixheaacd_macn32x16hin32(t_phi_01_i, curr_real, prev_imag); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, prev_real, prev_real); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, prev_imag, prev_imag); prev_real = *real1; real1 += 128; prev_imag = *imag1; imag1 += 128; prev_real = ixheaacd_shr32(prev_real, 3); prev_imag = ixheaacd_shr32(prev_imag, 3); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, prev_real, curr_real); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, prev_imag, curr_imag); t_phi_01_i = ixheaacd_mac32x16hin32(t_phi_01_i, prev_imag, curr_real); t_phi_01_i = ixheaacd_macn32x16hin32(t_phi_01_i, prev_real, curr_imag); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, curr_real, curr_real); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, curr_imag, curr_imag); } if (slots & 0x01) { curr_real = *real1; curr_imag = *imag1; curr_real = ixheaacd_shr32(curr_real, 3); curr_imag = ixheaacd_shr32(curr_imag, 3); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, curr_real, prev_real); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, curr_imag, prev_imag); t_phi_01_i = ixheaacd_mac32x16hin32(t_phi_01_i, curr_imag, prev_real); t_phi_01_i = ixheaacd_macn32x16hin32(t_phi_01_i, curr_real, prev_imag); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, prev_real, prev_real); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, prev_imag, prev_imag); } } { WORD32 t_phi_22 = t_phi_11; WORD32 curr_real = real_buffer[-2 * 128]; WORD32 curr_imag = img_buffer[-2 * 128]; curr_real = ixheaacd_shr32(curr_real, 3); curr_imag = ixheaacd_shr32(curr_imag, 3); t_phi_22 = ixheaacd_mac32x16hin32(t_phi_22, curr_real, curr_real); t_phi_22 = ixheaacd_mac32x16hin32(t_phi_22, curr_imag, curr_imag); curr_real = real_buffer[(slots - 2) * 128]; curr_imag = img_buffer[(slots - 2) * 128]; curr_real = ixheaacd_shr32(curr_real, 3); curr_imag = ixheaacd_shr32(curr_imag, 3); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, curr_real, curr_real); t_phi_11 = ixheaacd_mac32x16hin32(t_phi_11, curr_imag, curr_imag); cov_matrix->phi_11 = t_phi_11; cov_matrix->phi_22 = t_phi_22; } { WORD32 t_phi_12 = t_phi_01; t_phi_12 = ixheaacd_mac32x16hin32(t_phi_12, real_buffer[-128] >> 3, real_buffer[-2 * 128] >> 3); t_phi_12 = ixheaacd_mac32x16hin32(t_phi_12, img_buffer[-128] >> 3, img_buffer[-2 * 128] >> 3); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, real_buffer[(slots - 1) * 128] >> 3, real_buffer[(slots - 2) * 128] >> 3); t_phi_01 = ixheaacd_mac32x16hin32(t_phi_01, img_buffer[(slots - 1) * 128] >> 3, img_buffer[(slots - 2) * 128] >> 3); cov_matrix->phi_01 = t_phi_01; cov_matrix->phi_12 = t_phi_12; } { WORD32 t_phi_12_i = t_phi_01_i; t_phi_12_i = ixheaacd_mac32x16hin32(t_phi_12_i, img_buffer[-128] >> 3, real_buffer[-2 * 128] >> 3); t_phi_12_i = ixheaacd_macn32x16hin32(t_phi_12_i, real_buffer[-128] >> 3, img_buffer[-2 * 128] >> 3); t_phi_01_i = ixheaacd_mac32x16hin32(t_phi_01_i, img_buffer[(slots - 1) * 128] >> 3, real_buffer[(slots - 2) * 128] >> 3); t_phi_01_i = ixheaacd_macn32x16hin32(t_phi_01_i, real_buffer[(slots - 1) * 128] >> 3, img_buffer[(slots - 2) * 128] >> 3); cov_matrix->phi_01_im = t_phi_01_i; cov_matrix->phi_12_im = t_phi_12_i; } { WORD16 n, len_by_4, p; WORD32 t_phi_02 = 0x00, t_phi_02_i = 0x00; len_by_4 = (slots >> 2); p = 0; for (n = 0; n < len_by_4; n++) { WORD32 real1, real2, imag1, imag2; real1 = real_buffer[p * 128]; real2 = real_buffer[(p - 2) * 128]; imag1 = img_buffer[p * 128]; imag2 = img_buffer[(p - 2) * 128]; real1 = ixheaacd_shr32(real1, 3); real2 = ixheaacd_shr32(real2, 3); imag1 = ixheaacd_shr32(imag1, 3); imag2 = ixheaacd_shr32(imag2, 3); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, real1, real2); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, imag1, imag2); t_phi_02_i = ixheaacd_mac32x16hin32(t_phi_02_i, imag1, real2); t_phi_02_i = ixheaacd_macn32x16hin32(t_phi_02_i, real1, imag2); real1 = real_buffer[(p + 1) * 128]; real2 = real_buffer[(p - 1) * 128]; imag1 = img_buffer[(p + 1) * 128]; imag2 = img_buffer[(p - 1) * 128]; real1 = ixheaacd_shr32(real1, 3); real2 = ixheaacd_shr32(real2, 3); imag1 = ixheaacd_shr32(imag1, 3); imag2 = ixheaacd_shr32(imag2, 3); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, real1, real2); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, imag1, imag2); t_phi_02_i = ixheaacd_mac32x16hin32(t_phi_02_i, imag1, real2); t_phi_02_i = ixheaacd_macn32x16hin32(t_phi_02_i, real1, imag2); real1 = real_buffer[(p + 2) * 128]; real2 = real_buffer[p * 128]; imag1 = img_buffer[(p + 2) * 128]; imag2 = img_buffer[p * 128]; real1 = ixheaacd_shr32(real1, 3); real2 = ixheaacd_shr32(real2, 3); imag1 = ixheaacd_shr32(imag1, 3); imag2 = ixheaacd_shr32(imag2, 3); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, real1, real2); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, imag1, imag2); t_phi_02_i = ixheaacd_mac32x16hin32(t_phi_02_i, imag1, real2); t_phi_02_i = ixheaacd_macn32x16hin32(t_phi_02_i, real1, imag2); real1 = real_buffer[(p + 3) * 128]; real2 = real_buffer[(p + 1) * 128]; imag1 = img_buffer[(p + 3) * 128]; imag2 = img_buffer[(p + 1) * 128]; real1 = ixheaacd_shr32(real1, 3); real2 = ixheaacd_shr32(real2, 3); imag1 = ixheaacd_shr32(imag1, 3); imag2 = ixheaacd_shr32(imag2, 3); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, real1, real2); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, imag1, imag2); t_phi_02_i = ixheaacd_mac32x16hin32(t_phi_02_i, imag1, real2); t_phi_02_i = ixheaacd_macn32x16hin32(t_phi_02_i, real1, imag2); p += 4; } n = ixheaacd_shl16(len_by_4, 2); for (; n < slots; n++) { WORD32 real1, real2, imag1, imag2; real1 = real_buffer[(n * 128)]; real2 = real_buffer[(n - 2) * 128]; imag1 = img_buffer[n * 128]; imag2 = img_buffer[(n - 2) * 128]; real1 = ixheaacd_shr32(real1, 3); real2 = ixheaacd_shr32(real2, 3); imag1 = ixheaacd_shr32(imag1, 3); imag2 = ixheaacd_shr32(imag2, 3); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, real1, real2); t_phi_02 = ixheaacd_mac32x16hin32(t_phi_02, imag1, imag2); t_phi_02_i = ixheaacd_mac32x16hin32(t_phi_02_i, imag1, real2); t_phi_02_i = ixheaacd_macn32x16hin32(t_phi_02_i, real1, imag2); } cov_matrix->phi_02 = t_phi_02; cov_matrix->phi_02_im = t_phi_02_i; } ptr_real++; pac_arr++; } } static PLATFORM_INLINE VOID ixheaacd_filt_step3_lp(WORD len, WORD32 coef1, WORD32 coef2, WORD32 *pqmf_real_low, WORD32 *pqmf_real_high) { WORD32 prev1; WORD32 prev2; WORD32 i; prev2 = *pqmf_real_low; pqmf_real_low += 64; prev1 = *pqmf_real_low; pqmf_real_low += 64; for (i = len; i >= 0; i -= 2) { WORD32 curr = *pqmf_real_low; WORD32 temp = ixheaacd_mult32x16hin32(prev2, coef2); pqmf_real_low += 64; *pqmf_real_high = ixheaacd_add32((curr >> LPC_SCALE_FACTOR), ((ixheaacd_mac32x16hin32(temp, prev1, coef1)) << 1)); pqmf_real_high += 64; prev2 = *pqmf_real_low; temp = ixheaacd_mult32x16hin32(prev1, coef2); pqmf_real_low += 64; *pqmf_real_high = ixheaacd_add32((prev2 >> LPC_SCALE_FACTOR), ((ixheaacd_mac32x16hin32(temp, curr, coef1)) << 1)); pqmf_real_high += 64; prev1 = prev2; prev2 = curr; } } VOID ixheaacd_filter1_lp(ia_sbr_hf_generator_struct *hf_generator, ixheaacd_lpp_trans_cov_matrix *cov_matrix_seq, WORD32 *bw_array, WORD16 *degree_alias, WORD32 start_idx, WORD32 stop_idx, WORD32 max_qmf_subband, WORD32 start_patch, WORD32 stop_patch, WORD32 *sub_sig_x) { WORD16 k1, k1_below = 0, k1_below2 = 0; WORD32 i; WORD16 alpha_real[LPC_ORDER]; WORD32 low_band, high_band; WORD32 patch; WORD16 bw = 0; WORD32 a0r, a1r; WORD num_patches = hf_generator->pstr_settings->num_patches; ia_patch_param_struct *patch_param = hf_generator->pstr_settings->str_patch_param; WORD32 bw_index[MAX_NUM_PATCHES]; memset(bw_index, 0, sizeof(WORD32) * num_patches); for (low_band = start_patch; low_band < stop_patch; low_band++) { ixheaacd_lpp_trans_cov_matrix *p_cov_matrix = &cov_matrix_seq[low_band]; alpha_real[1] = 0; alpha_real[0] = 0; if (p_cov_matrix->d != 0) { WORD32 tmp_r, temp_real, modulus_d; WORD16 inverse_d; WORD32 norm_d; norm_d = ixheaacd_norm32(p_cov_matrix->d); inverse_d = (WORD16)(*ixheaacd_fix_div)(0x40000000, (p_cov_matrix->d << norm_d)); modulus_d = ixheaacd_abs32(p_cov_matrix->d); tmp_r = (ixheaacd_sub32_sat( ixheaacd_mult32(p_cov_matrix->phi_01, p_cov_matrix->phi_12), ixheaacd_mult32(p_cov_matrix->phi_02, p_cov_matrix->phi_11)) >> LPC_SCALE_FACTOR); temp_real = ixheaacd_abs32(tmp_r); if (temp_real < modulus_d) { alpha_real[1] = (WORD16)( (ixheaacd_mult32x16in32_shl_sat(tmp_r, inverse_d) << norm_d) >> 15); } tmp_r = (ixheaacd_sub32_sat( ixheaacd_mult32(p_cov_matrix->phi_02, p_cov_matrix->phi_12), ixheaacd_mult32(p_cov_matrix->phi_01, p_cov_matrix->phi_22)) >> LPC_SCALE_FACTOR); temp_real = ixheaacd_abs32(tmp_r); if (temp_real < modulus_d) { alpha_real[0] = (WORD16)( (ixheaacd_mult32x16in32_shl_sat(tmp_r, inverse_d) << norm_d) >> 15); } } if (p_cov_matrix->phi_11 == 0) { k1 = 0; } else { if (ixheaacd_abs32_sat(p_cov_matrix->phi_01) >= p_cov_matrix->phi_11) { if (p_cov_matrix->phi_01 < 0) { k1 = 0x7fff; } else { k1 = (WORD16)-0x8000; } } else { k1 = -((WORD16)( (*ixheaacd_fix_div)(p_cov_matrix->phi_01, p_cov_matrix->phi_11))); } } if (low_band > 1) { WORD16 deg = ixheaacd_sub16_sat( 0x7fff, ixheaacd_mult16_shl_sat(k1_below, k1_below)); degree_alias[low_band] = 0; if (((low_band & 1) == 0) && (k1 < 0)) { if (k1_below < 0) { degree_alias[low_band] = 0x7fff; if (k1_below2 > 0) { degree_alias[low_band - 1] = deg; } } else { if (k1_below2 > 0) { degree_alias[low_band] = deg; } } } if (((low_band & 1) != 0) && (k1 > 0)) { if (k1_below > 0) { degree_alias[low_band] = 0x7fff; if (k1_below2 < 0) { degree_alias[low_band - 1] = deg; } } else { if (k1_below2 < 0) { degree_alias[low_band] = deg; } } } } k1_below2 = k1_below; k1_below = k1; patch = 0; while (patch < num_patches) { ia_patch_param_struct *p_loc_patch_param = &patch_param[patch]; WORD32 bw_vec, bw_idx; WORD16 alpha1, alpha2; high_band = (((low_band + p_loc_patch_param->dst_end_band) << 8) >> 8); if ((low_band < p_loc_patch_param->src_start_band) || (low_band >= p_loc_patch_param->src_end_band) || (high_band < max_qmf_subband)) { patch++; continue; } bw_idx = bw_index[patch]; while (high_band >= hf_generator->pstr_settings->bw_borders[bw_idx]) { bw_idx++; bw_index[patch] = bw_idx; } bw_vec = bw_array[bw_idx]; alpha1 = alpha_real[0]; alpha2 = alpha_real[1]; bw = ixheaacd_extract16h(bw_vec); a0r = ixheaacd_mult16x16in32_shl(bw, alpha1); bw = ixheaacd_mult16_shl_sat(bw, bw); a1r = ixheaacd_mult16x16in32_shl(bw, alpha2); { WORD32 *p_sub_signal_xlow = sub_sig_x + low_band + ((start_idx) << 6); WORD32 *p_sub_signal_xhigh = sub_sig_x + high_band + ((start_idx + 2) << 6); WORD32 len = stop_idx - start_idx - 1; if (bw > 0) { ixheaacd_filt_step3_lp(len, a0r, a1r, p_sub_signal_xlow, p_sub_signal_xhigh); } else { p_sub_signal_xlow += 128; for (i = len; i >= 0; i--) { *p_sub_signal_xhigh = *p_sub_signal_xlow >> LPC_SCALE_FACTOR; p_sub_signal_xlow += 64; p_sub_signal_xhigh += 64; } } } patch++; } } } VOID ixheaacd_clr_subsamples(WORD32 *ptr_qmf_buf, WORD32 num, WORD32 size) { WORD32 i; for (i = num; i >= 0; i--) { memset(ptr_qmf_buf, 0, sizeof(WORD32) * (size)); ptr_qmf_buf += 64; } } VOID ixheaacd_low_pow_hf_generator(ia_sbr_hf_generator_struct *hf_generator, WORD32 **qmf_real, WORD16 *degree_alias, WORD32 start_idx, WORD32 stop_idx, WORD32 num_if_bands, WORD32 max_qmf_subband, WORD32 *sbr_invf_mode, WORD32 *sbr_invf_mode_prev, WORD32 norm_max, WORD32 *sub_sig_x) { WORD32 bw_array[MAX_NUM_PATCHES]; WORD32 i; WORD32 start_patch, stop_patch, low_band, high_band; ia_patch_param_struct *patch_param = hf_generator->pstr_settings->str_patch_param; WORD32 patch; ixheaacd_lpp_trans_cov_matrix cov_matrix_seq[MAX_COLS]; WORD32 actual_stop_band; WORD32 num_patches = hf_generator->pstr_settings->num_patches; stop_idx = (hf_generator->pstr_settings->num_columns + stop_idx); ixheaacd_invfilt_level_emphasis(hf_generator, num_if_bands, sbr_invf_mode, sbr_invf_mode_prev, bw_array); actual_stop_band = ixheaacd_add16(patch_param[num_patches - 1].dst_start_band, patch_param[num_patches - 1].num_bands_in_patch); { WORD32 *p_qmf_real; WORD32 len = 6, num; if (len > stop_idx) len = stop_idx; p_qmf_real = &qmf_real[start_idx][actual_stop_band]; num = (len - start_idx - 1); ixheaacd_clr_subsamples(p_qmf_real, num, (NO_SYNTHESIS_CHANNELS - actual_stop_band)); if (actual_stop_band < 32) { num = (stop_idx - len - 1); p_qmf_real = &qmf_real[len][actual_stop_band]; ixheaacd_clr_subsamples(p_qmf_real, num, (NO_ANALYSIS_CHANNELS - actual_stop_band)); } } start_patch = ixheaacd_max16( 1, ixheaacd_sub16(hf_generator->pstr_settings->start_patch, 2)); stop_patch = patch_param[0].dst_start_band; { WORD32 *ptr = &sub_sig_x[0]; WORD32 *plpc_filt_states_real = &hf_generator->lpc_filt_states_real[0][0]; for (i = LPC_ORDER; i != 0; i--) { memcpy(ptr, plpc_filt_states_real, sizeof(WORD32) * (stop_patch)); ptr += NO_SYNTHESIS_CHANNELS; plpc_filt_states_real += 32; } } if (norm_max != 30) { (*ixheaacd_covariance_matrix_calc)(sub_sig_x + start_patch, &cov_matrix_seq[start_patch], (stop_patch - start_patch)); } else { memset(&cov_matrix_seq[0], 0, sizeof(ixheaacd_lpp_trans_cov_matrix) * stop_patch); } ixheaacd_filter1_lp(hf_generator, cov_matrix_seq, bw_array, degree_alias, start_idx, stop_idx, max_qmf_subband, start_patch, stop_patch, sub_sig_x); start_patch = hf_generator->pstr_settings->start_patch; stop_patch = hf_generator->pstr_settings->stop_patch; for (low_band = start_patch; low_band < stop_patch; low_band++) { WORD32 src_start_band, src_end_band, dst_start_band, dst_end_band; patch = 0; while (patch < num_patches) { ia_patch_param_struct *ptr_loc_patch_param = &patch_param[patch]; src_start_band = ptr_loc_patch_param->src_start_band; src_end_band = ptr_loc_patch_param->src_end_band; dst_start_band = ptr_loc_patch_param->dst_start_band; dst_end_band = ptr_loc_patch_param->dst_end_band; high_band = (low_band + ptr_loc_patch_param->dst_end_band); if ((low_band < src_start_band) || (low_band >= src_end_band) || (high_band >= NO_SYNTHESIS_CHANNELS)) { patch++; continue; } if ((high_band != dst_start_band)) { degree_alias[high_band] = degree_alias[low_band]; } patch++; } } memcpy(hf_generator->bw_array_prev, bw_array, sizeof(WORD32) * num_if_bands); } VOID ixheaacd_hf_generator(ia_sbr_hf_generator_struct *hf_generator, ia_sbr_scale_fact_struct *scale_factor, WORD32 **qmf_real, WORD32 **qmf_imag, WORD32 factor, WORD32 start_idx, WORD32 stop_idx, WORD32 num_if_bands, WORD32 max_qmf_subband, WORD32 *sbr_invf_mode, WORD32 *sbr_invf_mode_prev, WORD32 *sub_sig_x, WORD audio_object_type) { WORD32 bw_index[MAX_NUM_PATCHES]; WORD32 bw_array[MAX_NUM_PATCHES]; WORD32 i, j; WORD32 start_patch, stop_patch, low_band, high_band; ia_patch_param_struct *patch_param = hf_generator->pstr_settings->str_patch_param; WORD32 patch; WORD16 alpha_real[LPC_ORDER]; WORD16 a0r, a1r; WORD16 alpha_imag[LPC_ORDER]; WORD16 a0i = 0, a1i = 0; WORD16 bw = 0; ixheaacd_lpp_trans_cov_matrix cov_matrix; ixheaacd_lpp_trans_cov_matrix cov_matrix_seq[MAX_COLS]; WORD32 common_scale; WORD32 actual_stop_band; WORD32 num_patches = hf_generator->pstr_settings->num_patches; start_idx = (start_idx * factor); stop_idx = (hf_generator->pstr_settings->num_columns + (stop_idx * factor)); ixheaacd_invfilt_level_emphasis(hf_generator, num_if_bands, sbr_invf_mode, sbr_invf_mode_prev, bw_array); actual_stop_band = ixheaacd_add16(patch_param[num_patches - 1].dst_start_band, patch_param[num_patches - 1].num_bands_in_patch); for (i = start_idx; i < stop_idx; i++) { WORD32 *p_qmf_real = &qmf_real[i][actual_stop_band]; WORD32 *p_qmf_imag = &qmf_imag[i][actual_stop_band]; for (j = NO_SYNTHESIS_CHANNELS - actual_stop_band; j != 0; j--) { *p_qmf_real++ = 0; *p_qmf_imag++ = 0; } } memset(bw_index, 0, sizeof(WORD32) * num_patches); common_scale = ixheaacd_min32(scale_factor->ov_lb_scale, scale_factor->lb_scale); start_patch = hf_generator->pstr_settings->start_patch; stop_patch = hf_generator->pstr_settings->stop_patch; { WORD32 *ptr; for (i = 0; i < LPC_ORDER; i++) { ptr = sub_sig_x + (start_patch) + i * 128; memcpy(ptr, &hf_generator->lpc_filt_states_real[i][start_patch], sizeof(WORD32) * (stop_patch - start_patch)); memcpy(ptr + 64, &hf_generator->lpc_filt_states_imag[i][start_patch], sizeof(WORD32) * (stop_patch - start_patch)); } } if (audio_object_type != AOT_ER_AAC_ELD && audio_object_type != AOT_ER_AAC_LD) { (*ixheaacd_covariance_matrix_calc_2)( &cov_matrix_seq[start_patch], (sub_sig_x + start_patch + LPC_ORDER * 128), (stop_patch - start_patch), 38); } else { (*ixheaacd_covariance_matrix_calc_2)( &cov_matrix_seq[start_patch], (sub_sig_x + start_patch + LPC_ORDER * 128), (stop_patch - start_patch), 16); } for (low_band = start_patch; low_band < stop_patch; low_band++) { FLAG reset_lpc_coeff = 0; WORD32 max_val; WORD32 q_shift; WORD32 v; max_val = ixheaacd_abs32_nrm(cov_matrix_seq[low_band].phi_01); max_val = max_val | ixheaacd_abs32_nrm(cov_matrix_seq[low_band].phi_02); max_val = max_val | ixheaacd_abs32_nrm(cov_matrix_seq[low_band].phi_12); max_val = max_val | (cov_matrix_seq[low_band].phi_11); max_val = max_val | (cov_matrix_seq[low_band].phi_22); max_val = max_val | ixheaacd_abs32_nrm(cov_matrix_seq[low_band].phi_01_im); max_val = max_val | ixheaacd_abs32_nrm(cov_matrix_seq[low_band].phi_02_im); max_val = max_val | ixheaacd_abs32_nrm(cov_matrix_seq[low_band].phi_12_im); q_shift = ixheaacd_pnorm32(max_val); cov_matrix.phi_11 = (cov_matrix_seq[low_band].phi_11 << q_shift); cov_matrix.phi_22 = (cov_matrix_seq[low_band].phi_22 << q_shift); cov_matrix.phi_01 = (cov_matrix_seq[low_band].phi_01 << q_shift); cov_matrix.phi_02 = (cov_matrix_seq[low_band].phi_02 << q_shift); cov_matrix.phi_12 = (cov_matrix_seq[low_band].phi_12 << q_shift); cov_matrix.phi_01_im = (cov_matrix_seq[low_band].phi_01_im << q_shift); cov_matrix.phi_02_im = (cov_matrix_seq[low_band].phi_02_im << q_shift); cov_matrix.phi_12_im = (cov_matrix_seq[low_band].phi_12_im << q_shift); max_val = ixheaacd_mult32(cov_matrix.phi_12, cov_matrix.phi_12); max_val = ixheaacd_add32_sat( max_val, ixheaacd_mult32(cov_matrix.phi_12_im, cov_matrix.phi_12_im)); v = ixheaacd_sub32(ixheaacd_mult32(cov_matrix.phi_11, cov_matrix.phi_22), max_val) << 1; cov_matrix.d = v; alpha_real[1] = 0; alpha_imag[1] = 0; if (cov_matrix.d != 0) { WORD32 tmp_r, temp_real, modulus_d; WORD32 tmp_i, temp_imag; WORD16 inverse_d; WORD32 norm_d; norm_d = ixheaacd_norm32(cov_matrix.d); inverse_d = (WORD16)(*ixheaacd_fix_div)(0x40000000, (cov_matrix.d << norm_d)); modulus_d = ixheaacd_abs32_sat(cov_matrix.d); tmp_r = (ixheaacd_sub32( ixheaacd_sub32( ixheaacd_mult32(cov_matrix.phi_01, cov_matrix.phi_12), ixheaacd_mult32(cov_matrix.phi_01_im, cov_matrix.phi_12_im)), ixheaacd_mult32(cov_matrix.phi_02, cov_matrix.phi_11))) >> (LPC_SCALE_FACTOR - 1); tmp_i = (ixheaacd_sub32_sat( ixheaacd_add32_sat( ixheaacd_mult32(cov_matrix.phi_01_im, cov_matrix.phi_12), ixheaacd_mult32(cov_matrix.phi_01, cov_matrix.phi_12_im)), ixheaacd_mult32(cov_matrix.phi_02_im, cov_matrix.phi_11))) >> (LPC_SCALE_FACTOR - 1); temp_imag = ixheaacd_abs32(tmp_i); temp_real = ixheaacd_abs32(tmp_r); if (temp_real >= modulus_d) { reset_lpc_coeff = 1; } else { alpha_real[1] = (WORD16)( (ixheaacd_mult32x16in32(tmp_r, inverse_d) << (norm_d + 1)) >> 15); } if (temp_imag >= modulus_d) { reset_lpc_coeff = 1; } else { alpha_imag[1] = (WORD16)( (ixheaacd_mult32x16in32(tmp_i, inverse_d) << (norm_d + 1)) >> 15); } } alpha_real[0] = 0; alpha_imag[0] = 0; if (cov_matrix.phi_11 != 0) { WORD32 tmp_r, temp_real; WORD32 tmp_i = 0, temp_imag = 0; WORD16 inverse_r11; WORD32 norm_r11; norm_r11 = ixheaacd_norm32(cov_matrix.phi_11); inverse_r11 = (WORD16)(*ixheaacd_fix_div)( 0x40000000, (cov_matrix.phi_11 << norm_r11)); tmp_r = ixheaacd_add32( ixheaacd_add32( (cov_matrix.phi_01 >> (LPC_SCALE_FACTOR + 1)), ixheaacd_mult32x16in32(cov_matrix.phi_12, alpha_real[1])), ixheaacd_mult32x16in32(cov_matrix.phi_12_im, alpha_imag[1])); tmp_i = ixheaacd_sub32( ixheaacd_add32( (cov_matrix.phi_01_im >> (LPC_SCALE_FACTOR + 1)), ixheaacd_mult32x16in32(cov_matrix.phi_12, alpha_imag[1])), ixheaacd_mult32x16in32(cov_matrix.phi_12_im, alpha_real[1])); tmp_r = tmp_r << 1; tmp_i = tmp_i << 1; temp_imag = ixheaacd_abs32(tmp_i); temp_real = ixheaacd_abs32(tmp_r); if (temp_real >= cov_matrix.phi_11) { reset_lpc_coeff = 1; } else { alpha_real[0] = (WORD16)( (ixheaacd_mult32x16in32(ixheaacd_sub32_sat(0, tmp_r), inverse_r11) << (norm_r11 + 1)) >> 15); } if (temp_imag >= cov_matrix.phi_11) { reset_lpc_coeff = 1; } else { alpha_imag[0] = (WORD16)( (ixheaacd_mult32x16in32(ixheaacd_sub32_sat(0, tmp_i), inverse_r11) << (norm_r11 + 1)) >> 15); } } if (ixheaacd_add32((alpha_real[0] * alpha_real[0]), (alpha_imag[0] * alpha_imag[0])) >= 0x40000000L) { reset_lpc_coeff = 1; } if (ixheaacd_add32((alpha_real[1] * alpha_real[1]), (alpha_imag[1] * alpha_imag[1])) >= 0x40000000L) { reset_lpc_coeff = 1; } if (reset_lpc_coeff) { alpha_real[0] = 0; alpha_real[1] = 0; alpha_imag[0] = 0; alpha_imag[1] = 0; } patch = 0; while (patch < num_patches) { high_band = (low_band + patch_param[patch].dst_end_band); if ((low_band < patch_param[patch].src_start_band) || (low_band >= patch_param[patch].src_end_band)) { patch++; continue; } if (high_band < max_qmf_subband) { patch++; continue; } while (high_band >= hf_generator->pstr_settings->bw_borders[bw_index[patch]]) { bw_index[patch] = (bw_index[patch] + 1); } bw = ixheaacd_extract16h(bw_array[bw_index[patch]]); a0r = ixheaacd_mult16_shl_sat(bw, alpha_real[0]); a0i = ixheaacd_mult16_shl_sat(bw, alpha_imag[0]); bw = ixheaacd_mult16_shl_sat(bw, bw); a1r = ixheaacd_mult16_shl_sat(bw, alpha_real[1]); a1i = ixheaacd_mult16_shl_sat(bw, alpha_imag[1]); if (bw > 0) { ixheaacd_filterstep3(a0r, a0i, a1r, a1i, start_idx, stop_idx, low_band, high_band, sub_sig_x); } else { WORD32 *p_src = sub_sig_x + low_band + ((start_idx + 2) << 7); WORD32 *p_dst = sub_sig_x + high_band + ((start_idx + 2) << 7); for (i = stop_idx - start_idx; i != 0; i--) { *(p_dst) = *(p_src) >> LPC_SCALE_FACTOR; p_src += 64; p_dst += 64; *(p_dst) = *(p_src) >> LPC_SCALE_FACTOR; p_src += 64; p_dst += 64; } } patch++; } } memcpy(hf_generator->bw_array_prev, bw_array, sizeof(WORD32) * num_if_bands); scale_factor->hb_scale = (WORD16)(common_scale - LPC_SCALE_FACTOR); }