/****************************************************************************** * * 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 #include #include "impd_type_def.h" #include "impd_drc_extr_delta_coded_info.h" #include "impd_drc_common.h" #include "impd_drc_struct.h" #include "impd_drc_interface.h" #include "impd_drc_gain_dec.h" #include "impd_drc_eq.h" #define CONFIG_REAL_POLE 0 #define CONFIG_COMPLEX_POLE 1 #define CONFIG_REAL_ZERO_RADIUS_ONE 2 #define CONFIG_REAL_ZERO 3 #define CONFIG_GENERIC_ZERO 4 #define STEP_RATIO_F_LO 20.0f #define STEP_RATIO_F_HI 24000.0f #define STEP_RATIO_EQ_NODE_COUNT_MAX 33 #define FILTER_ELEMENT_FORMAT_POLE_ZERO 0 #define FILTER_ELEMENT_FORMAT_FIR 1 #ifndef M_PI #define M_PI (3.14159265358979323846) #endif WORD32 impd_derive_subband_center_freq(WORD32 eq_subband_gain_count, WORD32 eq_subband_gain_format, FLOAT32 sample_rate, FLOAT32* subband_center_freq) { WORD32 i; FLOAT32 width, offset; switch (eq_subband_gain_format) { case GAINFORMAT_QMF32: case GAINFORMAT_QMF64: case GAINFORMAT_QMF128: case GAINFORMAT_UNIFORM: width = 0.5f * sample_rate / (FLOAT32)eq_subband_gain_count; offset = 0.5f * width; for (i = 0; i < eq_subband_gain_count; i++) { subband_center_freq[i] = offset; offset = offset + width; } break; case GAINFORMAT_QMFHYBRID39: case GAINFORMAT_QMFHYBRID71: case GAINFORMAT_QMFHYBRID135: return (UNEXPECTED_ERROR); break; default: break; } return (0); } VOID impd_calc_fir_filt_response(WORD32 fir_order, WORD32 fir_symmetry, FLOAT32* coeff, FLOAT32 frequency_radian, FLOAT32* response) { WORD32 m; FLOAT32 sum = 0.0f; WORD32 o2; if ((fir_order & 0x1) == 0) { o2 = fir_order / 2; if (fir_symmetry == 0) { /*ITTIAM: sum is been over written after the loop None of the conformance streams with us entering this function*/ for (m = 1; m <= o2; m++) { sum += coeff[o2 - m] * (FLOAT32)cos(m * frequency_radian); } sum += sum; sum = coeff[o2]; } else { for (m = 1; m <= o2; m++) { sum += coeff[o2 - m] * (FLOAT32)sin(m * frequency_radian); } sum += sum; } } else { o2 = (fir_order + 1) / 2; if (fir_symmetry == 0) { for (m = 1; m <= o2; m++) { sum += coeff[o2 - m] * (FLOAT32)cos((m - 0.5f) * frequency_radian); } } else { for (m = 1; m <= o2; m++) { sum += coeff[o2 - m] * (FLOAT32)sin((m - 0.5f) * frequency_radian); } } sum += sum; } *response = sum; return; } VOID impd_calc_filt_ele_response(ia_unique_td_filt_element* element, FLOAT32 frequency_radian, FLOAT32* response) { WORD32 i; FLOAT32 part_response, radius, angle_radian; FLOAT64 total_response = 1.0; if (element->eq_filter_format == FILTER_ELEMENT_FORMAT_POLE_ZERO) { for (i = 0; i < element->bs_real_zero_radius_one_count; i++) { part_response = 1.0f + 1.0f - 2.0f * 1.0f * (FLOAT32)cos(frequency_radian - (FLOAT32)element->zero_sign[i]); total_response *= part_response; } for (i = 0; i < element->real_zero_count; i++) { if (element->real_zero_radius[i] < 0.0f) { radius = -element->real_zero_radius[i]; angle_radian = (FLOAT32)M_PI; } else { radius = element->real_zero_radius[i]; angle_radian = 0.0f; } part_response = 1.0f + radius * radius - 2.0f * radius * (FLOAT32)cos(frequency_radian - angle_radian); total_response *= part_response; part_response = 1.0f + radius * radius - 2.0f * radius * (FLOAT32)cos(frequency_radian - angle_radian); total_response *= part_response; } total_response = sqrt(total_response); for (i = 0; i < element->generic_zero_count; i++) { radius = element->generic_zero_radius[i]; part_response = 1.0f + radius * radius - 2.0f * radius * (FLOAT32)cos(frequency_radian - element->generic_zero_angle[i]); total_response *= part_response; part_response = 1.0f + radius * radius - 2.0f * radius * (FLOAT32)cos(frequency_radian - element->generic_zero_angle[i]); total_response *= part_response; } for (i = 0; i < element->real_pole_count; i++) { if (element->real_pole_radius[i] < 0.0f) { radius = -element->real_pole_radius[i]; angle_radian = (FLOAT32)(-M_PI); } else { radius = element->real_pole_radius[i]; angle_radian = 0.0f; } part_response = 1 / (1.0f + radius * radius - 2.0f * radius * (FLOAT32)cos(frequency_radian - angle_radian)); total_response *= part_response; } for (i = 0; i < element->cmplx_pole_count; i++) { part_response = 1 / (1.0f + element->real_pole_radius[i] * element->real_pole_radius[i] - 2.0f * element->real_pole_radius[i] * (FLOAT32)cos(frequency_radian - element->complex_pole_angle[i])); total_response *= part_response * part_response; } } else { impd_calc_fir_filt_response(element->fir_filt_order, element->fir_symmetry, element->fir_coeff, frequency_radian, &part_response); total_response *= part_response; } *response = (FLOAT32)total_response; return; } VOID impd_calc_filt_block_response( ia_unique_td_filt_element* unique_td_filt_ele, ia_filt_block_struct* str_filter_block, FLOAT32 frequency_radian, FLOAT32* response) { WORD32 i; FLOAT32 part_response; FLOAT64 total_response = 1.0; for (i = 0; i < str_filter_block->filter_element_count; i++) { ia_filt_ele_struct* str_filter_element = &str_filter_block->str_filter_element[i]; impd_calc_filt_ele_response( &(unique_td_filt_ele[str_filter_element->filt_ele_idx]), frequency_radian, &part_response); total_response *= part_response; if (str_filter_element->filt_ele_gain_flag == 1) { total_response *= pow(10.0f, 0.05f * str_filter_element->filt_ele_gain); } } *response = (FLOAT32)total_response; return; } WORD32 impd_calc_subband_gains_td_cascade( ia_unique_td_filt_element* unique_td_filt_ele, ia_filt_block_struct* str_filter_block, ia_td_filter_cascade_struct* str_td_filter_cascade, WORD32 eq_subband_gain_format, WORD32 eq_ch_group_count, FLOAT32 sample_rate, WORD32 eq_frame_size_subband, ia_subband_filt_struct* subband_filt) { WORD32 i, err = 0, g, b; FLOAT32 response, frequency_radian; FLOAT32 subband_center_freq[256]; FLOAT64 total_response; WORD32 eq_subband_gain_count = subband_filt->coeff_count; err = impd_derive_subband_center_freq(eq_subband_gain_count, eq_subband_gain_format, sample_rate, subband_center_freq); if (err) return (err); for (g = 0; g < eq_ch_group_count; g++) { for (b = 0; b < eq_subband_gain_count; b++) { total_response = pow(10.0f, 0.05f * str_td_filter_cascade->eq_cascade_gain[g]); frequency_radian = (FLOAT32)(2.0f * M_PI * subband_center_freq[b] / sample_rate); for (i = 0; i < str_td_filter_cascade->str_filter_block_refs[g].filter_block_count; i++) { impd_calc_filt_block_response( unique_td_filt_ele, &(str_filter_block[str_td_filter_cascade->str_filter_block_refs[g] .filter_block_index[i]]), frequency_radian, &response); total_response *= response; } subband_filt[g].subband_coeff[b] = (FLOAT32)total_response; } subband_filt[g].eq_frame_size_subband = eq_frame_size_subband; } return (0); } VOID impd_add_cascade(ia_cascade_align_group_struct* pstr_cascade_align_grp, WORD32 c1, WORD32 c2, WORD32* done) { WORD32 m, n; *done = 0; for (m = 0; m < pstr_cascade_align_grp->member_count; m++) { if (pstr_cascade_align_grp->member_idx[m] == c1) { for (n = 0; n < pstr_cascade_align_grp->member_count; n++) { if (pstr_cascade_align_grp->member_idx[n] == c2) { *done = 1; } } if (*done == 0) { pstr_cascade_align_grp ->member_idx[pstr_cascade_align_grp->member_count] = c2; pstr_cascade_align_grp->member_count++; *done = 1; } } } return; } VOID impd_calc_cascade_align_groups( WORD32 eq_ch_group_count, WORD32 eq_phase_alignment_present, WORD32 eq_phase_alignment[][EQ_CHANNEL_GROUP_COUNT_MAX], WORD32* cascade_align_grp_cnt, ia_cascade_align_group_struct* pstr_cascade_align_grp) { WORD32 i, k, g, group_count, done; group_count = 0; if (eq_phase_alignment_present == 0) { if (eq_ch_group_count > 1) { for (i = 0; i < eq_ch_group_count; i++) { pstr_cascade_align_grp[group_count].member_idx[i] = i; } pstr_cascade_align_grp[group_count].member_count = eq_ch_group_count; group_count = 1; } } else { for (i = 0; i < eq_ch_group_count; i++) { for (k = i + 1; k < eq_ch_group_count; k++) { if (eq_phase_alignment[i][k] == 1) { done = 0; for (g = 0; g < group_count; g++) { impd_add_cascade(&pstr_cascade_align_grp[g], i, k, &done); if (done == 0) { impd_add_cascade(&pstr_cascade_align_grp[g], k, i, &done); } } if (done == 0) { pstr_cascade_align_grp[group_count].member_idx[0] = i; pstr_cascade_align_grp[group_count].member_idx[1] = k; pstr_cascade_align_grp[group_count].member_count = 2; group_count++; } } } } } *cascade_align_grp_cnt = group_count; return; } VOID impd_calc_phase_filt_params( WORD32 config, FLOAT32 radius, FLOAT32 angle, ia_ph_alignment_filt_struct* ph_alignment_filt) { WORD32 channel; FLOAT32 zReal, zImag; FLOAT32 prod; WORD32 section = ph_alignment_filt->section_count; ia_filt_sect_struct* filt_section = &ph_alignment_filt->filt_section[section]; switch (config) { case CONFIG_REAL_POLE: ph_alignment_filt->gain *= (-radius); filt_section->a1 = -radius; filt_section->a2 = 0.0f; filt_section->b1 = -1.0f / radius; filt_section->b2 = 0.0f; ph_alignment_filt->section_count++; break; case CONFIG_COMPLEX_POLE: zReal = radius * (FLOAT32)cos(M_PI * angle); zImag = radius * (FLOAT32)sin(M_PI * angle); prod = zReal * zReal + zImag * zImag; ph_alignment_filt->gain *= prod; filt_section->a1 = -2.0f * zReal; filt_section->a2 = prod; filt_section->b1 = -2.0f * zReal / prod; filt_section->b2 = 1.0f / prod; ph_alignment_filt->section_count++; break; default: break; } for (channel = 0; channel < EQ_CHANNEL_COUNT_MAX; channel++) { filt_section->filt_sect_state[channel].in_state_1 = 0.0f; filt_section->filt_sect_state[channel].in_state_2 = 0.0f; filt_section->filt_sect_state[channel].out_state_1 = 0.0f; filt_section->filt_sect_state[channel].out_state_2 = 0.0f; } return; } VOID impd_calc_phase_filt_delay( ia_unique_td_filt_element* element, ia_ph_alignment_filt_struct* ph_alignment_filt) { WORD32 i, delay = 0, channel; if (element->eq_filter_format == FILTER_ELEMENT_FORMAT_POLE_ZERO) { if (element->bs_real_zero_radius_one_count == 0) { delay = element->real_zero_count + 2 * element->generic_zero_count - element->real_pole_count - 2 * element->cmplx_pole_count; delay = max(0, delay); ph_alignment_filt->validity_flag = 1; } } ph_alignment_filt->audio_delay.delay = delay; for (channel = 0; channel < EQ_CHANNEL_COUNT_MAX; channel++) { for (i = 0; i < delay; i++) { ph_alignment_filt->audio_delay.state[channel][i] = 0.0f; } } return; } VOID impd_calc_phase_filt(ia_unique_td_filt_element* element, WORD32 filt_ele_idx, ia_matching_ph_filt_struct* matching_ph_filt) { WORD32 i; memset(matching_ph_filt, 0, sizeof(ia_matching_ph_filt_struct)); matching_ph_filt->gain = 1.0f; if (element->eq_filter_format == FILTER_ELEMENT_FORMAT_POLE_ZERO) { for (i = 0; i < element->real_pole_count; i++) { impd_calc_phase_filt_params(CONFIG_REAL_POLE, element->real_pole_radius[i], 0.0f, matching_ph_filt); } for (i = 0; i < element->cmplx_pole_count; i++) { impd_calc_phase_filt_params( CONFIG_COMPLEX_POLE, element->complex_pole_radius[i], element->complex_pole_angle[i], matching_ph_filt); } } impd_calc_phase_filt_delay(element, matching_ph_filt); matching_ph_filt->num_matches_filter = 1; matching_ph_filt->matches_filter[0] = filt_ele_idx; return; } WORD32 impd_calc_filt_params(ia_unique_td_filt_element* element, ia_interm_filt_params_struct* interm_filt_params) { FLOAT32 zReal; FLOAT32* coeff; // WORD32 offset_idx = 0; WORD32 i; WORD32 param_idx = 0; ia_2nd_order_filt_params_struct* pstr_2nd_oder_filt_params = &interm_filt_params->ord_2_filt_params_of_zeros[0]; for (i = 0; i < element->bs_real_zero_radius_one_count; i += 2) { FLOAT32 radius = (FLOAT32)element->zero_sign[i + 0]; FLOAT32 angle = (FLOAT32)element->zero_sign[i + 1]; FLOAT32 angle1 = radius; FLOAT32 angle2 = angle; pstr_2nd_oder_filt_params->radius = 1.0f; coeff = pstr_2nd_oder_filt_params->coeff; if (angle1 != angle2) { coeff[0] = 0.0f; coeff[1] = -1.0f; } else if (angle1 == 1.0f) { coeff[0] = -2.0f; coeff[1] = 1.0f; } else { coeff[0] = 2.0f; coeff[1] = 1.0f; } pstr_2nd_oder_filt_params += 1; param_idx += 1; } for (i = 0; i < element->real_zero_count; i++) { FLOAT32 radius = element->real_zero_radius[i]; // FLOAT32 angle = 0.0f; pstr_2nd_oder_filt_params->radius = radius; if (fabs(radius) == 1.0f) { return (-1); } else { coeff = pstr_2nd_oder_filt_params->coeff; coeff[0] = -(radius + 1.0f / radius); coeff[1] = 1.0f; } pstr_2nd_oder_filt_params += 1; param_idx += 1; } for (i = 0; i < element->generic_zero_count; i++) { FLOAT32 radius = element->generic_zero_radius[i]; FLOAT32 angle = element->generic_zero_angle[i]; zReal = radius * (FLOAT32)cos(M_PI * angle); pstr_2nd_oder_filt_params->radius = radius; coeff = pstr_2nd_oder_filt_params->coeff; coeff[0] = -2.0f * zReal; coeff[1] = radius * radius; pstr_2nd_oder_filt_params += 1; zReal = (FLOAT32)cos(M_PI * angle) / radius; pstr_2nd_oder_filt_params->radius = radius; coeff = pstr_2nd_oder_filt_params->coeff; coeff[0] = -2.0f * zReal; coeff[1] = 1.0f / (radius * radius); pstr_2nd_oder_filt_params += 1; param_idx += 2; } interm_filt_params->filter_param_count_of_zeros = param_idx; param_idx = 0; pstr_2nd_oder_filt_params = &interm_filt_params->ord_2_filt_params_of_poles[0]; for (i = 0; i < element->real_pole_count; i++) { FLOAT32 radius = element->real_pole_radius[i]; pstr_2nd_oder_filt_params->radius = radius; coeff = pstr_2nd_oder_filt_params->coeff; coeff[0] = -2.0f * radius; coeff[1] = radius * radius; param_idx += 1; pstr_2nd_oder_filt_params += 1; } for (i = 0; i < element->cmplx_pole_count; i++) { FLOAT32 radius = element->complex_pole_radius[i]; FLOAT32 angle = element->complex_pole_angle[i]; zReal = radius * (FLOAT32)cos(M_PI * angle); pstr_2nd_oder_filt_params->radius = radius; coeff = pstr_2nd_oder_filt_params->coeff; coeff[0] = -2.0f * zReal; coeff[1] = radius * radius; pstr_2nd_oder_filt_params += 1; pstr_2nd_oder_filt_params->radius = radius; pstr_2nd_oder_filt_params->coeff[0] = coeff[0]; pstr_2nd_oder_filt_params->coeff[1] = coeff[1]; pstr_2nd_oder_filt_params += 1; param_idx += 2; } interm_filt_params->filter_param_count_of_poles = param_idx; return 0; } VOID impd_convert_fir_filt_params(WORD32 fir_filt_order, WORD32 fir_symmetry, FLOAT32* fir_coeff, ia_fir_filter_struct* fir_filter) { WORD32 i, channel; FLOAT32* coeff = fir_filter->coeff; fir_filter->coeff_count = fir_filt_order + 1; for (i = 0; i < fir_filt_order / 2 + 1; i++) { coeff[i] = fir_coeff[i]; } if (fir_symmetry == 1) { for (i = 0; i < (fir_filt_order + 1) / 2; i++) { coeff[fir_filt_order - i] = -coeff[i]; } if ((fir_filt_order & 1) == 0) { coeff[fir_filt_order / 2] = 0.0f; } } else { for (i = 0; i < (fir_filt_order + 1) / 2; i++) { coeff[fir_filt_order - i] = coeff[i]; } } for (channel = 0; channel < EQ_CHANNEL_COUNT_MAX; channel++) { for (i = 0; i < fir_filt_order + 1; i++) { fir_filter->state[channel][i] = 0.0f; } } return; } WORD32 impd_calc_filt_params_all( ia_unique_td_filt_element* element, ia_interm_filt_params_struct* interm_filt_params) { WORD32 err = 0; interm_filt_params->filter_format = element->eq_filter_format; if (element->eq_filter_format == FILTER_ELEMENT_FORMAT_POLE_ZERO) { err = impd_calc_filt_params(element, interm_filt_params); if (err) return err; } else { interm_filt_params->filter_param_count_of_zeros = 0; interm_filt_params->filter_param_count_of_poles = 0; impd_convert_fir_filt_params(element->fir_filt_order, element->fir_symmetry, element->fir_coeff, &interm_filt_params->fir_filter); } return (0); } VOID impd_calc_eq_filt_elements( ia_interm_filt_params_struct* interm_filt_params, ia_eq_filt_ele_struct* eq_filt_element) { WORD32 i, poles_idx, zeros_idx, pole_order = 0, section, channel; WORD32 poles_over[REAL_POLE_COUNT_MAX + COMPLEX_POLE_COUNT_MAX]; WORD32 zeros_over[REAL_ZERO_COUNT_MAX + COMPLEX_ZERO_COUNT_MAX]; FLOAT32 max_radius, diff_radius; WORD32 coeff_count; FLOAT32* coeff; for (i = 0; i < REAL_POLE_COUNT_MAX + COMPLEX_POLE_COUNT_MAX; i++) { poles_over[i] = 0; } for (i = 0; i < REAL_ZERO_COUNT_MAX + COMPLEX_ZERO_COUNT_MAX; i++) { zeros_over[i] = 0; } section = 0; do { max_radius = -1.0; poles_idx = -1; for (i = 0; i < interm_filt_params->filter_param_count_of_poles; i++) { if (poles_over[i] == 0) { if (interm_filt_params->filter_format == 0) { if (max_radius < fabs(interm_filt_params->ord_2_filt_params_of_poles[i].radius)) { max_radius = (FLOAT32)fabs( interm_filt_params->ord_2_filt_params_of_poles[i].radius); poles_idx = i; if (interm_filt_params->ord_2_filt_params_of_poles[i].coeff[1] != 0.0f) { pole_order = 2; } else { pole_order = 1; } } } } } if (poles_idx >= 0) { diff_radius = 10.0f; zeros_idx = -1; for (i = 0; i < interm_filt_params->filter_param_count_of_zeros; i++) { if (zeros_over[i] == 0) { if (interm_filt_params->filter_format == 0) { if (pole_order == 2) { if (interm_filt_params->ord_2_filt_params_of_zeros[i].coeff[1] != 0.0f) { if (diff_radius > fabs(fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius)) { diff_radius = (FLOAT32)fabs( fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius); zeros_idx = i; } } } else { if (interm_filt_params->ord_2_filt_params_of_zeros[i].coeff[1] == 0.0f) { if (diff_radius > (FLOAT32)(fabs( fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius))) { diff_radius = (FLOAT32)(fabs( fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius)); zeros_idx = i; } } } } } } if (zeros_idx == -1) { for (i = 0; i < interm_filt_params->filter_param_count_of_zeros; i++) { if (zeros_over[i] == 0) { if (interm_filt_params->filter_format == 0) { if (pole_order == 2) { if (interm_filt_params->ord_2_filt_params_of_zeros[i] .coeff[1] == 0.0f) { if (diff_radius > (FLOAT32)(fabs( fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius))) { diff_radius = (FLOAT32)(fabs( fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius)); zeros_idx = i; } } } else { if (interm_filt_params->ord_2_filt_params_of_zeros[i] .coeff[1] != 0.0f) { if (diff_radius > (FLOAT32)(fabs( fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius))) { diff_radius = (FLOAT32)(fabs( fabs(interm_filt_params->ord_2_filt_params_of_zeros[i] .radius) - max_radius)); zeros_idx = i; } } } } } } } eq_filt_element->pstr_pole_zero_filt.filt_section[section].a1 = interm_filt_params->ord_2_filt_params_of_poles[poles_idx].coeff[0]; eq_filt_element->pstr_pole_zero_filt.filt_section[section].a2 = interm_filt_params->ord_2_filt_params_of_poles[poles_idx].coeff[1]; if (zeros_idx >= 0) { eq_filt_element->pstr_pole_zero_filt.filt_section[section].b1 = interm_filt_params->ord_2_filt_params_of_zeros[zeros_idx].coeff[0]; eq_filt_element->pstr_pole_zero_filt.filt_section[section].b2 = interm_filt_params->ord_2_filt_params_of_zeros[zeros_idx].coeff[1]; } else { eq_filt_element->pstr_pole_zero_filt.filt_section[section].b1 = 0.0f; eq_filt_element->pstr_pole_zero_filt.filt_section[section].b2 = 0.0f; eq_filt_element->pstr_pole_zero_filt.audio_delay.delay++; } for (channel = 0; channel < EQ_CHANNEL_COUNT_MAX; channel++) { eq_filt_element->pstr_pole_zero_filt.filt_section[section] .filt_sect_state[channel] .in_state_1 = 0.0f; eq_filt_element->pstr_pole_zero_filt.filt_section[section] .filt_sect_state[channel] .in_state_2 = 0.0f; eq_filt_element->pstr_pole_zero_filt.filt_section[section] .filt_sect_state[channel] .out_state_1 = 0.0f; eq_filt_element->pstr_pole_zero_filt.filt_section[section] .filt_sect_state[channel] .out_state_2 = 0.0f; } if (zeros_idx >= 0) zeros_over[zeros_idx] = 1; if (poles_idx >= 0) poles_over[poles_idx] = 1; section++; } } while (poles_idx >= 0); eq_filt_element->pstr_pole_zero_filt.section_count = section; coeff_count = 1; coeff = eq_filt_element->pstr_pole_zero_filt.fir_filter.coeff; coeff[0] = 1.0f; for (i = 0; i < interm_filt_params->filter_param_count_of_zeros; i++) { if (zeros_over[i] == 0) { if (interm_filt_params->filter_format == 0) { WORD32 k; FLOAT32 b1, b2; b1 = interm_filt_params->ord_2_filt_params_of_zeros[i].coeff[0]; b2 = interm_filt_params->ord_2_filt_params_of_zeros[i].coeff[1]; coeff_count += 2; k = coeff_count - 1; coeff[k] = b2 * coeff[k - 2]; k--; if (k > 1) { coeff[k] = b1 * coeff[k - 1] + b2 * coeff[k - 2]; k--; for (; k > 1; k--) { coeff[k] += b1 * coeff[k - 1] + b2 * coeff[k - 2]; } coeff[1] += b1 * coeff[0]; } else { coeff[1] = b1 * coeff[0]; } } } zeros_over[i] = 1; } if (coeff_count > 1) { eq_filt_element->pstr_pole_zero_filt.filt_coeffs_flag = 1; eq_filt_element->pstr_pole_zero_filt.fir_filter.coeff_count = coeff_count; } else { eq_filt_element->pstr_pole_zero_filt.filt_coeffs_flag = 0; eq_filt_element->pstr_pole_zero_filt.fir_filter.coeff_count = 0; } return; } WORD32 impd_calc_filt_block(ia_unique_td_filt_element* unique_td_filt_ele, ia_filt_block_struct* str_filter_block, ia_eq_filt_block_struct* pstr_eq_filt_block) { WORD32 i, k, err; ia_interm_filt_params_struct interm_filt_params; ia_matching_ph_filt_struct matching_ph_filt[FILTER_ELEMENT_COUNT_MAX]; for (i = 0; i < str_filter_block->filter_element_count; i++) { if ((unique_td_filt_ele[str_filter_block->str_filter_element[i] .filt_ele_idx] .eq_filter_format == FILTER_ELEMENT_FORMAT_FIR) && (str_filter_block->filter_element_count > 1)) { return (-1); } } for (i = 0; i < str_filter_block->filter_element_count; i++) { ia_eq_filt_ele_struct* eq_filt_element = &pstr_eq_filt_block->eq_filt_element[i]; ia_filt_ele_struct* str_filter_element = &str_filter_block->str_filter_element[i]; WORD32 filterIndex = str_filter_element->filt_ele_idx; if (unique_td_filt_ele[filterIndex].eq_filter_format == FILTER_ELEMENT_FORMAT_POLE_ZERO) { err = impd_calc_filt_params_all(&(unique_td_filt_ele[filterIndex]), &interm_filt_params); if (err) return (err); impd_calc_eq_filt_elements(&interm_filt_params, eq_filt_element); eq_filt_element->format = FILTER_ELEMENT_FORMAT_POLE_ZERO; } else { impd_convert_fir_filt_params( unique_td_filt_ele[filterIndex].fir_filt_order, unique_td_filt_ele[filterIndex].fir_symmetry, unique_td_filt_ele[filterIndex].fir_coeff, &eq_filt_element->fir_filter); eq_filt_element->format = FILTER_ELEMENT_FORMAT_FIR; } if (str_filter_element->filt_ele_gain_flag == 1) { eq_filt_element->elementGainLinear = (FLOAT32)(pow(10.0f, 0.05f * str_filter_element->filt_ele_gain)); } else { eq_filt_element->elementGainLinear = 1.0f; } for (k = 0; k < unique_td_filt_ele[filterIndex].real_zero_count; k++) { if (unique_td_filt_ele[filterIndex].real_zero_radius[k] > 0.0f) { eq_filt_element->elementGainLinear = -eq_filt_element->elementGainLinear; } } impd_calc_phase_filt(&(unique_td_filt_ele[filterIndex]), i, &matching_ph_filt[i]); } pstr_eq_filt_block->element_count = str_filter_block->filter_element_count; pstr_eq_filt_block->matching_ph_filt_ele_0 = matching_ph_filt[0]; return (0); } VOID impd_calc_cascade_phase_align_filt( ia_td_filter_cascade_struct* str_td_filter_cascade, WORD32 ch_group_cnt) { // WORD32 err = 0; WORD32 cascade_align_grp_cnt = 0; ia_cascade_align_group_struct pstr_cascade_align_grp[EQ_CHANNEL_GROUP_COUNT_MAX / 2]; impd_calc_cascade_align_groups( ch_group_cnt, str_td_filter_cascade->eq_phase_alignment_present, str_td_filter_cascade->eq_phase_alignment, &cascade_align_grp_cnt, pstr_cascade_align_grp); return; } WORD32 impd_calc_filt_cascade( ia_unique_td_filt_element* unique_td_filt_ele, ia_filt_block_struct* str_filter_block, ia_td_filter_cascade_struct* str_td_filter_cascade, WORD32 ch_group_cnt, ia_filt_cascade_td_struct filt_cascade_td[]) { WORD32 i, err, g; for (g = 0; g < ch_group_cnt; g++) { for (i = 0; i < str_td_filter_cascade->str_filter_block_refs[g].filter_block_count; i++) { err = impd_calc_filt_block( unique_td_filt_ele, &(str_filter_block[str_td_filter_cascade->str_filter_block_refs[g] .filter_block_index[i]]), &(filt_cascade_td[g].pstr_eq_filt_block[i])); if (err) return (err); } filt_cascade_td[g].block_count = i; filt_cascade_td[g].cascade_gain_linear = (FLOAT32)( pow(10.0f, 0.05f * str_td_filter_cascade->eq_cascade_gain[g])); } impd_calc_cascade_phase_align_filt(str_td_filter_cascade, ch_group_cnt); return (0); } VOID impd_calc_subband_eq(ia_eq_subband_gain_vector* str_eq_subband_gain_vector, WORD32 eq_subband_gain_count, ia_subband_filt_struct* subband_filt) { WORD32 i; for (i = 0; i < eq_subband_gain_count; i++) { subband_filt->subband_coeff[i] = str_eq_subband_gain_vector->eq_subband_gain[i]; } subband_filt->coeff_count = eq_subband_gain_count; return; } FLOAT32 impd_decode_eq_node_freq(WORD32 eq_node_freq_idx) { /*((FLOAT32)((log10(STEP_RATIO_F_HI) / log10(STEP_RATIO_F_LO) - 1.0f) / * (STEP_RATIO_EQ_NODE_COUNT_MAX - 1.0f)))*/ FLOAT32 step_ratio = 0.0739601809794f; return ( (FLOAT32)(pow(STEP_RATIO_F_LO, 1.0f + eq_node_freq_idx * step_ratio))); } FLOAT32 impd_calc_warp_freq_delta(FLOAT32 fsubband, FLOAT32 node_freq, WORD32 eq_node_freq_idx) { /*((FLOAT32)((log10(STEP_RATIO_F_HI) / log10(STEP_RATIO_F_LO) - 1.0f) / * (STEP_RATIO_EQ_NODE_COUNT_MAX - 1.0f)))*/ FLOAT32 step_ratio = 0.0739601809794f; return ((FLOAT32)((log10(fsubband) / log10(node_freq) - 1.0f) / step_ratio - (FLOAT32)eq_node_freq_idx)); } VOID impd_interpolate_eq_gain(WORD32 band_step, FLOAT32 left_gain, FLOAT32 right_gain, FLOAT32 left_slope, FLOAT32 right_slope, FLOAT32 f, FLOAT32* interpolated_gain) { FLOAT32 k1, k2, a, b, c, d; FLOAT32 inv_band_step = (FLOAT32)(1.0 / (FLOAT32)band_step); FLOAT32 inv_band_step_sqr = inv_band_step * inv_band_step; k1 = (right_gain - left_gain) * inv_band_step_sqr; left_slope = (FLOAT32)(left_slope / 3.128f); right_slope = (FLOAT32)(right_slope / 3.128f); k2 = right_slope + left_slope; a = inv_band_step * (inv_band_step * k2 - 2.0f * k1); b = 3.0f * k1 - inv_band_step * (k2 + left_slope); c = left_slope; d = left_gain; *interpolated_gain = (((a * f + b) * f + c) * f) + d; return; } WORD32 impd_interpolate_subband_spline( ia_eq_subband_gain_spline_struct* str_eq_subband_gain_spline, WORD32 eq_subband_gain_count, WORD32 eq_subband_gain_format, FLOAT32 sample_rate, ia_subband_filt_struct* subband_filt) { WORD32 b, n, err; FLOAT32 eq_gain[32]; WORD32 eq_node_freq_idx[32]; FLOAT32 eq_node_freq[32]; FLOAT32 subband_center_freq[256]; WORD32 num_eq_nodes = str_eq_subband_gain_spline->num_eq_nodes; FLOAT32* eq_slope = str_eq_subband_gain_spline->eq_slope; WORD32* eq_freq_delta = str_eq_subband_gain_spline->eq_freq_delta; FLOAT32 eq_gain_initial = str_eq_subband_gain_spline->eq_gain_initial; FLOAT32* eq_gain_delta = str_eq_subband_gain_spline->eq_gain_delta; FLOAT32* subband_coeff = subband_filt->subband_coeff; WORD32 max_eq_node_idx = 32; eq_gain[0] = eq_gain_initial; eq_node_freq_idx[0] = 0; eq_node_freq[0] = impd_decode_eq_node_freq(eq_node_freq_idx[0]); for (n = 1; n < num_eq_nodes; n++) { eq_gain[n] = eq_gain[n - 1] + eq_gain_delta[n]; eq_node_freq_idx[n] = eq_node_freq_idx[n - 1] + eq_freq_delta[n]; eq_node_freq[n] = impd_decode_eq_node_freq(eq_node_freq_idx[n]); } if ((eq_node_freq[num_eq_nodes - 1] < sample_rate * 0.5f) && (eq_node_freq_idx[num_eq_nodes - 1] < max_eq_node_idx)) { eq_slope[num_eq_nodes] = 0; eq_gain[num_eq_nodes] = eq_gain[num_eq_nodes - 1]; eq_freq_delta[num_eq_nodes] = max_eq_node_idx - eq_node_freq_idx[num_eq_nodes - 1]; eq_node_freq_idx[num_eq_nodes] = max_eq_node_idx; eq_node_freq[num_eq_nodes] = impd_decode_eq_node_freq(eq_node_freq_idx[num_eq_nodes]); num_eq_nodes += 1; } err = impd_derive_subband_center_freq(eq_subband_gain_count, eq_subband_gain_format, sample_rate, subband_center_freq); if (err) return (err); for (n = 0; n < num_eq_nodes - 1; n++) { for (b = 0; b < eq_subband_gain_count; b++) { FLOAT32 fSub; fSub = max(subband_center_freq[b], eq_node_freq[0]); fSub = min(fSub, eq_node_freq[num_eq_nodes - 1]); if ((fSub >= eq_node_freq[n]) && (fSub <= eq_node_freq[n + 1])) { FLOAT32 warpedDeltaFreq = impd_calc_warp_freq_delta( fSub, eq_node_freq[0], eq_node_freq_idx[n]); FLOAT32 gEqSubbandDb; impd_interpolate_eq_gain(eq_freq_delta[n + 1], eq_gain[n], eq_gain[n + 1], eq_slope[n], eq_slope[n + 1], warpedDeltaFreq, &gEqSubbandDb); subband_coeff[b] = (FLOAT32)pow(2.0, gEqSubbandDb / 6.0f); } } } subband_filt->coeff_count = eq_subband_gain_count; return (0); } WORD32 impd_calc_subband_gains(ia_eq_coeff_struct* str_eq_coeff, WORD32 eq_ch_group_count, WORD32* subband_gains_index, FLOAT32 sample_rate, WORD32 eq_frame_size_subband, ia_subband_filt_struct* subband_filt) { WORD32 g, err; WORD32 eq_subband_gain_representation = str_eq_coeff->eq_subband_gain_representation; WORD32 eq_subband_gain_count = str_eq_coeff->eq_subband_gain_count; WORD32 eq_subband_gain_format = str_eq_coeff->eq_subband_gain_format; for (g = 0; g < eq_ch_group_count; g++) { if (eq_subband_gain_representation == 1) { err = impd_interpolate_subband_spline( &(str_eq_coeff->str_eq_subband_gain_spline[subband_gains_index[g]]), eq_subband_gain_count, eq_subband_gain_format, sample_rate, &(subband_filt[g])); if (err) return (err); } else { impd_calc_subband_eq( &(str_eq_coeff->str_eq_subband_gain_vector[subband_gains_index[g]]), eq_subband_gain_count, &(subband_filt[g])); } subband_filt[g].eq_frame_size_subband = eq_frame_size_subband; } return (0); } VOID impd_calc_filt_sect_delay(WORD32 section_count, ia_filt_sect_struct* filt_section, FLOAT32* delay) { WORD32 i; FLOAT32 d = 0.0f; for (i = 0; i < section_count; i++) { if (filt_section[i].b2 != 0.0f) { d += 1.0f; } else if (filt_section[i].b1 != 0.0f) { d += 0.5f; } } *delay = d; return; } VOID impd_get_eq_set_delay(ia_eq_set_struct* eq_set, WORD32* cascade_delay) { FLOAT32 delay, sect_delay; WORD32 k, g, b; delay = 0; g = eq_set->eq_ch_group_of_channel[0]; if (g >= 0) { switch (eq_set->domain) { case EQ_FILTER_DOMAIN_TIME: { ia_filt_cascade_td_struct* filt_cascade_td = &eq_set->filt_cascade_td[g]; for (b = 0; b < filt_cascade_td->block_count; b++) { ia_eq_filt_ele_struct* eq_filt_element = &filt_cascade_td->pstr_eq_filt_block[b].eq_filt_element[0]; switch (eq_filt_element->format) { case FILTER_ELEMENT_FORMAT_POLE_ZERO: impd_calc_filt_sect_delay( eq_filt_element->pstr_pole_zero_filt.section_count, eq_filt_element->pstr_pole_zero_filt.filt_section, §_delay); delay += sect_delay; if (eq_filt_element->pstr_pole_zero_filt.filt_coeffs_flag) { delay += 0.5f * (eq_filt_element->pstr_pole_zero_filt.fir_filter .coeff_count - 1); } break; case FILTER_ELEMENT_FORMAT_FIR: delay += 0.5f * (eq_filt_element->fir_filter.coeff_count - 1); break; default: break; } for (k = 0; k < eq_filt_element->num_ph_align_filt; k++) { ia_ph_alignment_filt_struct* ph_alignment_filt = &eq_filt_element->ph_alignment_filt[k]; impd_calc_filt_sect_delay(ph_alignment_filt->section_count, ph_alignment_filt->filt_section, §_delay); delay += sect_delay; } } for (b = 0; b < filt_cascade_td->num_ph_align_filt; b++) { ia_ph_alignment_filt_struct* ph_alignment_filt = &filt_cascade_td->ph_alignment_filt[b]; impd_calc_filt_sect_delay(ph_alignment_filt->section_count, ph_alignment_filt->filt_section, §_delay); delay += sect_delay; } } break; case EQ_FILTER_DOMAIN_SUBBAND: case EQ_FILTER_DOMAIN_NONE: default: break; } } *cascade_delay = (WORD32)delay; return; } WORD32 impd_derive_eq_set(ia_eq_coeff_struct* str_eq_coeff, ia_eq_instructions_struct* str_eq_instructions, FLOAT32 sample_rate, WORD32 drc_frame_size, WORD32 sub_band_domain_mode, ia_eq_set_struct* eq_set) { WORD32 err, i, eq_frame_size_subband; eq_set->domain = EQ_FILTER_DOMAIN_NONE; if (sub_band_domain_mode == SUBBAND_DOMAIN_MODE_OFF) { if (str_eq_instructions->td_filter_cascade_present == 1) { err = impd_calc_filt_cascade( str_eq_coeff->unique_td_filt_ele, str_eq_coeff->str_filter_block, &str_eq_instructions->str_td_filter_cascade, str_eq_instructions->eq_ch_group_count, eq_set->filt_cascade_td); if (err) return (err); } eq_set->domain |= EQ_FILTER_DOMAIN_TIME; } if (sub_band_domain_mode != SUBBAND_DOMAIN_MODE_OFF) { switch (sub_band_domain_mode) { case SUBBAND_DOMAIN_MODE_QMF64: if (str_eq_coeff->eq_subband_gain_count != AUDIO_CODEC_SUBBAND_COUNT_QMF64) { return (-1); } eq_frame_size_subband = drc_frame_size / AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR_QMF64; break; case SUBBAND_DOMAIN_MODE_QMF71: if (str_eq_coeff->eq_subband_gain_count != AUDIO_CODEC_SUBBAND_COUNT_QMF71) { return (-1); } eq_frame_size_subband = drc_frame_size / AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR_QMF71; break; case SUBBAND_DOMAIN_MODE_STFT256: if (str_eq_coeff->eq_subband_gain_count != AUDIO_CODEC_SUBBAND_COUNT_STFT256) { return (-1); } eq_frame_size_subband = drc_frame_size / AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR_STFT256; break; default: return (-1); break; } if (str_eq_instructions->subband_gains_present == 1) { err = impd_calc_subband_gains( str_eq_coeff, str_eq_instructions->eq_ch_group_count, str_eq_instructions->subband_gains_index, sample_rate, eq_frame_size_subband, eq_set->subband_filt); if (err) return (err); } else { if (str_eq_instructions->td_filter_cascade_present == 1) { err = impd_calc_subband_gains_td_cascade( str_eq_coeff->unique_td_filt_ele, str_eq_coeff->str_filter_block, &str_eq_instructions->str_td_filter_cascade, str_eq_coeff->eq_subband_gain_format, str_eq_instructions->eq_ch_group_count, sample_rate, eq_frame_size_subband, eq_set->subband_filt); if (err) return (err); } } eq_set->domain |= EQ_FILTER_DOMAIN_SUBBAND; } eq_set->audio_num_chan = str_eq_instructions->eq_channel_count; eq_set->eq_ch_group_count = str_eq_instructions->eq_ch_group_count; for (i = 0; i < str_eq_instructions->eq_channel_count; i++) { eq_set->eq_ch_group_of_channel[i] = str_eq_instructions->eq_ch_group_of_channel[i]; } return (0); } VOID impd_process_filt_sect( ia_filt_sect_struct filt_section[EQ_FILTER_SECTION_COUNT_MAX], WORD32 channel, FLOAT32* audio_out, WORD32 section_count) { WORD32 i; for (i = 0; i < section_count; i++) { ia_filt_sect_state_struct* filt_sect_state = &filt_section[i].filt_sect_state[channel]; FLOAT32 audio_in = *audio_out; *audio_out = audio_in + filt_section[i].b1 * filt_sect_state->in_state_1 + filt_section[i].b2 * filt_sect_state->in_state_2 - filt_section[i].a1 * filt_sect_state->out_state_1 - filt_section[i].a2 * filt_sect_state->out_state_2; filt_sect_state->in_state_2 = filt_sect_state->in_state_1; filt_sect_state->in_state_1 = audio_in; filt_sect_state->out_state_2 = filt_sect_state->out_state_1; filt_sect_state->out_state_1 = *audio_out; } return; } VOID impd_fir_filt_process(ia_fir_filter_struct* fir_filter, WORD32 channel, FLOAT32 audio_in, FLOAT32* audio_out) { WORD32 i; FLOAT32* coeff = fir_filter->coeff; FLOAT32* state = fir_filter->state[channel]; FLOAT32 sum; sum = coeff[0] * audio_in; for (i = 1; i < fir_filter->coeff_count; i++) { sum += coeff[i] * state[i - 1]; } *audio_out = sum; for (i = fir_filter->coeff_count - 2; i > 0; i--) { state[i] = state[i - 1]; } state[0] = audio_in; return; } VOID impd_audio_delay_process(ia_audio_delay_struct* audio_delay, WORD32 channel, FLOAT32 audio_in, FLOAT32* ptr_audio_out) { WORD32 i; FLOAT32* state = audio_delay->state[channel]; if (audio_delay->delay > 0) { *ptr_audio_out = state[audio_delay->delay - 1]; for (i = audio_delay->delay - 1; i > 0; i--) { state[i] = state[i - 1]; } state[0] = audio_in; } else { *ptr_audio_out = audio_in; } return; } VOID impd_pole_zero_filt_process(ia_pole_zero_filt_struct* pstr_pole_zero_filt, WORD32 channel, FLOAT32 audio_in, FLOAT32* ptr_audio_out) { FLOAT32 inp = audio_in; FLOAT32 out = inp; impd_process_filt_sect(pstr_pole_zero_filt->filt_section, channel, &out, pstr_pole_zero_filt->section_count); inp = out; if (pstr_pole_zero_filt->filt_coeffs_flag == 1) { impd_fir_filt_process(&pstr_pole_zero_filt->fir_filter, channel, inp, &out); inp = out; } impd_audio_delay_process(&pstr_pole_zero_filt->audio_delay, channel, inp, &out); *ptr_audio_out = out; return; } VOID impd_subband_filter_process(ia_subband_filt_struct* pstr_subband_filt, FLOAT32* ptr_audio_real_buff, FLOAT32* ptr_audio_imag_buff) { WORD32 i, j; WORD32 eq_frame_size_subband = pstr_subband_filt->eq_frame_size_subband; WORD32 coeff_count = pstr_subband_filt->coeff_count; FLOAT32* ptr_subband_coeff = pstr_subband_filt->subband_coeff; for (i = 0; i < eq_frame_size_subband; i++) { for (j = 0; j < coeff_count; j++) { ptr_audio_real_buff[j] *= ptr_subband_coeff[j]; ptr_audio_imag_buff[j] *= ptr_subband_coeff[j]; } ptr_audio_real_buff += coeff_count; ptr_audio_imag_buff += coeff_count; } return; } VOID impd_phase_align_filt_process( ia_ph_alignment_filt_struct* ph_alignment_filt, WORD32 channel, FLOAT32* ptr_audio_out) { FLOAT32 audio_in = *ptr_audio_out; FLOAT32 inp = audio_in; FLOAT32 out = inp; impd_process_filt_sect(ph_alignment_filt->filt_section, channel, &out, ph_alignment_filt->section_count); inp = out; impd_audio_delay_process(&ph_alignment_filt->audio_delay, channel, inp, &out); *ptr_audio_out = out * ph_alignment_filt->gain; return; } VOID impd_eq_filt_element_process( ia_eq_filt_block_struct str_eq_filt_block[EQ_FILTER_BLOCK_COUNT_MAX], WORD32 channel, FLOAT32 audio_in, FLOAT32* ptr_audio_out, WORD32 block_count) { WORD32 i; FLOAT32 inp = audio_in; FLOAT32 out = inp; WORD32 k, j; WORD32 element_count; for (j = 0; j < block_count; j++) { FLOAT32 sum = 0.0f; element_count = str_eq_filt_block[j].element_count; for (k = 0; k < element_count; k++) { switch (str_eq_filt_block[j].eq_filt_element[k].format) { case FILTER_ELEMENT_FORMAT_POLE_ZERO: impd_pole_zero_filt_process( &str_eq_filt_block[j].eq_filt_element[k].pstr_pole_zero_filt, channel, inp, &out); break; case FILTER_ELEMENT_FORMAT_FIR: impd_fir_filt_process( &str_eq_filt_block[j].eq_filt_element[k].fir_filter, channel, inp, &out); break; default: break; } out *= str_eq_filt_block[j].eq_filt_element[k].elementGainLinear; for (i = 0; i < str_eq_filt_block[j].eq_filt_element[k].num_ph_align_filt; i++) { inp = out; impd_phase_align_filt_process( &str_eq_filt_block[j].eq_filt_element[k].ph_alignment_filt[i], channel, &out); } sum += out; } inp = sum; } *ptr_audio_out = inp; return; } WORD32 impd_process_eq_set_time_domain(ia_eq_set_struct* pstr_eq_set, WORD32 channel, FLOAT32* ptr_audio_in, FLOAT32* ptr_audio_out, WORD32 frame_size) { WORD32 i, j, g = 0; if (pstr_eq_set == NULL) return 0; g = pstr_eq_set->eq_ch_group_of_channel[channel]; if (g < 0) return 0; for (i = 0; i < frame_size; i++) { impd_eq_filt_element_process( (pstr_eq_set->filt_cascade_td[g].pstr_eq_filt_block), channel, ptr_audio_in[i], &ptr_audio_out[i], pstr_eq_set->filt_cascade_td[g].block_count); for (j = 0; j < pstr_eq_set->filt_cascade_td[g].num_ph_align_filt; j++) { impd_phase_align_filt_process( &pstr_eq_set->filt_cascade_td[g].ph_alignment_filt[j], channel, &ptr_audio_out[i]); } ptr_audio_out[i] = ptr_audio_out[i] * pstr_eq_set->filt_cascade_td[g].cascade_gain_linear; } return 0; } WORD32 impd_process_eq_set_subband_domain(ia_eq_set_struct* pstr_eq_set, WORD32 channel, FLOAT32* ptr_audio_real_buff, FLOAT32* ptr_audio_imag_buff) { WORD32 g; if (pstr_eq_set != NULL) { g = pstr_eq_set->eq_ch_group_of_channel[channel]; if (g >= 0) { if (pstr_eq_set->domain == 0) { return (-1); } else { impd_subband_filter_process(&pstr_eq_set->subband_filt[g], &ptr_audio_real_buff[0], &ptr_audio_imag_buff[0]); } } } return (0); }