/****************************************************************************** * * * 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_type_def.h" #include "ixheaacd_bitbuffer.h" #include "ixheaacd_common_rom.h" #include "ixheaacd_sbrdecsettings.h" #include "ixheaacd_sbr_scale.h" #include "ixheaacd_env_extr_part.h" #include "ixheaacd_sbr_rom.h" #include "ixheaacd_hybrid.h" #include "ixheaacd_ps_dec.h" #include "ixheaacd_config.h" #include "ixheaacd_qmf_dec.h" #include "ixheaacd_audioobjtypes.h" #include "ixheaacd_mps_polyphase.h" #include "ixheaacd_mps_struct_def.h" #include "ixheaacd_mps_res_rom.h" #include "ixheaacd_mps_aac_struct.h" #include "ixheaacd_constants.h" #include "ixheaacd_mps_dec.h" #include "ixheaacd_mps_decor.h" #include "ixheaacd_mps_hybfilter.h" #include "ixheaacd_error_standards.h" #include "ixheaacd_basic_ops32.h" #include "ixheaacd_basic_ops40.h" #include "ixheaacd_mps_macro_def.h" #include "ixheaacd_mps_basic_op.h" static const WORD32 ixheaacd_decorr_delay[] = {11, 10, 5, 2}; static const WORD32 ixheaacd_decorr_delay_ldmps[] = {8, 7, 2, 1}; static const WORD32 ixheaacd_qmf_split_freq_0[] = {3, 15, 24, 65}; static const WORD32 ixheaacd_qmf_split_freq_1[] = {3, 50, 65, 65}; static const WORD32 ixheaacd_qmf_split_freq_2[] = {0, 15, 65, 65}; static const WORD32 ixheaacd_qmf_split_freq_0_ldmps[] = {0, 15, 24, 65}; static const WORD32 ixheaacd_qmf_split_freq_1_ldmps[] = {0, 50, 65, 65}; static const WORD32 ixheaacd_qmf_split_freq_2_ldmps[] = {0, 15, 65, 65}; extern const WORD32 ixheaacd_mps_gain_set_indx[29]; static const FLOAT32 ixheaacd_lattice_coeff_0_filt_den_coeff[DECORR_FILT_0_ORD + 1] = { 1.000000f, -0.314818f, -0.256828f, -0.173641f, -0.115077f, 0.000599f, 0.033343f, 0.122672f, -0.356362f, 0.128058f, 0.089800f}; static const FLOAT32 ixheaacd_lattice_coeff_0_filt_num_coeff[DECORR_FILT_0_ORD + 1] = { 0.089800f, 0.128058f, -0.356362f, 0.122672f, 0.033343f, 0.000599f, -0.115077f, -0.173641f, -0.256828f, -0.314818f, 1.000000f}; static const FLOAT32 ixheaacd_lattice_coeff_1_filt_den_coeff[DECORR_FILT_1_ORD + 1] = { 1.000000f, -0.287137f, -0.088940f, 0.123204f, -0.126111f, 0.064218f, 0.045768f, -0.016264f, -0.122100f}; static const FLOAT32 ixheaacd_lattice_coeff_1_filt_num_coeff[DECORR_FILT_1_ORD + 1] = { -0.122100f, -0.016264f, 0.045768f, 0.064218f, -0.126111f, 0.123204f, -0.088940f, -0.287137f, 1.000000f}; static const FLOAT32 ixheaacd_lattice_coeff_2_filt_den_coeff[DECORR_FILT_2_ORD + 1] = { 1.000000f, 0.129403f, -0.032633f, 0.035700f}; static const FLOAT32 ixheaacd_lattice_coeff_2_filt_num_coeff[DECORR_FILT_2_ORD + 1] = { 0.035700f, -0.032633f, 0.129403f, 1.000000f}; static const FLOAT32 ixheaacd_lattice_coeff_3_filt_den_coeff[DECORR_FILT_3_ORD + 1] = { 1.000000f, 0.034742f, -0.013000f}; static const FLOAT32 ixheaacd_lattice_coeff_3_filt_num_coeff[DECORR_FILT_3_ORD + 1] = { -0.013000f, 0.034742f, 1.000000f}; static const FLOAT32 ixheaacd_lattice_coeff_1_filt_num_ldmps[DECORR_FILTER_ORDER_BAND_1 + 1] = { (0.3355999887f), (0.0024894588f), (-0.1572290659f), (0.2807503343f), (-0.1942857355f), (0.3840600252f), (-0.4084388912f), (-0.1750483066f), (0.5559588671f), (-0.4935829639f), (0.0567415841f), (-0.0658148378f), (0.3378961682f), (0.2284426540f), (-0.7025330663f), (1.0000000000f)}; static const FLOAT32 ixheaacd_lattice_coeff_1_filt_den_ldmps[DECORR_FILTER_ORDER_BAND_1 + 1] = { (1.0000000000f), (-0.7025330663f), (0.2284426540f), (0.3378961682f), (-0.0658148378f), (0.0567415841f), (-0.4935829639f), (0.5559588671f), (-0.1750483066f), (-0.4084388912f), (0.3840600252f), (-0.1942857355f), (0.2807503343f), (-0.1572290659f), (0.0024894588f), (0.3355999887f)}; static const FLOAT32 ixheaacd_lattice_coeff_2_filt_num_ldmps[DECORR_FILTER_ORDER_BAND_2 + 1] = { (-0.4623999894f), (0.2341193259f), (0.5163637400f), (-0.0253488291f), (-0.2871030867f), (0.0153170601f), (1.0000000000f)}; static const FLOAT32 ixheaacd_lattice_coeff_2_filt_den_ldmps[DECORR_FILTER_ORDER_BAND_2 + 1] = { (1.0000000000f), (0.0153170601f), (-0.2871030867f), (-0.0253488291f), (0.5163637400f), (0.2341193259f), (-0.4623999894f) }; static const FLOAT32 ixheaacd_lattice_coeff_3_filt_num_ldmps[DECORR_FILTER_ORDER_BAND_3 + 1] = { (0.2468000054f), (0.0207958221f), (-0.3898491263f), (1.0000000000f)}; static const FLOAT32 ixheaacd_lattice_coeff_3_filt_den_ldmps[DECORR_FILTER_ORDER_BAND_3 + 1] = { (1.0000000000f), (-0.3898491263f), (0.0207958221f), (0.2468000054f)}; extern WORD32 ixheaacd_hybrid_band_71_to_processing_band_28_map[MAX_HYBRID_BANDS_MPS]; extern WORD32 ixheaacd_hybrid_band_64_to_processing_band_23_map[MAX_HYBRID_BANDS_MPS]; static const WORD32 ixheaacd_hybrid_to_qmf_map[MAX_HYBRID_BANDS_MPS] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; static const WORD32 ixheaacd_hybrid_to_qmf_map_ldmps[MAX_HYBRID_BANDS_MPS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70}; static VOID ixheaacd_mps_decor_filt_init(ia_mps_decor_filt_struct *self, WORD32 reverb_band, WORD32 object_type) { if (object_type == AOT_ER_AAC_ELD || object_type == AOT_ER_AAC_LD) { switch (reverb_band) { case 0: self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_0 + 1; self->num = NULL; self->den = NULL; break; case 1: self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_1 + 1; self->num = ixheaacd_lattice_coeff_1_filt_num_ldmps; self->den = ixheaacd_lattice_coeff_1_filt_den_ldmps; break; case 2: self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_2 + 1; self->num = ixheaacd_lattice_coeff_2_filt_num_ldmps; self->den = ixheaacd_lattice_coeff_2_filt_den_ldmps; break; case 3: self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_3 + 1; self->num = ixheaacd_lattice_coeff_3_filt_num_ldmps; self->den = ixheaacd_lattice_coeff_3_filt_den_ldmps; break; } } else { switch (reverb_band) { case 0: self->num_len = self->den_len = DECORR_FILT_0_ORD + 1; self->num = ixheaacd_lattice_coeff_0_filt_num_coeff; self->den = ixheaacd_lattice_coeff_0_filt_den_coeff; break; case 1: self->num_len = self->den_len = DECORR_FILT_1_ORD + 1; self->num = ixheaacd_lattice_coeff_1_filt_num_coeff; self->den = ixheaacd_lattice_coeff_1_filt_den_coeff; break; case 2: self->num_len = self->den_len = DECORR_FILT_2_ORD + 1; self->num = ixheaacd_lattice_coeff_2_filt_num_coeff; self->den = ixheaacd_lattice_coeff_2_filt_den_coeff; break; case 3: self->num_len = self->den_len = DECORR_FILT_3_ORD + 1; self->num = ixheaacd_lattice_coeff_3_filt_num_coeff; self->den = ixheaacd_lattice_coeff_3_filt_den_coeff; break; } } self->state_len = self->num_len; memset(self->state, 0, sizeof(ia_cmplx_flt_struct) * (MAX_DECORR_FILTER_ORDER + 1)); return; } static VOID ixheaacd_mps_allpass_apply(ia_mps_decor_filt_struct *self, ia_cmplx_flt_struct *input, WORD32 len, ia_cmplx_flt_struct *output) { WORD32 i, j; for (i = 0; i < len; i++) { output[i].re = self->state[0].re + input[i].re * self->num[0]; output[i].im = self->state[0].im + input[i].im * self->num[0]; for (j = 1; j < self->num_len; j++) { self->state[j - 1].re = self->state[j].re + self->num[j] * input[i].re - self->den[j] * output[i].re; self->state[j - 1].im = self->state[j].im + self->num[j] * input[i].im - self->den[j] * output[i].im; } } } static VOID ixheaacd_mps_decor_energy_adjustment( ixheaacd_mps_decor_energy_adjust_filt_struct *handle, ia_cmplx_flt_struct in[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS], ia_cmplx_flt_struct out[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS], WORD32 time_slots, WORD32 res_bands, WORD32 ldmps_present) { ixheaacd_mps_decor_energy_adjust_filt_struct *self = (ixheaacd_mps_decor_energy_adjust_filt_struct *)handle; FLOAT32 in_energy[MAX_PARAMETER_BANDS] = {0}; FLOAT32 out_energy[MAX_PARAMETER_BANDS] = {0}; FLOAT32 gain[MAX_PARAMETER_BANDS]; WORD32 i, j, k, loop_counter; WORD32 *ptr_hybrid_band; if (ldmps_present == 1) ptr_hybrid_band = ixheaacd_hybrid_band_64_to_processing_band_23_map; else ptr_hybrid_band = ixheaacd_hybrid_band_71_to_processing_band_28_map; WORD32 start_param_band = 0, start_bin = 0; if (res_bands != NO_RES_BANDS) { start_bin = ixheaacd_mps_gain_set_indx[res_bands]; start_param_band = res_bands; } for (i = 0; i < time_slots; i++) { memset(in_energy, 0, sizeof(FLOAT32) * MAX_PARAMETER_BANDS); memset(out_energy, 0, sizeof(FLOAT32) * MAX_PARAMETER_BANDS); for (j = start_bin; j < self->num_bins; j++) { k = ptr_hybrid_band[j]; in_energy[k] += in[i][j].re * in[i][j].re + in[i][j].im * in[i][j].im; out_energy[k] += out[i][j].re * out[i][j].re + out[i][j].im * out[i][j].im; } loop_counter = MAX_PARAMETER_BANDS; for (k = start_param_band; k < loop_counter; k++) { self->smooth_in_energy[k] = self->smooth_in_energy[k] * DECOR_ALPHA + in_energy[k] * ONE_MINUS_DECOR_ALPHA; self->smooth_out_energy[k] = self->smooth_out_energy[k] * DECOR_ALPHA + out_energy[k] * ONE_MINUS_DECOR_ALPHA; gain[k] = 1.0f; if (self->smooth_out_energy[k] > self->smooth_in_energy[k] * DECOR_GAMMA) { gain[k] = (FLOAT32)sqrt(self->smooth_in_energy[k] * DECOR_GAMMA / (self->smooth_out_energy[k] + ABS_THR)); } if (self->smooth_in_energy[k] > self->smooth_out_energy[k] * DECOR_GAMMA) { gain[k] = min(2.0f, (FLOAT32)sqrt(self->smooth_in_energy[k] / (DECOR_GAMMA * self->smooth_out_energy[k] + ABS_THR))); } } for (j = start_bin; j < self->num_bins; j++) { k = ptr_hybrid_band[j]; out[i][j].re *= gain[k]; out[i][j].im *= gain[k]; } } } IA_ERRORCODE ixheaacd_mps_decor_init(ia_mps_decor_struct *self, WORD32 subbands, WORD32 decor_config, WORD32 object_type) { WORD32 i, reverb_band; const WORD32 *splitfreq; const WORD32 *ptr_ixheaacd_hybrid_to_qmf_map; const WORD32 *ptr_decorr_delay; if (object_type == AOT_ER_AAC_ELD || object_type == AOT_ER_AAC_LD) { ptr_ixheaacd_hybrid_to_qmf_map = ixheaacd_hybrid_to_qmf_map_ldmps; ptr_decorr_delay = ixheaacd_decorr_delay_ldmps; switch (decor_config) { case 0: splitfreq = ixheaacd_qmf_split_freq_0_ldmps; break; case 1: splitfreq = ixheaacd_qmf_split_freq_1_ldmps; break; case 2: splitfreq = ixheaacd_qmf_split_freq_2_ldmps; break; default: return IA_FATAL_ERROR; } } else { ptr_ixheaacd_hybrid_to_qmf_map = ixheaacd_hybrid_to_qmf_map; ptr_decorr_delay = ixheaacd_decorr_delay; switch (decor_config) { case 0: splitfreq = ixheaacd_qmf_split_freq_0; break; case 1: splitfreq = ixheaacd_qmf_split_freq_1; break; case 2: splitfreq = ixheaacd_qmf_split_freq_2; break; default: return IA_FATAL_ERROR; } } self->num_bins = subbands; if (self->num_bins > MAX_HYBRID_BANDS_MPS) return IA_FATAL_ERROR; for (i = 0; i < self->num_bins; i++) { reverb_band = 0; while ((reverb_band < 3) && (ptr_ixheaacd_hybrid_to_qmf_map[i] >= (splitfreq[reverb_band] - 1))) reverb_band++; self->delay_sample_count[i] = ptr_decorr_delay[reverb_band]; ixheaacd_mps_decor_filt_init(&self->filter[i], reverb_band, object_type); } self->decor_nrg_smooth.num_bins = self->num_bins; return IA_NO_ERROR; } VOID ixheaacd_mps_decor_apply( ia_mps_decor_struct *self, ia_cmplx_flt_struct in[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS], ia_cmplx_flt_struct out[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS], WORD32 length, WORD32 res_bands, WORD32 ldmps_present) { WORD32 idx, sb_sample, index = 0; ia_cmplx_flt_struct scratch[MAX_TIME_SLOTS]; if (res_bands != NO_RES_BANDS) index = ixheaacd_mps_gain_set_indx[res_bands]; for (idx = index; idx < self->num_bins; idx++) { for (sb_sample = 0; sb_sample < length; sb_sample++) { self->decor_delay_buffer[idx][self->delay_sample_count[idx] + sb_sample] .re = in[sb_sample][idx].re; self->decor_delay_buffer[idx][self->delay_sample_count[idx] + sb_sample] .im = in[sb_sample][idx].im; } ixheaacd_mps_allpass_apply(&self->filter[idx], self->decor_delay_buffer[idx], length, scratch); for (sb_sample = 0; sb_sample < length; sb_sample++) { out[sb_sample][idx].re = scratch[sb_sample].re; out[sb_sample][idx].im = scratch[sb_sample].im; } for (sb_sample = 0; sb_sample < self->delay_sample_count[idx]; sb_sample++) { self->decor_delay_buffer[idx][sb_sample].re = self->decor_delay_buffer[idx][length + sb_sample].re; self->decor_delay_buffer[idx][sb_sample].im = self->decor_delay_buffer[idx][length + sb_sample].im; } } ixheaacd_mps_decor_energy_adjustment(&self->decor_nrg_smooth, in, out, length, res_bands, ldmps_present); } static VOID ixheaacd_convert_lattice_coefs_complex(WORD32 const order, WORD32 const *const rfc_real, WORD32 const *const rfc_imag, WORD32 *const apar_real, WORD32 *const apar_imag) { WORD32 i, j; WORD32 tmp_real[MAX_DECORR_FILTER_ORDER + 1]; WORD32 tmp_imag[MAX_DECORR_FILTER_ORDER + 1]; WORD64 temp; apar_real[0] = 32768; apar_imag[0] = 0; for (i = 0; i < order; i++) { apar_real[i + 1] = rfc_real[i]; apar_imag[i + 1] = rfc_imag[i]; for (j = 0; j < i; j++) { temp = (WORD64)((WORD64)rfc_real[i] * (WORD64)tmp_real[i - j - 1] + (WORD64)rfc_imag[i] * (WORD64)tmp_imag[i - j - 1]); temp >>= 15; apar_real[j + 1] = ixheaacd_add32(tmp_real[j], (WORD32)temp); temp = (WORD64)((WORD64)rfc_real[i] * (WORD64)tmp_imag[i - j - 1] + (WORD64)rfc_imag[i] * (WORD64)tmp_real[i - j - 1]); temp >>= 15; apar_imag[j + 1] = ixheaacd_sub32(tmp_imag[j], (WORD32)temp); } for (j = 0; j <= i; j++) { tmp_real[j] = apar_real[j + 1]; tmp_imag[j] = apar_imag[j + 1]; } } } static IA_ERRORCODE ixheaacd_decorr_filt_create( ia_mps_dec_decorr_filter_instance_struct *self, WORD32 const decorr_seed, WORD32 const qmf_band, WORD32 const reverb_band, WORD32 const dec_type, ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table) { IA_ERRORCODE error_code = IA_NO_ERROR; WORD32 i; const WORD32 *lattice_coeff = NULL; WORD32 lattice_coeff_real[MAX_DECORR_FILTER_ORDER]; WORD32 lattice_coeff_imag[MAX_DECORR_FILTER_ORDER]; WORD32 temp_1; if (self == NULL) { error_code = IA_FATAL_ERROR; } if (error_code == IA_NO_ERROR) { switch (reverb_band) { case REVERB_BAND_0: self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_0 + 1; lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr ->lattice_coeff_0[decorr_seed][0]); break; case REVERB_BAND_1: self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_1 + 1; lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr ->lattice_coeff_1[decorr_seed][0]); break; case REVERB_BAND_2: self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_2 + 1; lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr ->lattice_coeff_2[decorr_seed][0]); break; case REVERB_BAND_3: self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_3 + 1; lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr ->lattice_coeff_3[decorr_seed][0]); break; default: return IA_FATAL_ERROR; } self->state_length = (self->num_length > self->den_length) ? self->num_length : self->den_length; } if (error_code == IA_NO_ERROR) { const WORD32 *cos_tab = ia_mps_dec_mps_table->hybrid_table_ptr->cosine_array; const WORD32 *sin_tab = ia_mps_dec_mps_table->hybrid_table_ptr->sine_array; if (dec_type == 1) { for (i = 0; i < self->num_length - 1; i++) { temp_1 = (qmf_band * ia_mps_dec_mps_table->decor_table_ptr ->lattice_delta_phi[decorr_seed][i]) >> 1; lattice_coeff_real[i] = ixheaacd_mps_mult32_shr_15( ixheaacd_mps_cos(temp_1, cos_tab), lattice_coeff[i]); lattice_coeff_imag[i] = ixheaacd_mps_mult32_shr_15( ixheaacd_mps_sin(temp_1, sin_tab), lattice_coeff[i]); } ixheaacd_convert_lattice_coefs_complex( self->num_length - 1, lattice_coeff_real, lattice_coeff_imag, self->denominator_real, self->denominator_imag); for (i = 0; i < self->num_length; i++) { self->numerator_real[i] = self->denominator_real[self->num_length - 1 - i]; self->numerator_imag[i] = -self->denominator_imag[self->num_length - 1 - i]; } self->complex = 1; } else { switch (reverb_band) { case REVERB_BAND_0: self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr ->den_coef_0[decorr_seed][0]); break; case REVERB_BAND_1: self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr ->den_coef_1[decorr_seed][0]); break; case REVERB_BAND_2: self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr ->den_coef_2[decorr_seed][0]); break; case REVERB_BAND_3: self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr ->den_coef_3[decorr_seed][0]); break; default: return IA_FATAL_ERROR; } for (i = 0; i < self->num_length; i++) { self->numerator_real[i] = self->denominator_real[self->num_length - 1 - i]; } self->complex = 0; } } return error_code; } static VOID ixheaacd_decorr_filt_apply( ia_mps_dec_decorr_filter_instance_struct *const self, WORD32 const length, WORD32 const *const input_real, WORD32 const *const input_imag, WORD32 *const p_output_real, WORD32 *const p_output_imag) { WORD32 temp_1, temp_2, temp3, temp4; WORD32 temp5, temp6, temp7, temp8; WORD32 *state_real, *state_imag; WORD32 *numerator_real, *denominator_real; WORD32 *output_real = p_output_real; WORD32 *output_imag = p_output_imag; WORD32 common_part; WORD32 i; WORD32 j; common_part = self->num_length; state_real = self->state_real; state_imag = self->state_imag; numerator_real = self->numerator_real; denominator_real = self->denominator_real; { for (i = 0; i < length; i++) { { temp5 = input_real[i]; temp6 = input_imag[i]; temp_1 = ixheaacd_mps_mult32_shr_14(temp5, numerator_real[0]); temp_2 = ixheaacd_mps_mult32_shr_14(temp6, numerator_real[0]); *output_real = temp_1 + state_real[0]; *output_imag = temp_2 + state_imag[0]; temp7 = *output_real; temp8 = *output_imag; output_real += MAX_HYBRID_BANDS; output_imag += MAX_HYBRID_BANDS; for (j = 1; j < common_part; j++) { temp_1 = ixheaacd_mps_mult32x16_shr_16(temp5, numerator_real[j]); temp3 = ixheaacd_mps_mult32x16_shr_16(temp6, numerator_real[j]); temp_2 = ixheaacd_mps_mult32x16_shr_16(temp7, denominator_real[j]); temp4 = ixheaacd_mps_mult32x16_shr_16(temp8, denominator_real[j]); temp_1 -= temp_2; state_real[j - 1] = state_real[j] + (temp_1 << 2); temp3 -= temp4; state_imag[j - 1] = state_imag[j] + (temp3 << 2); } } } } } static VOID ixheaacd_ducker_apply_71( ia_mps_dec_ducker_interface *const face, WORD32 const time_slots, WORD32 const *input_real, WORD32 const *input_imag, WORD32 *output_real, WORD32 *output_imag, ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table_ptr, VOID *scratch) { ia_mps_dec_duck_instance_struct *self = (ia_mps_dec_duck_instance_struct *)&face[1]; WORD32 *duck_gain; WORD32 gain; WORD16 qgain; WORD64 direct_nrg[28]; WORD64 reverb_nrg[28]; WORD16 *q_duck_gain; WORD32 ts; WORD32 qs; WORD32 pb; WORD16 qtemp1, qtemp2, qtemp3; WORD32 temp_1, temp_2, temp3; const WORD32 *p_input_real; const WORD32 *p_input_imag; const WORD32 *hybrid_2_param_28 = ia_mps_dec_mps_table_ptr->m1_m2_table_ptr->hybrid_2_param_28; const WORD32 *sqrt_tab = ia_mps_dec_mps_table_ptr->common_table_ptr->sqrt_tab; WORD32 *smooth_direct_nrg = self->smooth_direct_nrg; WORD16 *q_smooth_direct_nrg = self->q_smooth_direct_nrg; WORD32 *smooth_reverb_nrg = self->smooth_reverb_nrg; WORD16 *q_smooth_reverb_nrg = self->q_smooth_reverb_nrg; WORD32 parameter_bands = self->parameter_bands; WORD32 *p_output_real, *p_output_imag; WORD32 num_bands_2 = self->hybrid_bands; WORD32 v1, v2, v3, v4; WORD16 one_by_5 = ONE_BY_FIVE_Q16; duck_gain = scratch; q_duck_gain = (WORD16 *)scratch + PARAMETER_BANDSX2; p_input_real = input_real; p_input_imag = input_imag; p_output_real = output_real; p_output_imag = output_imag; for (ts = 0; ts < time_slots; ts++) { memset(direct_nrg, 0, sizeof(direct_nrg)); memset(reverb_nrg, 0, sizeof(reverb_nrg)); for (qs = 0; qs < 55; qs++) { v1 = p_input_real[qs]; v2 = p_input_imag[qs]; v3 = p_output_real[qs]; v4 = p_output_imag[qs]; pb = hybrid_2_param_28[qs]; direct_nrg[pb] += (WORD64)((WORD64)v1 * (WORD64)v1) + (WORD64)((WORD64)v2 * (WORD64)v2); reverb_nrg[pb] += (WORD64)((WORD64)v3 * (WORD64)v3) + (WORD64)((WORD64)v4 * (WORD64)v4); } for (; qs < num_bands_2; qs++) { v1 = p_input_real[qs]; v2 = p_input_imag[qs]; v3 = p_output_real[qs]; v4 = p_output_imag[qs]; direct_nrg[27] += (WORD64)((WORD64)v1 * (WORD64)v1) + (WORD64)((WORD64)v2 * (WORD64)v2); reverb_nrg[27] += (WORD64)((WORD64)v3 * (WORD64)v3) + (WORD64)((WORD64)v4 * (WORD64)v4); } for (pb = 0; pb < parameter_bands; pb++) { WORD16 qtemp, qtemp_1; temp_1 = ixheaacd_mps_narrow(direct_nrg[pb], &qtemp); temp_2 = smooth_direct_nrg[pb] << 2; temp3 = ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_direct_nrg[pb]), qtemp); smooth_direct_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5); temp_1 = ixheaacd_mps_narrow(reverb_nrg[pb], &qtemp); temp_2 = smooth_reverb_nrg[pb] << 2; temp3 = ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_reverb_nrg[pb]), qtemp); smooth_reverb_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5); qtemp1 = q_smooth_reverb_nrg[pb] - 1; temp_1 = (smooth_reverb_nrg[pb] >> 2) * 3; qtemp = q_smooth_direct_nrg[pb]; temp3 = smooth_direct_nrg[pb]; if (ixheaacd_mps_comp(temp3, temp_1, &qtemp, qtemp1)) { temp_2 = ixheaacd_mps_div_32(temp3, temp_1, &qtemp2); qtemp2 = qtemp2 + qtemp - qtemp1; temp3 = (qtemp2) > 28 ? MAX_32 : 4 << qtemp2; if (temp_2 > temp3) { *duck_gain = (ONE_IN_Q15 - 1); *q_duck_gain++ = 14; } else { *duck_gain = ixheaacd_mps_sqrt(temp_2, &qtemp2, sqrt_tab); *q_duck_gain++ = qtemp2; } duck_gain++; continue; } *duck_gain = ONE_IN_Q14 - 1; qtemp = q_smooth_direct_nrg[pb] - 1; temp_1 = (smooth_direct_nrg[pb] >> 2) * 3; qtemp_1 = q_smooth_reverb_nrg[pb]; temp_2 = smooth_reverb_nrg[pb]; if (ixheaacd_mps_comp(temp_2, temp_1, &(qtemp_1), qtemp)) { temp3 = ixheaacd_mps_div_32(temp_1, temp_2, &qtemp3); qtemp3 = qtemp3 + qtemp - qtemp_1; *duck_gain = ixheaacd_mps_sqrt(temp3, &qtemp3, sqrt_tab); *q_duck_gain = qtemp3; } duck_gain++; q_duck_gain++; } duck_gain -= parameter_bands; q_duck_gain -= parameter_bands; for (qs = 0; qs < 55; qs++) { pb = hybrid_2_param_28[qs]; gain = duck_gain[pb]; if (gain == 16383) { continue; } qgain = q_duck_gain[pb]; p_output_real[qs] = ixheaacd_mps_mult32_shr_n(p_output_real[qs], gain, qgain); p_output_imag[qs] = ixheaacd_mps_mult32_shr_n(p_output_imag[qs], gain, qgain); } gain = duck_gain[27]; if (gain != 16383) { qgain = q_duck_gain[27]; for (; qs < num_bands_2; qs++) { p_output_real[qs] = ixheaacd_mps_mult32_shr_n(p_output_real[qs], gain, qgain); p_output_imag[qs] = ixheaacd_mps_mult32_shr_n(p_output_imag[qs], gain, qgain); } } p_input_real += MAX_HYBRID_BANDS; p_input_imag += MAX_HYBRID_BANDS; p_output_real += MAX_HYBRID_BANDS; p_output_imag += MAX_HYBRID_BANDS; } } static VOID ixheaacd_ducker_apply( ia_mps_dec_ducker_interface *const face, WORD32 const time_slots, WORD32 const *input_real, WORD32 const *input_imag, WORD32 *output_real, WORD32 *output_imag, ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table_ptr, VOID *scratch) { ia_mps_dec_duck_instance_struct *self = (ia_mps_dec_duck_instance_struct *)&face[1]; WORD32 *duck_gain; WORD32 gain; WORD16 qgain; WORD64 direct_nrg[28]; WORD64 reverb_nrg[28]; WORD16 *q_duck_gain; WORD32 ts; WORD32 qs; WORD32 pb; WORD16 qtemp1, qtemp2, qtemp3; WORD32 temp_1, temp_2, temp3; const WORD32 *p_input_real; const WORD32 *p_input_imag; const WORD32 *hybrid_2_param_28 = ia_mps_dec_mps_table_ptr->m1_m2_table_ptr->hybrid_2_param_28; const WORD32 *sqrt_tab = ia_mps_dec_mps_table_ptr->common_table_ptr->sqrt_tab; WORD32 *smooth_direct_nrg = self->smooth_direct_nrg; WORD16 *q_smooth_direct_nrg = self->q_smooth_direct_nrg; WORD32 *smooth_reverb_nrg = self->smooth_reverb_nrg; WORD16 *q_smooth_reverb_nrg = self->q_smooth_reverb_nrg; WORD32 parameter_bands = self->parameter_bands; WORD32 *p_output_real, *p_output_imag; WORD32 num_bands_2 = self->hybrid_bands; WORD32 v1, v2, v3, v4; WORD16 one_by_5 = ONE_BY_FIVE_Q16; duck_gain = scratch; q_duck_gain = (WORD16 *)scratch + PARAMETER_BANDSX2; p_input_real = input_real; p_input_imag = input_imag; p_output_real = output_real; p_output_imag = output_imag; for (ts = 0; ts < time_slots; ts++) { memset(direct_nrg, 0, sizeof(direct_nrg)); memset(reverb_nrg, 0, sizeof(reverb_nrg)); for (qs = 0; qs < num_bands_2; qs++) { v1 = p_input_real[qs]; v2 = p_input_imag[qs]; v3 = p_output_real[qs]; v4 = p_output_imag[qs]; pb = hybrid_2_param_28[qs]; direct_nrg[pb] += (WORD64)((WORD64)v1 * (WORD64)v1) + (WORD64)((WORD64)v2 * (WORD64)v2); reverb_nrg[pb] += (WORD64)((WORD64)v3 * (WORD64)v3) + (WORD64)((WORD64)v4 * (WORD64)v4); } for (pb = 0; pb < parameter_bands; pb++) { WORD16 qtemp, qtemp_1; temp_1 = ixheaacd_mps_narrow(direct_nrg[pb], &qtemp); temp_2 = smooth_direct_nrg[pb] << 2; temp3 = ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_direct_nrg[pb]), qtemp); smooth_direct_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5); temp_1 = ixheaacd_mps_narrow(reverb_nrg[pb], &qtemp); temp_2 = smooth_reverb_nrg[pb] << 2; temp3 = ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_reverb_nrg[pb]), qtemp); smooth_reverb_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5); qtemp1 = q_smooth_reverb_nrg[pb] - 1; temp_1 = (smooth_reverb_nrg[pb] >> 2) * 3; qtemp = q_smooth_direct_nrg[pb]; temp3 = smooth_direct_nrg[pb]; if (ixheaacd_mps_comp(temp3, temp_1, &qtemp, qtemp1)) { temp_2 = ixheaacd_mps_div_32(temp3, temp_1, &qtemp2); qtemp2 = qtemp2 + qtemp - qtemp1; temp3 = qtemp2 > 28 ? MAX_32 : 4 << qtemp2; if (temp_2 > temp3) { *duck_gain = 32767; *q_duck_gain++ = 14; } else { *duck_gain = ixheaacd_mps_sqrt(temp_2, &qtemp2, sqrt_tab); *q_duck_gain++ = qtemp2; } duck_gain++; continue; } *duck_gain = 16383; qtemp = q_smooth_direct_nrg[pb] - 1; temp_1 = (smooth_direct_nrg[pb] >> 2) * 3; qtemp_1 = q_smooth_reverb_nrg[pb]; temp_2 = smooth_reverb_nrg[pb]; if (ixheaacd_mps_comp(temp_2, temp_1, &(qtemp_1), qtemp)) { temp3 = ixheaacd_mps_div_32(temp_1, temp_2, &qtemp3); qtemp3 = qtemp3 + qtemp - qtemp_1; *duck_gain = ixheaacd_mps_sqrt(temp3, &qtemp3, sqrt_tab); *q_duck_gain = qtemp3; } duck_gain++; q_duck_gain++; } duck_gain -= parameter_bands; q_duck_gain -= parameter_bands; for (qs = 0; qs < num_bands_2; qs++) { pb = hybrid_2_param_28[qs]; gain = duck_gain[pb]; if (gain == 16383) { continue; } qgain = q_duck_gain[pb]; p_output_real[qs] = ixheaacd_mps_mult32_shr_n(p_output_real[qs], gain, qgain); p_output_imag[qs] = ixheaacd_mps_mult32_shr_n(p_output_imag[qs], gain, qgain); } p_input_real += MAX_HYBRID_BANDS; p_input_imag += MAX_HYBRID_BANDS; p_output_real += MAX_HYBRID_BANDS; p_output_imag += MAX_HYBRID_BANDS; } } static IA_ERRORCODE ixheaacd_ducker_create( ia_mps_dec_ducker_interface *const face, WORD32 const hybrid_bands) { ia_mps_dec_duck_instance_struct *self = NULL; IA_ERRORCODE error_code = IA_NO_ERROR; WORD32 i; if (face == NULL) { error_code = IA_FATAL_ERROR; } if (error_code == IA_NO_ERROR) { self = (ia_mps_dec_duck_instance_struct *)&face[1]; self->hybrid_bands = hybrid_bands; self->parameter_bands = MAX_PARAMETER_BANDS; self->alpha = DUCK_ALPHA; self->one_minus_alpha = DUCK_ONEMINUSALPHA; self->gamma = DUCK_GAMMA; self->abs_thr = ABS_THR_FIX; self->hybrid_bands = hybrid_bands; self->parameter_bands = MAX_PARAMETER_BANDS; self->qalpha = 15; self->qgamma = 14; if (hybrid_bands == 71) face->apply = ixheaacd_ducker_apply_71; else face->apply = ixheaacd_ducker_apply; for (i = 0; i < MAX_PARAMETER_BANDS; i++) { self->q_smooth_direct_nrg[i] = 31; self->q_smooth_reverb_nrg[i] = 31; } } return error_code; } IA_ERRORCODE ixheaacd_decorr_create( ia_mps_dec_decorr_dec_handle self, WORD32 subbands, WORD32 seed, WORD32 dec_type, WORD32 decorr_config, ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table_ptr) { IA_ERRORCODE error_code = IA_NO_ERROR; WORD32 i, reverb_band; const WORD32 *rev_split_freq; switch (decorr_config) { case DECOR_CONFIG_0: rev_split_freq = ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table.rev_split_freq_0; break; case DECOR_CONFIG_1: rev_split_freq = ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table.rev_split_freq_1; break; case DECOR_CONFIG_2: rev_split_freq = ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table.rev_split_freq_2; break; default: return IA_FATAL_ERROR; break; } if (error_code == IA_NO_ERROR) { self->decorr_seed = seed; self->numbins = subbands; for (i = 0; i < self->numbins; i++) { reverb_band = 0; while ((reverb_band < 3) && (ixheaacd_get_qmf_sb( i, ia_mps_dec_mps_table_ptr->mdct2qmf_table_ptr) >= (rev_split_freq[reverb_band] - 1))) reverb_band++; { self->no_sample_delay[i] = ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table .rev_delay[reverb_band][self->decorr_seed]; error_code = ixheaacd_decorr_filt_create( self->filter[i], self->decorr_seed, ixheaacd_get_qmf_sb(i, ia_mps_dec_mps_table_ptr->mdct2qmf_table_ptr), reverb_band, dec_type, ia_mps_dec_mps_table_ptr); } } if (error_code == IA_NO_ERROR) { error_code = ixheaacd_ducker_create(self->ducker, self->numbins); } } return (error_code); } VOID ixheaacd_decorr_apply(ia_heaac_mps_state_struct *pstr_mps_state, WORD32 length, WORD32 *input_real, WORD32 *input_imag, WORD32 *output_real, WORD32 *output_imag, WORD32 index) { WORD32 l = index - pstr_mps_state->num_direct_signals; ia_mps_dec_decorr_dec_handle decorr_ptr = pstr_mps_state->ap_decor[l]; WORD32 idx, sb_sample; WORD32 *p_input_real, *p_input_re, *p_input_imag, *p_input_im; WORD32 *p_output_real, *p_output_imag, *p_output_re, *p_output_im; WORD32 *delay_buffer_real, *delay_buffer_imag; WORD32 length1; VOID *free_scratch; free_scratch = (WORD32 *)pstr_mps_state->mps_scratch_mem_v + MAX_TIMESLOTSX2; if (decorr_ptr != NULL) { p_input_real = input_real; p_input_imag = input_imag; p_output_real = output_real; p_output_imag = output_imag; for (idx = 0; idx < decorr_ptr->numbins; idx++) { p_input_re = p_input_real; p_input_im = p_input_imag; p_output_re = p_output_real; p_output_im = p_output_imag; length1 = length - decorr_ptr->no_sample_delay[idx]; delay_buffer_real = &decorr_ptr->delay_buffer_real[idx][decorr_ptr->no_sample_delay[idx]]; delay_buffer_imag = &decorr_ptr->delay_buffer_imag[idx][decorr_ptr->no_sample_delay[idx]]; for (sb_sample = 0; sb_sample < length1; sb_sample++) { delay_buffer_real[sb_sample] = *p_input_re; *delay_buffer_imag++ = *p_input_im; p_input_re += MAX_HYBRID_BANDS; p_input_im += MAX_HYBRID_BANDS; } { ixheaacd_decorr_filt_apply( decorr_ptr->filter[idx], length, decorr_ptr->delay_buffer_real[idx], decorr_ptr->delay_buffer_imag[idx], p_output_re++, p_output_im++); } length1 = decorr_ptr->no_sample_delay[idx]; delay_buffer_real = &decorr_ptr->delay_buffer_real[idx][0]; delay_buffer_imag = &decorr_ptr->delay_buffer_imag[idx][0]; for (sb_sample = 0; sb_sample < length1; sb_sample++) { delay_buffer_real[sb_sample] = *p_input_re; p_input_re += MAX_HYBRID_BANDS; *delay_buffer_imag++ = *p_input_im; p_input_im += MAX_HYBRID_BANDS; } p_input_real++; p_input_imag++; p_output_real++; p_output_imag++; } decorr_ptr->ducker->apply(decorr_ptr->ducker, length, input_real, input_imag, output_real, output_imag, &(pstr_mps_state->ia_mps_dec_mps_table), free_scratch); } }