xref: /aosp_15_r20/external/libxaac/encoder/drc_src/impd_drc_uni_drc_eq.c (revision 15dc779a375ca8b5125643b829a8aa4b70d7f451)
1 /******************************************************************************
2  *                                                                            *
3  * Copyright (C) 2023 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19  */
20 
21 #include <math.h>
22 #include <string.h>
23 #include "ixheaac_type_def.h"
24 #include "ixheaac_error_standards.h"
25 #include "ixheaace_error_codes.h"
26 
27 #include "impd_drc_common_enc.h"
28 #include "impd_drc_uni_drc.h"
29 #include "impd_drc_uni_drc_eq.h"
30 
impd_drc_derive_subband_center_freq(const WORD32 eq_subband_gain_count,const WORD32 eq_subband_gain_format,const FLOAT32 audio_sample_rate,FLOAT32 * ptr_subband_center_freq)31 static IA_ERRORCODE impd_drc_derive_subband_center_freq(const WORD32 eq_subband_gain_count,
32                                                         const WORD32 eq_subband_gain_format,
33                                                         const FLOAT32 audio_sample_rate,
34                                                         FLOAT32 *ptr_subband_center_freq) {
35   LOOPIDX idx;
36   FLOAT32 width, offset;
37 
38   switch (eq_subband_gain_format) {
39     case GAINFORMAT_QMF32:
40     case GAINFORMAT_QMF64:
41     case GAINFORMAT_QMF128:
42     case GAINFORMAT_UNIFORM:
43       width = 0.5f * audio_sample_rate / (FLOAT32)eq_subband_gain_count;
44       offset = 0.5f * width;
45       for (idx = 0; idx < eq_subband_gain_count; idx++) {
46         ptr_subband_center_freq[idx] = idx * width + offset;
47       }
48       break;
49     case GAINFORMAT_QMFHYBRID39:
50     case GAINFORMAT_QMFHYBRID71:
51     case GAINFORMAT_QMFHYBRID135:
52       return IA_EXHEAACE_CONFIG_FATAL_DRC_UNSUPPORTED_CONFIG;
53       break;
54     default:
55       break;
56   }
57 
58   return IA_NO_ERROR;
59 }
60 
impd_drc_derive_zero_response(const FLOAT32 radius,const FLOAT32 angle_radian,const FLOAT32 frequency_radian,FLOAT32 * response)61 static VOID impd_drc_derive_zero_response(const FLOAT32 radius, const FLOAT32 angle_radian,
62                                           const FLOAT32 frequency_radian, FLOAT32 *response) {
63   *response =
64       (FLOAT32)(1.0f + radius * radius - 2.0f * radius * cos(frequency_radian - angle_radian));
65 }
66 
impd_drc_derive_pole_response(const FLOAT32 radius,const FLOAT32 angle_radian,const FLOAT32 frequency_radian,FLOAT32 * response)67 static VOID impd_drc_derive_pole_response(const FLOAT32 radius, const FLOAT32 angle_radian,
68                                           const FLOAT32 frequency_radian, FLOAT32 *response) {
69   *response =
70       (FLOAT32)(1.0f + radius * radius - 2.0f * radius * cos(frequency_radian - angle_radian));
71   *response = 1.0f / *response;
72 }
73 
impd_drc_derive_fir_filter_response(const WORD32 fir_order,const WORD32 fir_symmetry,const FLOAT32 * ptr_fir_coeff,const FLOAT32 frequency_radian,FLOAT32 * response)74 static VOID impd_drc_derive_fir_filter_response(const WORD32 fir_order, const WORD32 fir_symmetry,
75                                                 const FLOAT32 *ptr_fir_coeff,
76                                                 const FLOAT32 frequency_radian,
77                                                 FLOAT32 *response) {
78   LOOPIDX idx;
79   WORD32 order_2;
80   FLOAT32 sum = 0.0f;
81 
82   if ((fir_order & 0x1) != 0) {
83     order_2 = (fir_order + 1) / 2;
84     if (fir_symmetry != 0) {
85       for (idx = 1; idx <= order_2; idx++) {
86         sum += (FLOAT32)(ptr_fir_coeff[order_2 - idx] * sin((idx - 0.5f) * frequency_radian));
87       }
88     } else {
89       for (idx = 1; idx <= order_2; idx++) {
90         sum += (FLOAT32)(ptr_fir_coeff[order_2 - idx] * cos((idx - 0.5f) * frequency_radian));
91       }
92     }
93     sum *= 2.0f;
94   } else {
95     order_2 = fir_order / 2;
96     if (fir_symmetry != 0) {
97       for (idx = 1; idx <= order_2; idx++) {
98         sum += (FLOAT32)(ptr_fir_coeff[order_2 - idx] * sin(idx * frequency_radian));
99       }
100       sum *= 2.0f;
101     } else {
102       sum = ptr_fir_coeff[order_2];
103     }
104   }
105 
106   *response = sum;
107 }
108 
impd_drc_derive_filter_element_response(ia_drc_unique_td_filter_element_struct * pstr_unique_td_filter_element,const FLOAT32 frequency_radian,FLOAT32 * response)109 static VOID impd_drc_derive_filter_element_response(
110     ia_drc_unique_td_filter_element_struct *pstr_unique_td_filter_element,
111     const FLOAT32 frequency_radian, FLOAT32 *response) {
112   LOOPIDX idx;
113   FLOAT32 response_part, radius, angle_radian;
114   FLOAT64 combined_response = 1.0;
115 
116   if (pstr_unique_td_filter_element->eq_filter_format != FILTER_ELEMENT_FORMAT_POLE_ZERO) {
117     impd_drc_derive_fir_filter_response(pstr_unique_td_filter_element->fir_filter_order,
118                                         pstr_unique_td_filter_element->fir_symmetry,
119                                         pstr_unique_td_filter_element->fir_coefficient,
120                                         frequency_radian, &response_part);
121     combined_response *= response_part;
122   } else {
123     for (idx = 0; idx < pstr_unique_td_filter_element->real_zero_radius_one_count; idx++) {
124       impd_drc_derive_zero_response(1.0f,
125                                     (FLOAT32)(M_PI)*pstr_unique_td_filter_element->zero_sign[idx],
126                                     frequency_radian, &response_part);
127       combined_response *= response_part;
128     }
129     for (idx = 0; idx < pstr_unique_td_filter_element->real_zero_count; idx++) {
130       if (pstr_unique_td_filter_element->real_zero_radius[idx] >= 0.0f) {
131         radius = pstr_unique_td_filter_element->real_zero_radius[idx];
132         angle_radian = 0.0f;
133       } else {
134         radius = -pstr_unique_td_filter_element->real_zero_radius[idx];
135         angle_radian = (FLOAT32)(M_PI);
136       }
137       impd_drc_derive_zero_response(radius, angle_radian, frequency_radian, &response_part);
138       combined_response *= response_part;
139       impd_drc_derive_zero_response(1.0f / radius, angle_radian, frequency_radian,
140                                     &response_part);
141       combined_response *= response_part;
142     }
143 
144     combined_response = sqrt(combined_response);
145 
146     for (idx = 0; idx < pstr_unique_td_filter_element->generic_zero_count; idx++) {
147       radius = pstr_unique_td_filter_element->generic_zero_radius[idx];
148 
149       impd_drc_derive_zero_response(
150           radius, (FLOAT32)(M_PI)*pstr_unique_td_filter_element->generic_zero_angle[idx],
151           frequency_radian, &response_part);
152       combined_response *= response_part;
153 
154       impd_drc_derive_zero_response(
155           1.0f / radius, (FLOAT32)(M_PI)*pstr_unique_td_filter_element->generic_zero_angle[idx],
156           frequency_radian, &response_part);
157       combined_response *= response_part;
158     }
159     for (idx = 0; idx < pstr_unique_td_filter_element->real_pole_count; idx++) {
160       if (pstr_unique_td_filter_element->real_pole_radius[idx] >= 0.0f) {
161         radius = pstr_unique_td_filter_element->real_pole_radius[idx];
162         angle_radian = 0.0f;
163       } else {
164         radius = -pstr_unique_td_filter_element->real_pole_radius[idx];
165         angle_radian = (FLOAT32)(-M_PI);
166       }
167       impd_drc_derive_pole_response(radius, angle_radian, frequency_radian, &response_part);
168       combined_response *= response_part;
169     }
170     for (idx = 0; idx < pstr_unique_td_filter_element->complex_pole_count; idx++) {
171       impd_drc_derive_pole_response(
172           pstr_unique_td_filter_element->real_pole_radius[idx],
173           (FLOAT32)(M_PI)*pstr_unique_td_filter_element->complex_pole_angle[idx],
174           frequency_radian, &response_part);
175       combined_response *= response_part * response_part;
176     }
177   }
178 
179   *response = (FLOAT32)combined_response;
180 }
181 
impd_drc_derive_filter_block_response(ia_drc_unique_td_filter_element_struct * pstr_unique_td_filter_element,ia_drc_filter_block_struct * pstr_filter_block,const FLOAT32 frequency_radian,FLOAT32 * response)182 static VOID impd_drc_derive_filter_block_response(
183     ia_drc_unique_td_filter_element_struct *pstr_unique_td_filter_element,
184     ia_drc_filter_block_struct *pstr_filter_block, const FLOAT32 frequency_radian,
185     FLOAT32 *response) {
186   LOOPIDX idx;
187   FLOAT32 response_part;
188   FLOAT64 combined_response = 1.0;
189   ia_drc_filter_element_struct *pstr_filter_element;
190 
191   for (idx = 0; idx < pstr_filter_block->filter_element_count; idx++) {
192     pstr_filter_element = &pstr_filter_block->filter_element[idx];
193     impd_drc_derive_filter_element_response(
194         &(pstr_unique_td_filter_element[pstr_filter_element->filter_element_index]),
195         frequency_radian, &response_part);
196     combined_response *= response_part;
197 
198     if (pstr_filter_element->filter_element_gain_present == 1) {
199       combined_response *= pow(10.0f, 0.05f * pstr_filter_element->filter_element_gain);
200     }
201   }
202 
203   *response = (FLOAT32)combined_response;
204 }
205 
impd_drc_derive_subband_gains_from_td_cascade(ia_drc_unique_td_filter_element_struct * pstr_unique_td_filter_element,ia_drc_filter_block_struct * pstr_filter_block,ia_drc_td_filter_cascade_struct * pstr_td_filter_cascade,const WORD32 eq_subband_gain_format,const WORD32 eq_channel_group_count,const FLOAT32 audio_sample_rate,const WORD32 eq_frame_size_subband,ia_drc_subband_filter_struct * pstr_subband_filter,VOID * ptr_scratch)206 static IA_ERRORCODE impd_drc_derive_subband_gains_from_td_cascade(
207     ia_drc_unique_td_filter_element_struct *pstr_unique_td_filter_element,
208     ia_drc_filter_block_struct *pstr_filter_block,
209     ia_drc_td_filter_cascade_struct *pstr_td_filter_cascade, const WORD32 eq_subband_gain_format,
210     const WORD32 eq_channel_group_count, const FLOAT32 audio_sample_rate,
211     const WORD32 eq_frame_size_subband, ia_drc_subband_filter_struct *pstr_subband_filter,
212     VOID *ptr_scratch) {
213   IA_ERRORCODE err_code = IA_NO_ERROR;
214   LOOPIDX i, j, k;
215   WORD32 eq_subband_gain_count = pstr_subband_filter->coeff_count;
216   FLOAT32 response_part, frequency_radian;
217   FLOAT32 *ptr_subband_center_freq = (FLOAT32 *)ptr_scratch;
218   FLOAT64 combined_response;
219 
220   err_code = impd_drc_derive_subband_center_freq(eq_subband_gain_count, eq_subband_gain_format,
221                                                  audio_sample_rate, ptr_subband_center_freq);
222   if (err_code & IA_FATAL_ERROR) {
223     return err_code;
224   }
225 
226   for (i = 0; i < eq_channel_group_count; i++) {
227     for (j = 0; j < eq_subband_gain_count; j++) {
228       combined_response = pow(10.0f, 0.05f * pstr_td_filter_cascade->eq_cascade_gain[i]);
229       frequency_radian = 2.0f * (FLOAT32)M_PI * ptr_subband_center_freq[j] / audio_sample_rate;
230 
231       for (k = 0; k < pstr_td_filter_cascade->str_filter_block_refs[i].filter_block_count; k++) {
232         impd_drc_derive_filter_block_response(
233             pstr_unique_td_filter_element,
234             &(pstr_filter_block[pstr_td_filter_cascade->str_filter_block_refs[i]
235                                     .filter_block_index[k]]),
236             frequency_radian, &response_part);
237         combined_response *= response_part;
238       }
239       pstr_subband_filter[i].subband_coeff[j] = (FLOAT32)combined_response;
240     }
241     pstr_subband_filter[i].eq_frame_size_subband = eq_frame_size_subband;
242   }
243 
244   return err_code;
245 }
246 
impd_drc_check_presence_and_add_cascade(ia_drc_cascade_alignment_group_struct * pstr_cascade_alignment_group,const WORD32 index_c1,const WORD32 index_c2,WORD32 * done)247 static VOID impd_drc_check_presence_and_add_cascade(
248     ia_drc_cascade_alignment_group_struct *pstr_cascade_alignment_group, const WORD32 index_c1,
249     const WORD32 index_c2, WORD32 *done) {
250   LOOPIDX i, j;
251 
252   *done = 0;
253   for (i = 0; i < pstr_cascade_alignment_group->member_count; i++) {
254     if (pstr_cascade_alignment_group->member_index[i] == index_c1) {
255       for (j = 0; j < pstr_cascade_alignment_group->member_count; j++) {
256         if (pstr_cascade_alignment_group->member_index[j] == index_c2) {
257           *done = 1;
258         }
259       }
260       if (*done == 0) {
261         pstr_cascade_alignment_group->member_index[pstr_cascade_alignment_group->member_count] =
262             index_c2;
263         pstr_cascade_alignment_group->member_count++;
264         *done = 1;
265       }
266     }
267   }
268 }
269 
impd_drc_derive_cascade_alignment_groups(const WORD32 eq_channel_group_count,const WORD32 eq_phase_alignment_present,const WORD32 eq_phase_alignment[EQ_MAX_CHANNEL_GROUP_COUNT][EQ_MAX_CHANNEL_GROUP_COUNT],WORD32 * cascade_alignment_group_count,ia_drc_cascade_alignment_group_struct * pstr_cascade_alignment_group)270 static VOID impd_drc_derive_cascade_alignment_groups(
271     const WORD32 eq_channel_group_count, const WORD32 eq_phase_alignment_present,
272     const WORD32 eq_phase_alignment[EQ_MAX_CHANNEL_GROUP_COUNT][EQ_MAX_CHANNEL_GROUP_COUNT],
273     WORD32 *cascade_alignment_group_count,
274     ia_drc_cascade_alignment_group_struct *pstr_cascade_alignment_group) {
275   LOOPIDX i, j, k;
276   WORD32 group_count = 0, done;
277 
278   if (eq_phase_alignment_present != 0) {
279     for (i = 0; i < eq_channel_group_count; i++) {
280       for (j = i + 1; j < eq_channel_group_count; j++) {
281         if (eq_phase_alignment[i][j] == 1) {
282           done = 0;
283           for (k = 0; k < group_count; k++) {
284             impd_drc_check_presence_and_add_cascade(&pstr_cascade_alignment_group[k], i, j,
285                                                     &done);
286             if (done == 0) {
287               impd_drc_check_presence_and_add_cascade(&pstr_cascade_alignment_group[k], j, i,
288                                                       &done);
289             }
290           }
291           if (done == 0) {
292             pstr_cascade_alignment_group[group_count].member_count = 2;
293             pstr_cascade_alignment_group[group_count].member_index[0] = i;
294             pstr_cascade_alignment_group[group_count].member_index[1] = j;
295             group_count++;
296           }
297         }
298       }
299     }
300   } else {
301     if (eq_channel_group_count > 1) {
302       for (i = 0; i < eq_channel_group_count; i++) {
303         pstr_cascade_alignment_group[group_count].member_index[i] = i;
304       }
305       pstr_cascade_alignment_group[group_count].member_count = eq_channel_group_count;
306       group_count = 1;
307     }
308   }
309 
310   *cascade_alignment_group_count = group_count;
311 }
312 
impd_drc_derive_allpass_chain(ia_drc_filter_cascade_t_domain_struct * pstr_filter_cascade_t_domain,ia_drc_allpass_chain_struct * pstr_allpass_chain)313 static IA_ERRORCODE impd_drc_derive_allpass_chain(
314     ia_drc_filter_cascade_t_domain_struct *pstr_filter_cascade_t_domain,
315     ia_drc_allpass_chain_struct *pstr_allpass_chain) {
316   LOOPIDX i, j;
317   WORD32 allpass_count = 0;
318 
319   for (i = 0; i < pstr_filter_cascade_t_domain->block_count; i++) {
320     ia_drc_eq_filter_element_struct *pstr_eq_filter_element =
321         &pstr_filter_cascade_t_domain->str_eq_filter_block[i].str_eq_filter_element[0];
322 
323     if (pstr_filter_cascade_t_domain->str_eq_filter_block[i]
324             .str_matching_phase_filter_element_0.is_valid != 1) {
325       return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
326     } else {
327       pstr_allpass_chain->str_matching_phase_filter[allpass_count] =
328           pstr_filter_cascade_t_domain->str_eq_filter_block[i]
329               .str_matching_phase_filter_element_0;
330       allpass_count++;
331     }
332 
333     for (j = 0; j < pstr_eq_filter_element->phase_alignment_filter_count; j++) {
334       if (pstr_eq_filter_element->str_phase_alignment_filter[j].is_valid != 1) {
335         return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
336       } else {
337         pstr_allpass_chain->str_matching_phase_filter[allpass_count] =
338             pstr_eq_filter_element->str_phase_alignment_filter[j];
339         allpass_count++;
340       }
341     }
342   }
343   pstr_allpass_chain->allpass_count = allpass_count;
344 
345   return IA_NO_ERROR;
346 }
347 
impd_drc_add_allpass_filter_chain(ia_drc_allpass_chain_struct * pstr_allpass_chain,ia_drc_filter_cascade_t_domain_struct * pstr_filter_cascade_t_domain)348 static VOID impd_drc_add_allpass_filter_chain(
349     ia_drc_allpass_chain_struct *pstr_allpass_chain,
350     ia_drc_filter_cascade_t_domain_struct *pstr_filter_cascade_t_domain) {
351   LOOPIDX idx;
352 
353   for (idx = 0; idx < pstr_allpass_chain->allpass_count; idx++) {
354     pstr_filter_cascade_t_domain
355         ->str_phase_alignment_filter[pstr_filter_cascade_t_domain->phase_alignment_filter_count +
356                                      idx] = pstr_allpass_chain->str_matching_phase_filter[idx];
357   }
358   pstr_filter_cascade_t_domain->phase_alignment_filter_count += pstr_allpass_chain->allpass_count;
359 }
360 
impd_drc_phase_align_cascade_group(const WORD32 cascade_alignment_group_count,ia_drc_cascade_alignment_group_struct * pstr_cascade_alignment_group,ia_drc_filter_cascade_t_domain_struct * pstr_filter_cascade_t_domain,VOID * ptr_scratch,WORD32 * scratch_used)361 static IA_ERRORCODE impd_drc_phase_align_cascade_group(
362     const WORD32 cascade_alignment_group_count,
363     ia_drc_cascade_alignment_group_struct *pstr_cascade_alignment_group,
364     ia_drc_filter_cascade_t_domain_struct *pstr_filter_cascade_t_domain, VOID *ptr_scratch,
365     WORD32 *scratch_used) {
366   IA_ERRORCODE err_code = IA_NO_ERROR;
367   LOOPIDX i, j, k;
368   WORD32 cascade_index;
369   ia_drc_allpass_chain_struct *pstr_allpass_chain =
370       (ia_drc_allpass_chain_struct *)((pUWORD8)(ptr_scratch)) + *scratch_used;
371 
372   for (i = 0; i < cascade_alignment_group_count; i++) {
373     for (j = 0; j < pstr_cascade_alignment_group[i].member_count; j++) {
374       cascade_index = pstr_cascade_alignment_group[i].member_index[j];
375 
376       err_code = impd_drc_derive_allpass_chain(&pstr_filter_cascade_t_domain[cascade_index],
377                                                &pstr_allpass_chain[j]);
378       if (err_code & IA_FATAL_ERROR) {
379         return err_code;
380       }
381       pstr_allpass_chain[j].matches_cascade_index = cascade_index;
382     }
383     for (j = 0; j < pstr_cascade_alignment_group[i].member_count; j++) {
384       cascade_index = pstr_cascade_alignment_group[i].member_index[j];
385       for (k = 0; k < pstr_cascade_alignment_group[i].member_count; k++) {
386         if (cascade_index != pstr_allpass_chain[k].matches_cascade_index) {
387           impd_drc_add_allpass_filter_chain(&pstr_allpass_chain[k],
388                                             &pstr_filter_cascade_t_domain[cascade_index]);
389         }
390       }
391     }
392   }
393 
394   return err_code;
395 }
396 
impd_drc_derive_matching_phase_filter_params(const WORD32 config,FLOAT32 radius,FLOAT32 angle,ia_drc_phase_alignment_filter_struct * pstr_phase_alignment_filter)397 static VOID impd_drc_derive_matching_phase_filter_params(
398     const WORD32 config, FLOAT32 radius, FLOAT32 angle,
399     ia_drc_phase_alignment_filter_struct *pstr_phase_alignment_filter) {
400   LOOPIDX idx;
401   WORD32 section = pstr_phase_alignment_filter->section_count;
402   FLOAT32 z_real, z_imag, product;
403   ia_drc_filter_section_struct *pstr_filter_section =
404       &pstr_phase_alignment_filter->str_filter_section[section];
405 
406   switch (config) {
407     case CONFIG_COMPLEX_POLE:
408       z_real = (FLOAT32)(radius * cos((FLOAT32)M_PI * angle));
409       z_imag = (FLOAT32)(radius * sin((FLOAT32)M_PI * angle));
410       product = z_real * z_real + z_imag * z_imag;
411       pstr_phase_alignment_filter->gain *= product;
412       pstr_filter_section->var_a1 = -2.0f * z_real;
413       pstr_filter_section->var_a2 = product;
414       pstr_filter_section->var_b1 = -2.0f * z_real / product;
415       pstr_filter_section->var_b2 = 1.0f / product;
416       pstr_phase_alignment_filter->section_count++;
417       break;
418     case CONFIG_REAL_POLE:
419       pstr_phase_alignment_filter->gain *= (-radius);
420       pstr_filter_section->var_a1 = -radius;
421       pstr_filter_section->var_a2 = 0.0f;
422       pstr_filter_section->var_b1 = -1.0f / radius;
423       pstr_filter_section->var_b2 = 0.0f;
424       pstr_phase_alignment_filter->section_count++;
425       break;
426     default:
427       break;
428   }
429   for (idx = 0; idx < MAX_EQ_CHANNEL_COUNT; idx++) {
430     pstr_filter_section->str_filter_section_state[idx].state_in_1 = 0.0f;
431     pstr_filter_section->str_filter_section_state[idx].state_out_1 = 0.0f;
432     pstr_filter_section->str_filter_section_state[idx].state_in_2 = 0.0f;
433     pstr_filter_section->str_filter_section_state[idx].state_out_2 = 0.0f;
434   }
435 }
436 
impd_drc_derive_matching_phase_filter_delay(ia_drc_unique_td_filter_element_struct * pstr_filter_element,ia_drc_phase_alignment_filter_struct * pstr_phase_alignment_filter)437 static VOID impd_drc_derive_matching_phase_filter_delay(
438     ia_drc_unique_td_filter_element_struct *pstr_filter_element,
439     ia_drc_phase_alignment_filter_struct *pstr_phase_alignment_filter) {
440   LOOPIDX i, j;
441   WORD32 delay = 0;
442 
443   if (pstr_filter_element->eq_filter_format == FILTER_ELEMENT_FORMAT_POLE_ZERO) {
444     if (pstr_filter_element->real_zero_radius_one_count == 0) {
445       delay = pstr_filter_element->real_zero_count + 2 * pstr_filter_element->generic_zero_count -
446               pstr_filter_element->real_pole_count - 2 * pstr_filter_element->complex_pole_count;
447       delay = MAX(0, delay);
448       pstr_phase_alignment_filter->is_valid = 1;
449     }
450   }
451 
452   pstr_phase_alignment_filter->str_audio_delay.delay = delay;
453   for (i = 0; i < MAX_EQ_CHANNEL_COUNT; i++) {
454     for (j = 0; j < delay; j++) {
455       pstr_phase_alignment_filter->str_audio_delay.state[i][j] = 0.0f;
456     }
457   }
458 }
459 
impd_drc_derive_matching_phase_filter(ia_drc_unique_td_filter_element_struct * pstr_filter_element,WORD32 filter_element_index,ia_drc_matching_phase_filter_struct * pstr_matching_phase_filter)460 static VOID impd_drc_derive_matching_phase_filter(
461     ia_drc_unique_td_filter_element_struct *pstr_filter_element, WORD32 filter_element_index,
462     ia_drc_matching_phase_filter_struct *pstr_matching_phase_filter) {
463   LOOPIDX idx;
464 
465   memset(pstr_matching_phase_filter, 0, sizeof(ia_drc_matching_phase_filter_struct));
466   pstr_matching_phase_filter->gain = 1.0f;
467 
468   if (pstr_filter_element->eq_filter_format == FILTER_ELEMENT_FORMAT_POLE_ZERO) {
469     for (idx = 0; idx < pstr_filter_element->real_pole_count; idx++) {
470       impd_drc_derive_matching_phase_filter_params(CONFIG_REAL_POLE,
471                                                    pstr_filter_element->real_pole_radius[idx],
472                                                    0.0f, pstr_matching_phase_filter);
473     }
474     for (idx = 0; idx < pstr_filter_element->complex_pole_count; idx++) {
475       impd_drc_derive_matching_phase_filter_params(
476           CONFIG_COMPLEX_POLE, pstr_filter_element->complex_pole_radius[idx],
477           pstr_filter_element->complex_pole_angle[idx], pstr_matching_phase_filter);
478     }
479   }
480   impd_drc_derive_matching_phase_filter_delay(pstr_filter_element, pstr_matching_phase_filter);
481 
482   pstr_matching_phase_filter->matches_filter_count = 1;
483   pstr_matching_phase_filter->matches_filter[0] = filter_element_index;
484 }
485 
impd_drc_check_phase_filter_is_equal(ia_drc_matching_phase_filter_struct * pstr_matching_phase_filter_1,ia_drc_matching_phase_filter_struct * pstr_matching_phase_filter_2,WORD32 * is_equal)486 static VOID impd_drc_check_phase_filter_is_equal(
487     ia_drc_matching_phase_filter_struct *pstr_matching_phase_filter_1,
488     ia_drc_matching_phase_filter_struct *pstr_matching_phase_filter_2, WORD32 *is_equal) {
489   LOOPIDX idx;
490 
491   *is_equal = 1;
492   if (pstr_matching_phase_filter_1->section_count ==
493       pstr_matching_phase_filter_2->section_count) {
494     for (idx = 0; idx < pstr_matching_phase_filter_1->section_count; idx++) {
495       if ((pstr_matching_phase_filter_1->str_filter_section[idx].var_a1 !=
496            pstr_matching_phase_filter_2->str_filter_section[idx].var_a1) ||
497           (pstr_matching_phase_filter_1->str_filter_section[idx].var_a2 !=
498            pstr_matching_phase_filter_2->str_filter_section[idx].var_a2) ||
499           (pstr_matching_phase_filter_1->str_filter_section[idx].var_b1 !=
500            pstr_matching_phase_filter_2->str_filter_section[idx].var_b1) ||
501           (pstr_matching_phase_filter_1->str_filter_section[idx].var_b2 !=
502            pstr_matching_phase_filter_2->str_filter_section[idx].var_b2)) {
503         *is_equal = 0;
504         break;
505       }
506     }
507   } else {
508     *is_equal = 0;
509   }
510 
511   if (pstr_matching_phase_filter_1->str_audio_delay.delay !=
512       pstr_matching_phase_filter_2->str_audio_delay.delay) {
513     *is_equal = 0;
514   }
515 }
516 
impd_drc_add_phase_alignment_filter(ia_drc_matching_phase_filter_struct * pstr_matching_phase_filter,ia_drc_eq_filter_element_struct * pstr_eq_filter_element)517 static IA_ERRORCODE impd_drc_add_phase_alignment_filter(
518     ia_drc_matching_phase_filter_struct *pstr_matching_phase_filter,
519     ia_drc_eq_filter_element_struct *pstr_eq_filter_element) {
520   if (pstr_matching_phase_filter->is_valid != 1) {
521     return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
522   } else {
523     pstr_eq_filter_element
524         ->str_phase_alignment_filter[pstr_eq_filter_element->phase_alignment_filter_count] =
525         *pstr_matching_phase_filter;
526     pstr_eq_filter_element->phase_alignment_filter_count++;
527   }
528 
529   return IA_NO_ERROR;
530 }
531 
impd_drc_derive_element_phase_alignment_filters(ia_drc_matching_phase_filter_struct * pstr_matching_phase_filter,ia_drc_eq_filter_block_struct * pstr_eq_filter_block,VOID * ptr_scratch,WORD32 * scratch_used)532 static IA_ERRORCODE impd_drc_derive_element_phase_alignment_filters(
533     ia_drc_matching_phase_filter_struct *pstr_matching_phase_filter,
534     ia_drc_eq_filter_block_struct *pstr_eq_filter_block, VOID *ptr_scratch,
535     WORD32 *scratch_used) {
536   IA_ERRORCODE err_code = IA_NO_ERROR;
537   LOOPIDX i, j, k;
538   WORD32 skip, is_equal;
539   WORD32 optimized_phase_filter_count;
540   WORD32 path_delay_min, path_delay, path_delay_new, path_delay_to_remove;
541 
542   ia_drc_matching_phase_filter_struct *pstr_matching_phase_filter_opt =
543       (ia_drc_matching_phase_filter_struct *)((pUWORD8)ptr_scratch) + *scratch_used;
544   ia_drc_eq_filter_element_struct *pstr_eq_filter_element;
545 
546   optimized_phase_filter_count = 0;
547   for (i = 0; i < pstr_eq_filter_block->element_count; i++) {
548     is_equal = 0;
549     for (j = 0; j < optimized_phase_filter_count; j++) {
550       impd_drc_check_phase_filter_is_equal(&pstr_matching_phase_filter[i],
551                                            &pstr_matching_phase_filter_opt[j], &is_equal);
552       if (is_equal == 1) {
553         break;
554       }
555     }
556     if (is_equal != 1) {
557       pstr_matching_phase_filter_opt[optimized_phase_filter_count] =
558           pstr_matching_phase_filter[i];
559       optimized_phase_filter_count++;
560     } else {
561       pstr_matching_phase_filter_opt[j]
562           .matches_filter[pstr_matching_phase_filter_opt[j].matches_filter_count] = i;
563       pstr_matching_phase_filter_opt[j].matches_filter_count++;
564     }
565   }
566 
567   for (i = 0; i < pstr_eq_filter_block->element_count; i++) {
568     for (j = 0; j < optimized_phase_filter_count; j++) {
569       skip = 0;
570       for (k = 0; k < pstr_matching_phase_filter_opt[j].matches_filter_count; k++) {
571         if (pstr_matching_phase_filter_opt[j].matches_filter[k] == i) {
572           skip = 1;
573           break;
574         }
575       }
576       if (skip == 0) {
577         err_code = impd_drc_add_phase_alignment_filter(
578             &pstr_matching_phase_filter_opt[j], &pstr_eq_filter_block->str_eq_filter_element[i]);
579         if (err_code & IA_FATAL_ERROR) {
580           return err_code;
581         }
582       }
583     }
584   }
585 
586   path_delay_min = 100000;
587   for (i = 0; i < pstr_eq_filter_block->element_count; i++) {
588     pstr_eq_filter_element = &pstr_eq_filter_block->str_eq_filter_element[i];
589     path_delay = 0;
590     for (k = 0; k < pstr_eq_filter_element->phase_alignment_filter_count; k++) {
591       path_delay += pstr_eq_filter_element->str_phase_alignment_filter[k].str_audio_delay.delay;
592     }
593     if (path_delay_min > path_delay) {
594       path_delay_min = path_delay;
595     }
596   }
597   if (path_delay_min > 0) {
598     for (i = 0; i < pstr_eq_filter_block->element_count; i++) {
599       pstr_eq_filter_element = &pstr_eq_filter_block->str_eq_filter_element[i];
600       path_delay_to_remove = path_delay_min;
601       for (k = 0; k < pstr_eq_filter_element->phase_alignment_filter_count; k++) {
602         path_delay = pstr_eq_filter_element->str_phase_alignment_filter[k].str_audio_delay.delay;
603         path_delay_new = MAX(0, path_delay - path_delay_to_remove);
604         path_delay_to_remove -= path_delay - path_delay_new;
605         pstr_eq_filter_element->str_phase_alignment_filter[k].str_audio_delay.delay =
606             path_delay_new;
607       }
608     }
609   }
610 
611   return err_code;
612 }
613 
impd_drc_convert_pole_zero_to_filter_params(const WORD32 config,FLOAT32 radius,FLOAT32 angle,WORD32 * filter_param_count,ia_drc_second_order_filter_params_struct * pstr_second_order_filter_params)614 static IA_ERRORCODE impd_drc_convert_pole_zero_to_filter_params(
615     const WORD32 config, FLOAT32 radius, FLOAT32 angle, WORD32 *filter_param_count,
616     ia_drc_second_order_filter_params_struct *pstr_second_order_filter_params) {
617   FLOAT32 z_real, angle_1, angle_2;
618   FLOAT32 *ptr_coeff;
619 
620   switch (config) {
621     case CONFIG_REAL_POLE: {
622       pstr_second_order_filter_params[0].radius = radius;
623       ptr_coeff = pstr_second_order_filter_params[0].coeff;
624       ptr_coeff[0] = -2.0f * radius;
625       ptr_coeff[1] = radius * radius;
626       *filter_param_count = 1;
627     } break;
628     case CONFIG_COMPLEX_POLE: {
629       z_real = (FLOAT32)(radius * cos((FLOAT32)M_PI * angle));
630       pstr_second_order_filter_params[0].radius = radius;
631       ptr_coeff = pstr_second_order_filter_params[0].coeff;
632       ptr_coeff[0] = -2.0f * z_real;
633       ptr_coeff[1] = radius * radius;
634       pstr_second_order_filter_params[1].radius = radius;
635       pstr_second_order_filter_params[1].coeff[0] = ptr_coeff[0];
636       pstr_second_order_filter_params[1].coeff[1] = ptr_coeff[1];
637       *filter_param_count = 2;
638     } break;
639     case CONFIG_REAL_ZERO_RADIUS_ONE: {
640       angle_1 = radius;
641       angle_2 = angle;
642       pstr_second_order_filter_params[0].radius = 1.0f;
643       ptr_coeff = pstr_second_order_filter_params[0].coeff;
644 
645       if (angle_1 != angle_2) {
646         ptr_coeff[0] = 0.0f;
647         ptr_coeff[1] = -1.0f;
648       } else if (angle_1 == 1.0f) {
649         ptr_coeff[0] = -2.0f;
650         ptr_coeff[1] = 1.0f;
651       } else {
652         ptr_coeff[0] = 2.0f;
653         ptr_coeff[1] = 1.0f;
654       }
655       *filter_param_count = 1;
656     } break;
657     case CONFIG_REAL_ZERO: {
658       pstr_second_order_filter_params[0].radius = radius;
659       if (fabs(radius) == 1.0f) {
660         return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
661       } else {
662         ptr_coeff = pstr_second_order_filter_params[0].coeff;
663         ptr_coeff[0] = -(radius + 1.0f / radius);
664         ptr_coeff[1] = 1.0f;
665       }
666       *filter_param_count = 1;
667     } break;
668     case CONFIG_GENERIC_ZERO: {
669       z_real = (FLOAT32)(radius * cos((FLOAT32)M_PI * angle));
670       pstr_second_order_filter_params[0].radius = radius;
671       ptr_coeff = pstr_second_order_filter_params[0].coeff;
672       ptr_coeff[0] = -2.0f * z_real;
673       ptr_coeff[1] = (FLOAT32)(radius * radius);
674       z_real = (FLOAT32)(cos((FLOAT32)M_PI * angle) / radius);
675       pstr_second_order_filter_params[1].radius = radius;
676       ptr_coeff = pstr_second_order_filter_params[1].coeff;
677       ptr_coeff[0] = -2.0f * z_real;
678       ptr_coeff[1] = 1.0f / (radius * radius);
679       *filter_param_count = 2;
680     } break;
681     default:
682       break;
683   }
684 
685   return IA_NO_ERROR;
686 }
687 
impd_drc_convert_fir_filter_params(const WORD32 fir_filter_order,const WORD32 fir_symmetry,FLOAT32 * fir_coefficient,ia_drc_fir_filter_struct * pstr_fir_filter)688 static VOID impd_drc_convert_fir_filter_params(const WORD32 fir_filter_order,
689                                                const WORD32 fir_symmetry,
690                                                FLOAT32 *fir_coefficient,
691                                                ia_drc_fir_filter_struct *pstr_fir_filter) {
692   LOOPIDX i, j;
693   FLOAT32 *ptr_coeff = pstr_fir_filter->coeff;
694 
695   pstr_fir_filter->coeff_count = fir_filter_order + 1;
696   for (i = 0; i < (fir_filter_order / 2 + 1); i++) {
697     ptr_coeff[i] = fir_coefficient[i];
698   }
699   for (i = 0; i < (fir_filter_order + 1) / 2; i++) {
700     if (fir_symmetry != 1) {
701       ptr_coeff[fir_filter_order - i] = ptr_coeff[i];
702     } else {
703       ptr_coeff[fir_filter_order - i] = -ptr_coeff[i];
704     }
705   }
706   if ((fir_symmetry == 1) && ((fir_filter_order & 1) == 0)) {
707     ptr_coeff[fir_filter_order / 2] = 0.0f;
708   }
709   for (i = 0; i < MAX_EQ_CHANNEL_COUNT; i++) {
710     for (j = 0; j < (fir_filter_order + 1); j++) {
711       pstr_fir_filter->state[i][j] = 0.0f;
712     }
713   }
714 }
715 
impd_drc_derive_pole_zero_filter_params(ia_drc_unique_td_filter_element_struct * pstr_filter_element,ia_drc_intermediate_filter_params_struct * pstr_intermediate_filter_params)716 static IA_ERRORCODE impd_drc_derive_pole_zero_filter_params(
717     ia_drc_unique_td_filter_element_struct *pstr_filter_element,
718     ia_drc_intermediate_filter_params_struct *pstr_intermediate_filter_params) {
719   IA_ERRORCODE err_code = IA_NO_ERROR;
720   LOOPIDX idx;
721   WORD32 param_index, filter_param_count;
722   ia_drc_second_order_filter_params_struct *pstr_second_order_filter_params_for_zeros;
723   ia_drc_second_order_filter_params_struct *pstr_second_order_filter_params_for_poles;
724 
725   pstr_intermediate_filter_params->filter_format = pstr_filter_element->eq_filter_format;
726   if (pstr_filter_element->eq_filter_format != FILTER_ELEMENT_FORMAT_POLE_ZERO) {
727     pstr_intermediate_filter_params->filter_param_count_for_zeros = 0;
728     pstr_intermediate_filter_params->filter_param_count_for_poles = 0;
729 
730     impd_drc_convert_fir_filter_params(
731         pstr_filter_element->fir_filter_order, pstr_filter_element->fir_symmetry,
732         pstr_filter_element->fir_coefficient, &pstr_intermediate_filter_params->str_fir_filter);
733   } else {
734     pstr_second_order_filter_params_for_zeros =
735         pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros;
736     pstr_second_order_filter_params_for_poles =
737         pstr_intermediate_filter_params->str_second_order_filter_params_for_poles;
738 
739     param_index = 0;
740     for (idx = 0; idx < pstr_filter_element->real_zero_radius_one_count; idx += 2) {
741       err_code = impd_drc_convert_pole_zero_to_filter_params(
742           CONFIG_REAL_ZERO_RADIUS_ONE, pstr_filter_element->zero_sign[idx],
743           pstr_filter_element->zero_sign[idx + 1], &filter_param_count,
744           &(pstr_second_order_filter_params_for_zeros[param_index]));
745       if (err_code & IA_FATAL_ERROR) {
746         return err_code;
747       }
748       param_index += filter_param_count;
749     }
750     for (idx = 0; idx < pstr_filter_element->real_zero_count; idx++) {
751       err_code = impd_drc_convert_pole_zero_to_filter_params(
752           CONFIG_REAL_ZERO, pstr_filter_element->real_zero_radius[idx], 0.0f, &filter_param_count,
753           &(pstr_second_order_filter_params_for_zeros[param_index]));
754       if (err_code & IA_FATAL_ERROR) {
755         return err_code;
756       }
757       param_index += filter_param_count;
758     }
759     for (idx = 0; idx < pstr_filter_element->generic_zero_count; idx++) {
760       err_code = impd_drc_convert_pole_zero_to_filter_params(
761           CONFIG_GENERIC_ZERO, pstr_filter_element->generic_zero_radius[idx],
762           pstr_filter_element->generic_zero_angle[idx], &filter_param_count,
763           &(pstr_second_order_filter_params_for_zeros[param_index]));
764       if (err_code & IA_FATAL_ERROR) {
765         return err_code;
766       }
767       param_index += filter_param_count;
768     }
769     pstr_intermediate_filter_params->filter_param_count_for_zeros = param_index;
770 
771     param_index = 0;
772     for (idx = 0; idx < pstr_filter_element->real_pole_count; idx++) {
773       err_code = impd_drc_convert_pole_zero_to_filter_params(
774           CONFIG_REAL_POLE, pstr_filter_element->real_pole_radius[idx], 0.0f, &filter_param_count,
775           &(pstr_second_order_filter_params_for_poles[param_index]));
776       if (err_code & IA_FATAL_ERROR) {
777         return err_code;
778       }
779       param_index += filter_param_count;
780     }
781     for (idx = 0; idx < pstr_filter_element->complex_pole_count; idx++) {
782       err_code = impd_drc_convert_pole_zero_to_filter_params(
783           CONFIG_COMPLEX_POLE, pstr_filter_element->complex_pole_radius[idx],
784           pstr_filter_element->complex_pole_angle[idx], &filter_param_count,
785           &(pstr_second_order_filter_params_for_poles[param_index]));
786       if (err_code & IA_FATAL_ERROR) {
787         return err_code;
788       }
789       param_index += filter_param_count;
790     }
791     pstr_intermediate_filter_params->filter_param_count_for_poles = param_index;
792   }
793 
794   return err_code;
795 }
796 
impd_drc_derive_eq_filter_elements(ia_drc_intermediate_filter_params_struct * pstr_intermediate_filter_params,ia_drc_eq_filter_element_struct * pstr_eq_filter_element,pUWORD8 ptr_scratch)797 static VOID impd_drc_derive_eq_filter_elements(
798     ia_drc_intermediate_filter_params_struct *pstr_intermediate_filter_params,
799     ia_drc_eq_filter_element_struct *pstr_eq_filter_element, pUWORD8 ptr_scratch) {
800   LOOPIDX idx, ch_idx;
801   WORD32 poles_index, zeros_index, pole_order = 0, section;
802   WORD32 coeff_count, coeff_idx;
803   WORD32 *ptr_poles_done = (WORD32 *)ptr_scratch;
804   WORD32 *ptr_zeros_done =
805       (WORD32 *)(ptr_scratch +
806                  ((REAL_POLE_COUNT_MAX + COMPLEX_POLE_COUNT_MAX) * sizeof(ptr_poles_done[0])));
807   FLOAT32 radius_max, radius_diff;
808   FLOAT32 temp_b1, temp_b2;
809   FLOAT32 *ptr_coeff;
810 
811   for (idx = 0; idx < (REAL_ZERO_COUNT_MAX + COMPLEX_ZERO_COUNT_MAX); idx++) {
812     ptr_zeros_done[idx] = 0;
813   }
814   for (idx = 0; idx < (REAL_POLE_COUNT_MAX + COMPLEX_POLE_COUNT_MAX); idx++) {
815     ptr_poles_done[idx] = 0;
816   }
817   section = 0;
818   do {
819     poles_index = -1;
820     radius_max = -1.0;
821     for (idx = 0; idx < pstr_intermediate_filter_params->filter_param_count_for_poles; idx++) {
822       if ((ptr_poles_done[idx] == 0) && (pstr_intermediate_filter_params->filter_format == 0)) {
823         if (radius_max <
824             fabs(pstr_intermediate_filter_params->str_second_order_filter_params_for_poles[idx]
825                      .radius)) {
826           radius_max = (FLOAT32)fabs(
827               pstr_intermediate_filter_params->str_second_order_filter_params_for_poles[idx]
828                   .radius);
829           poles_index = idx;
830           if (pstr_intermediate_filter_params->str_second_order_filter_params_for_poles[idx]
831                   .coeff[1] == 0.0f) {
832             pole_order = 1;
833           } else {
834             pole_order = 2;
835           }
836         }
837       }
838     }
839 
840     if (poles_index >= 0) {
841       radius_diff = 10.0f;
842       zeros_index = -1;
843       for (idx = 0; idx < pstr_intermediate_filter_params->filter_param_count_for_zeros; idx++) {
844         if (ptr_zeros_done[idx] == 0 && pstr_intermediate_filter_params->filter_format == 0) {
845           if (pole_order == 2) {
846             if (pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[idx]
847                     .coeff[1] != 0.0f) {
848               if (radius_diff > fabs(fabs(pstr_intermediate_filter_params
849                                               ->str_second_order_filter_params_for_zeros[idx]
850                                               .radius) -
851                                      radius_max)) {
852                 radius_diff =
853                     (FLOAT32)fabs(fabs(pstr_intermediate_filter_params
854                                            ->str_second_order_filter_params_for_zeros[idx]
855                                            .radius) -
856                                   radius_max);
857                 zeros_index = idx;
858               }
859             }
860           } else {
861             if (pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[idx]
862                     .coeff[1] == 0.0f) {
863               if (radius_diff > fabs(fabs(pstr_intermediate_filter_params
864                                               ->str_second_order_filter_params_for_zeros[idx]
865                                               .radius) -
866                                      radius_max)) {
867                 radius_diff =
868                     (FLOAT32)fabs(fabs(pstr_intermediate_filter_params
869                                            ->str_second_order_filter_params_for_zeros[idx]
870                                            .radius) -
871                                   radius_max);
872                 zeros_index = idx;
873               }
874             }
875           }
876         }
877       }
878 
879       if (zeros_index == -1) {
880         for (idx = 0; idx < pstr_intermediate_filter_params->filter_param_count_for_zeros;
881              idx++) {
882           if (ptr_zeros_done[idx] == 0 && pstr_intermediate_filter_params->filter_format == 0) {
883             if (pole_order == 2) {
884               if (pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[idx]
885                       .coeff[1] == 0.0f) {
886                 if (radius_diff > fabs(fabs(pstr_intermediate_filter_params
887                                                 ->str_second_order_filter_params_for_zeros[idx]
888                                                 .radius) -
889                                        radius_max)) {
890                   radius_diff =
891                       (FLOAT32)fabs(fabs(pstr_intermediate_filter_params
892                                              ->str_second_order_filter_params_for_zeros[idx]
893                                              .radius) -
894                                     radius_max);
895                   zeros_index = idx;
896                 }
897               }
898             } else {
899               if (pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[idx]
900                       .coeff[1] != 0.0f) {
901                 if (radius_diff > fabs(fabs(pstr_intermediate_filter_params
902                                                 ->str_second_order_filter_params_for_zeros[idx]
903                                                 .radius) -
904                                        radius_max)) {
905                   radius_diff =
906                       (FLOAT32)fabs(fabs(pstr_intermediate_filter_params
907                                              ->str_second_order_filter_params_for_zeros[idx]
908                                              .radius) -
909                                     radius_max);
910                   zeros_index = idx;
911                 }
912               }
913             }
914           }
915         }
916       }
917       pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section].var_a1 =
918           pstr_intermediate_filter_params->str_second_order_filter_params_for_poles[poles_index]
919               .coeff[0];
920       pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section].var_a2 =
921           pstr_intermediate_filter_params->str_second_order_filter_params_for_poles[poles_index]
922               .coeff[1];
923       if (zeros_index < 0) {
924         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section].var_b1 = 0.0f;
925         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section].var_b2 = 0.0f;
926         pstr_eq_filter_element->str_pole_zero_filter.str_audio_delay.delay++;
927       } else {
928         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section].var_b1 =
929             pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[zeros_index]
930                 .coeff[0];
931         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section].var_b2 =
932             pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[zeros_index]
933                 .coeff[1];
934       }
935       for (ch_idx = 0; ch_idx < MAX_EQ_CHANNEL_COUNT; ch_idx++) {
936         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section]
937             .str_filter_section_state[ch_idx]
938             .state_in_1 = 0.0f;
939         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section]
940             .str_filter_section_state[ch_idx]
941             .state_in_2 = 0.0f;
942         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section]
943             .str_filter_section_state[ch_idx]
944             .state_out_1 = 0.0f;
945         pstr_eq_filter_element->str_pole_zero_filter.str_filter_section[section]
946             .str_filter_section_state[ch_idx]
947             .state_out_2 = 0.0f;
948       }
949       if (zeros_index >= 0) {
950         ptr_zeros_done[zeros_index] = 1;
951       }
952       if (poles_index >= 0) {
953         ptr_poles_done[poles_index] = 1;
954       }
955       section++;
956     }
957   } while (poles_index >= 0);
958 
959   pstr_eq_filter_element->str_pole_zero_filter.section_count = section;
960 
961   coeff_count = 1;
962   ptr_coeff = pstr_eq_filter_element->str_pole_zero_filter.str_fir_filter.coeff;
963   ptr_coeff[0] = 1.0f;
964   for (idx = 0; idx < pstr_intermediate_filter_params->filter_param_count_for_zeros; idx++) {
965     if (ptr_zeros_done[idx] == 0 && pstr_intermediate_filter_params->filter_format == 0) {
966       temp_b1 =
967           pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[idx].coeff[0];
968       temp_b2 =
969           pstr_intermediate_filter_params->str_second_order_filter_params_for_zeros[idx].coeff[1];
970 
971       coeff_count += 2;
972       coeff_idx = coeff_count - 1;
973       ptr_coeff[coeff_idx] = temp_b2 * ptr_coeff[coeff_idx - 2];
974       coeff_idx--;
975       if (coeff_idx > 1) {
976         ptr_coeff[coeff_idx] =
977             temp_b1 * ptr_coeff[coeff_idx - 1] + temp_b2 * ptr_coeff[coeff_idx - 2];
978         coeff_idx--;
979         for (; coeff_idx > 1; coeff_idx--) {
980           ptr_coeff[coeff_idx] +=
981               temp_b1 * ptr_coeff[coeff_idx - 1] + temp_b2 * ptr_coeff[coeff_idx - 2];
982         }
983         ptr_coeff[1] += temp_b1 * ptr_coeff[0];
984       } else {
985         ptr_coeff[1] = temp_b1 * ptr_coeff[0];
986       }
987     }
988     ptr_zeros_done[idx] = 1;
989   }
990   if (coeff_count > 1) {
991     pstr_eq_filter_element->str_pole_zero_filter.fir_coeffs_present = 1;
992     pstr_eq_filter_element->str_pole_zero_filter.str_fir_filter.coeff_count = coeff_count;
993   } else {
994     pstr_eq_filter_element->str_pole_zero_filter.fir_coeffs_present = 0;
995     pstr_eq_filter_element->str_pole_zero_filter.str_fir_filter.coeff_count = 0;
996   }
997 }
998 
impd_drc_derive_filter_block(ia_drc_unique_td_filter_element_struct * pstr_unique_td_filter_element,ia_drc_filter_block_struct * pstr_filter_block,ia_drc_eq_filter_block_struct * pstr_eq_filter_block,VOID * ptr_scratch,WORD32 * scratch_used)999 static IA_ERRORCODE impd_drc_derive_filter_block(
1000     ia_drc_unique_td_filter_element_struct *pstr_unique_td_filter_element,
1001     ia_drc_filter_block_struct *pstr_filter_block,
1002     ia_drc_eq_filter_block_struct *pstr_eq_filter_block, VOID *ptr_scratch,
1003     WORD32 *scratch_used) {
1004   IA_ERRORCODE err_code = IA_NO_ERROR;
1005   LOOPIDX i, j;
1006   WORD32 filter_index;
1007   WORD32 temp_scratch_used = *scratch_used;
1008   ia_drc_intermediate_filter_params_struct str_intermediate_filter_params;
1009   ia_drc_eq_filter_element_struct *pstr_eq_filter_element;
1010   ia_drc_filter_element_struct *pstr_filter_element;
1011   ia_drc_matching_phase_filter_struct *pstr_matching_phase_filter =
1012       (ia_drc_matching_phase_filter_struct *)((pUWORD8)(ptr_scratch)) + temp_scratch_used;
1013 
1014   temp_scratch_used += sizeof(ia_drc_matching_phase_filter_struct) * FILTER_ELEMENT_COUNT_MAX;
1015 
1016   for (i = 0; i < pstr_filter_block->filter_element_count; i++) {
1017     if ((pstr_unique_td_filter_element[pstr_filter_block->filter_element[i].filter_element_index]
1018              .eq_filter_format == FILTER_ELEMENT_FORMAT_FIR) &&
1019         (pstr_filter_block->filter_element_count > 1)) {
1020       return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
1021     }
1022   }
1023   for (i = 0; i < pstr_filter_block->filter_element_count; i++) {
1024     pstr_filter_element = &pstr_filter_block->filter_element[i];
1025     filter_index = pstr_filter_element->filter_element_index;
1026     pstr_eq_filter_element = &pstr_eq_filter_block->str_eq_filter_element[i];
1027 
1028     if (pstr_unique_td_filter_element[filter_index].eq_filter_format ==
1029         FILTER_ELEMENT_FORMAT_POLE_ZERO) {
1030       err_code = impd_drc_derive_pole_zero_filter_params(
1031           &(pstr_unique_td_filter_element[filter_index]), &str_intermediate_filter_params);
1032       if (err_code & IA_FATAL_ERROR) {
1033         return err_code;
1034       }
1035 
1036       impd_drc_derive_eq_filter_elements(&str_intermediate_filter_params, pstr_eq_filter_element,
1037                                          (pUWORD8)(ptr_scratch) + temp_scratch_used);
1038       pstr_eq_filter_element->format = FILTER_ELEMENT_FORMAT_POLE_ZERO;
1039     } else {
1040       impd_drc_convert_fir_filter_params(
1041           pstr_unique_td_filter_element[filter_index].fir_filter_order,
1042           pstr_unique_td_filter_element[filter_index].fir_symmetry,
1043           pstr_unique_td_filter_element[filter_index].fir_coefficient,
1044           &pstr_eq_filter_element->str_fir_filter);
1045       pstr_eq_filter_element->format = FILTER_ELEMENT_FORMAT_FIR;
1046     }
1047     if (pstr_filter_element->filter_element_gain_present != 1) {
1048       pstr_eq_filter_element->element_gain_linear = 1.0f;
1049     } else {
1050       pstr_eq_filter_element->element_gain_linear =
1051           (FLOAT32)pow(10.0f, 0.05f * pstr_filter_element->filter_element_gain);
1052     }
1053     for (j = 0; j < pstr_unique_td_filter_element[filter_index].real_zero_count; j++) {
1054       if (pstr_unique_td_filter_element[filter_index].real_zero_radius[j] > 0.0f) {
1055         pstr_eq_filter_element->element_gain_linear =
1056             -pstr_eq_filter_element->element_gain_linear;
1057       }
1058     }
1059     impd_drc_derive_matching_phase_filter(&(pstr_unique_td_filter_element[filter_index]), i,
1060                                           &pstr_matching_phase_filter[i]);
1061   }
1062   pstr_eq_filter_block->str_matching_phase_filter_element_0 = pstr_matching_phase_filter[0];
1063   pstr_eq_filter_block->element_count = pstr_filter_block->filter_element_count;
1064 
1065   err_code = impd_drc_derive_element_phase_alignment_filters(
1066       pstr_matching_phase_filter, pstr_eq_filter_block, ptr_scratch, &temp_scratch_used);
1067   if (err_code & IA_FATAL_ERROR) {
1068     return err_code;
1069   }
1070 
1071   return err_code;
1072 }
1073 
impd_drc_derive_cascade_phase_alignment_filters(ia_drc_td_filter_cascade_struct * pstr_td_filter_cascade,const WORD32 channel_group_count,ia_drc_filter_cascade_t_domain_struct * pstr_filter_cascade_t_domain,VOID * ptr_scratch,WORD32 * scratch_used)1074 static IA_ERRORCODE impd_drc_derive_cascade_phase_alignment_filters(
1075     ia_drc_td_filter_cascade_struct *pstr_td_filter_cascade, const WORD32 channel_group_count,
1076     ia_drc_filter_cascade_t_domain_struct *pstr_filter_cascade_t_domain, VOID *ptr_scratch,
1077     WORD32 *scratch_used) {
1078   IA_ERRORCODE err_code = IA_NO_ERROR;
1079   WORD32 cascade_alignment_group_count = 0;
1080   ia_drc_cascade_alignment_group_struct *pstr_cascade_alignment_group =
1081       (ia_drc_cascade_alignment_group_struct *)ptr_scratch;
1082   *scratch_used +=
1083       sizeof(ia_drc_cascade_alignment_group_struct) * (EQ_MAX_CHANNEL_GROUP_COUNT / 2);
1084 
1085   impd_drc_derive_cascade_alignment_groups(
1086       channel_group_count, pstr_td_filter_cascade->eq_phase_alignment_present,
1087       (const WORD32(*)[EQ_MAX_CHANNEL_GROUP_COUNT])pstr_td_filter_cascade->eq_phase_alignment,
1088       &cascade_alignment_group_count, pstr_cascade_alignment_group);
1089 
1090   if (cascade_alignment_group_count > 0) {
1091     err_code = impd_drc_phase_align_cascade_group(
1092         cascade_alignment_group_count, pstr_cascade_alignment_group, pstr_filter_cascade_t_domain,
1093         ptr_scratch, scratch_used);
1094     if (err_code & IA_FATAL_ERROR) {
1095       return err_code;
1096     }
1097   }
1098 
1099   return err_code;
1100 }
1101 
impd_drc_derive_filter_cascade(ia_drc_unique_td_filter_element_struct * pstr_unique_td_filter_element,ia_drc_filter_block_struct * pstr_filter_block,ia_drc_td_filter_cascade_struct * pstr_td_filter_cascade,WORD32 channel_group_count,ia_drc_filter_cascade_t_domain_struct * pstr_filter_cascade_t_domain,VOID * ptr_scratch,WORD32 * scratch_used)1102 static IA_ERRORCODE impd_drc_derive_filter_cascade(
1103     ia_drc_unique_td_filter_element_struct *pstr_unique_td_filter_element,
1104     ia_drc_filter_block_struct *pstr_filter_block,
1105     ia_drc_td_filter_cascade_struct *pstr_td_filter_cascade, WORD32 channel_group_count,
1106     ia_drc_filter_cascade_t_domain_struct *pstr_filter_cascade_t_domain, VOID *ptr_scratch,
1107     WORD32 *scratch_used) {
1108   IA_ERRORCODE err_code = IA_NO_ERROR;
1109   LOOPIDX i, j;
1110 
1111   for (i = 0; i < channel_group_count; i++) {
1112     for (j = 0; j < pstr_td_filter_cascade->str_filter_block_refs[i].filter_block_count; j++) {
1113       err_code = impd_drc_derive_filter_block(
1114           pstr_unique_td_filter_element,
1115           &(pstr_filter_block[pstr_td_filter_cascade->str_filter_block_refs[i]
1116                                   .filter_block_index[j]]),
1117           &(pstr_filter_cascade_t_domain[i].str_eq_filter_block[j]), ptr_scratch, scratch_used);
1118       if (err_code & IA_FATAL_ERROR) {
1119         return err_code;
1120       }
1121     }
1122     pstr_filter_cascade_t_domain[i].cascade_gain_linear =
1123         (FLOAT32)pow(10.0f, 0.05f * pstr_td_filter_cascade->eq_cascade_gain[i]);
1124     pstr_filter_cascade_t_domain[i].block_count = j;
1125   }
1126 
1127   err_code = impd_drc_derive_cascade_phase_alignment_filters(
1128       pstr_td_filter_cascade, channel_group_count, pstr_filter_cascade_t_domain, ptr_scratch,
1129       scratch_used);
1130   if (err_code & IA_FATAL_ERROR) {
1131     return err_code;
1132   }
1133 
1134   return err_code;
1135 }
1136 
impd_drc_derive_subband_eq(ia_drc_eq_subband_gain_vector_struct * pstr_eq_subband_gain_vector,const WORD32 eq_subband_gain_count,ia_drc_subband_filter_struct * pstr_subband_filter)1137 static VOID impd_drc_derive_subband_eq(
1138     ia_drc_eq_subband_gain_vector_struct *pstr_eq_subband_gain_vector,
1139     const WORD32 eq_subband_gain_count, ia_drc_subband_filter_struct *pstr_subband_filter) {
1140   LOOPIDX idx;
1141 
1142   for (idx = 0; idx < eq_subband_gain_count; idx++) {
1143     pstr_subband_filter->subband_coeff[idx] =
1144         (FLOAT32)pstr_eq_subband_gain_vector->eq_subband_gain[idx];
1145   }
1146   pstr_subband_filter->coeff_count = eq_subband_gain_count;
1147 }
1148 
impd_drc_decode_eq_node_freq(const WORD32 eq_node_freq_index)1149 static FLOAT32 impd_drc_decode_eq_node_freq(const WORD32 eq_node_freq_index) {
1150   FLOAT32 eq_node_frequency;
1151 
1152   eq_node_frequency =
1153       (FLOAT32)(pow(STEP_RATIO_F_LOW, 1.0f + eq_node_freq_index * STEP_RATIO_COMPUTED));
1154 
1155   return eq_node_frequency;
1156 }
1157 
impd_drc_warp_freq_delta(const FLOAT32 f_subband,const FLOAT32 node_frequency_0,const WORD32 eq_node_freq_index)1158 static FLOAT32 impd_drc_warp_freq_delta(const FLOAT32 f_subband, const FLOAT32 node_frequency_0,
1159                                         const WORD32 eq_node_freq_index) {
1160   FLOAT32 wraped_delta_frequency;
1161 
1162   wraped_delta_frequency =
1163       (FLOAT32)((log10(f_subband) / log10(node_frequency_0) - 1.0f) / STEP_RATIO_COMPUTED -
1164                 (FLOAT32)eq_node_freq_index);
1165 
1166   return wraped_delta_frequency;
1167 }
1168 
impd_drc_interpolate_eq_gain(const WORD32 band_step,const FLOAT32 eq_gain_0,const FLOAT32 eq_gain_1,const FLOAT32 eq_slope_0,const FLOAT32 eq_slope_1,const FLOAT32 wrap_delta_freq,FLOAT32 * interpolated_gain)1169 static VOID impd_drc_interpolate_eq_gain(const WORD32 band_step, const FLOAT32 eq_gain_0,
1170                                          const FLOAT32 eq_gain_1, const FLOAT32 eq_slope_0,
1171                                          const FLOAT32 eq_slope_1, const FLOAT32 wrap_delta_freq,
1172                                          FLOAT32 *interpolated_gain) {
1173   FLOAT32 k1, k2, val_a, val_b;
1174   FLOAT32 nodes_per_octave_count = 3.128f;
1175   FLOAT32 gain_left = eq_gain_0;
1176   FLOAT32 gain_right = eq_gain_1;
1177   FLOAT32 slope_left = eq_slope_0 / nodes_per_octave_count;
1178   FLOAT32 slope_right = eq_slope_1 / nodes_per_octave_count;
1179   FLOAT32 band_step_inv = (FLOAT32)(1.0 / (FLOAT32)band_step);
1180   FLOAT32 band_step_inv_square = band_step_inv * band_step_inv;
1181 
1182   k1 = (gain_right - gain_left) * band_step_inv_square;
1183   k2 = slope_right + slope_left;
1184   val_a = (FLOAT32)(band_step_inv * (band_step_inv * k2 - 2.0 * k1));
1185   val_b = (FLOAT32)(3.0 * k1 - band_step_inv * (k2 + slope_left));
1186 
1187   *interpolated_gain =
1188       (((val_a * wrap_delta_freq + val_b) * wrap_delta_freq + slope_left) * wrap_delta_freq) +
1189       gain_left;
1190 }
1191 
impd_drc_interpolate_subband_spline(ia_drc_eq_subband_gain_spline_struct * pstr_eq_subband_gain_spline,const WORD32 eq_subband_gain_count,const WORD32 eq_subband_gain_format,const FLOAT32 audio_sample_rate,ia_drc_subband_filter_struct * pstr_subband_filter,VOID * ptr_scratch)1192 static IA_ERRORCODE impd_drc_interpolate_subband_spline(
1193     ia_drc_eq_subband_gain_spline_struct *pstr_eq_subband_gain_spline,
1194     const WORD32 eq_subband_gain_count, const WORD32 eq_subband_gain_format,
1195     const FLOAT32 audio_sample_rate, ia_drc_subband_filter_struct *pstr_subband_filter,
1196     VOID *ptr_scratch) {
1197   IA_ERRORCODE err_code = IA_NO_ERROR;
1198   LOOPIDX i, j;
1199   WORD32 eq_node_freq_index[32] = {0};
1200   WORD32 n_eq_nodes = pstr_eq_subband_gain_spline->n_eq_nodes;
1201   WORD32 eq_node_count_max = 33;
1202   WORD32 eq_node_index_max = eq_node_count_max - 1;
1203   WORD32 *ptr_eq_freq_delta = pstr_eq_subband_gain_spline->eq_freq_delta;
1204   FLOAT32 eq_gain[32] = {0}, eq_node_freq[32] = {0};
1205   FLOAT32 freq_subband, warped_delta_freq, g_eq_subband_db;
1206   FLOAT32 eq_gain_initial = pstr_eq_subband_gain_spline->eq_gain_initial;
1207   FLOAT32 *ptr_subband_center_freq = (FLOAT32 *)ptr_scratch;
1208   FLOAT32 *ptr_eq_slope = pstr_eq_subband_gain_spline->eq_slope;
1209   FLOAT32 *ptr_eq_gain_delta = pstr_eq_subband_gain_spline->eq_gain_delta;
1210   FLOAT32 *ptr_subband_coeff = pstr_subband_filter->subband_coeff;
1211 
1212   eq_gain[0] = eq_gain_initial;
1213   eq_node_freq_index[0] = 0;
1214   eq_node_freq[0] = impd_drc_decode_eq_node_freq(eq_node_freq_index[0]);
1215   for (i = 1; i < n_eq_nodes; i++) {
1216     eq_gain[i] = eq_gain[i - 1] + ptr_eq_gain_delta[i];
1217     eq_node_freq_index[i] = eq_node_freq_index[i - 1] + ptr_eq_freq_delta[i];
1218     eq_node_freq[i] = impd_drc_decode_eq_node_freq(eq_node_freq_index[i]);
1219   }
1220   if ((eq_node_freq[n_eq_nodes - 1] < audio_sample_rate * 0.5f) &&
1221       (eq_node_freq_index[n_eq_nodes - 1] < eq_node_index_max)) {
1222     ptr_eq_slope[n_eq_nodes] = 0;
1223     eq_gain[n_eq_nodes] = eq_gain[n_eq_nodes - 1];
1224     ptr_eq_freq_delta[n_eq_nodes] = eq_node_index_max - eq_node_freq_index[n_eq_nodes - 1];
1225     eq_node_freq_index[n_eq_nodes] = eq_node_index_max;
1226     eq_node_freq[n_eq_nodes] = impd_drc_decode_eq_node_freq(eq_node_freq_index[n_eq_nodes]);
1227     n_eq_nodes += 1;
1228   }
1229 
1230   err_code = impd_drc_derive_subband_center_freq(eq_subband_gain_count, eq_subband_gain_format,
1231                                                  audio_sample_rate, ptr_subband_center_freq);
1232   if (err_code & IA_FATAL_ERROR) {
1233     return err_code;
1234   }
1235 
1236   for (i = 0; i < n_eq_nodes - 1; i++) {
1237     for (j = 0; j < eq_subband_gain_count; j++) {
1238       freq_subband = MAX(ptr_subband_center_freq[j], eq_node_freq[0]);
1239       freq_subband = MIN(freq_subband, eq_node_freq[n_eq_nodes - 1]);
1240       if ((freq_subband >= eq_node_freq[i]) && (freq_subband <= eq_node_freq[i + 1])) {
1241         warped_delta_freq =
1242             impd_drc_warp_freq_delta(freq_subband, eq_node_freq[0], eq_node_freq_index[i]);
1243         impd_drc_interpolate_eq_gain(ptr_eq_freq_delta[i + 1], eq_gain[i], eq_gain[i + 1],
1244                                      ptr_eq_slope[i], ptr_eq_slope[i + 1], warped_delta_freq,
1245                                      &g_eq_subband_db);
1246 
1247         ptr_subband_coeff[j] = (FLOAT32)pow(2.0, (FLOAT32)(g_eq_subband_db / 6.0f));
1248       }
1249     }
1250   }
1251   pstr_subband_filter->coeff_count = eq_subband_gain_count;
1252 
1253   return err_code;
1254 }
1255 
impd_drc_derive_subband_gains(ia_drc_eq_coefficients_struct * pstr_eq_coefficients,const WORD32 eq_channel_group_count,const WORD32 * subband_gains_index,const FLOAT32 audio_sample_rate,const WORD32 eq_frame_size_subband,ia_drc_subband_filter_struct * pstr_subband_filter,VOID * ptr_scratch)1256 static IA_ERRORCODE impd_drc_derive_subband_gains(
1257     ia_drc_eq_coefficients_struct *pstr_eq_coefficients, const WORD32 eq_channel_group_count,
1258     const WORD32 *subband_gains_index, const FLOAT32 audio_sample_rate,
1259     const WORD32 eq_frame_size_subband, ia_drc_subband_filter_struct *pstr_subband_filter,
1260     VOID *ptr_scratch) {
1261   IA_ERRORCODE err_code = IA_NO_ERROR;
1262   LOOPIDX idx;
1263 
1264   for (idx = 0; idx < eq_channel_group_count; idx++) {
1265     if (pstr_eq_coefficients->eq_subband_gain_representation != 1) {
1266       impd_drc_derive_subband_eq(
1267           &(pstr_eq_coefficients->str_eq_subband_gain_vector[subband_gains_index[idx]]),
1268           pstr_eq_coefficients->eq_subband_gain_count, &(pstr_subband_filter[idx]));
1269     } else {
1270       err_code = impd_drc_interpolate_subband_spline(
1271           &(pstr_eq_coefficients->str_eq_subband_gain_spline[subband_gains_index[idx]]),
1272           pstr_eq_coefficients->eq_subband_gain_count,
1273           pstr_eq_coefficients->eq_subband_gain_format, audio_sample_rate,
1274           &(pstr_subband_filter[idx]), ptr_scratch);
1275       if (err_code & IA_FATAL_ERROR) {
1276         return err_code;
1277       }
1278     }
1279     pstr_subband_filter[idx].eq_frame_size_subband = eq_frame_size_subband;
1280   }
1281 
1282   return err_code;
1283 }
1284 
impd_drc_get_eq_complexity(ia_drc_eq_set_struct * pstr_eq_set,WORD32 * eq_complexity_level)1285 IA_ERRORCODE impd_drc_get_eq_complexity(ia_drc_eq_set_struct *pstr_eq_set,
1286                                         WORD32 *eq_complexity_level) {
1287   LOOPIDX idx_c, idx_b, i, j;
1288   WORD32 group;
1289   WORD32 fir_order_complexity = 0;
1290   WORD32 zero_pole_pair_count_complexity = 0;
1291   WORD32 subband_filter_complexity = 0;
1292   FLOAT32 complexity;
1293   ia_drc_filter_cascade_t_domain_struct *pstr_filter_cascade_t_domain;
1294   ia_drc_eq_filter_block_struct *pstr_eq_filter_block;
1295   ia_drc_eq_filter_element_struct *pstr_eq_filter_element;
1296 
1297   for (idx_c = 0; idx_c < pstr_eq_set->audio_channel_count; idx_c++) {
1298     group = pstr_eq_set->eq_channel_group_for_channel[idx_c];
1299     if (group >= 0) {
1300       switch (pstr_eq_set->domain) {
1301         case EQ_FILTER_DOMAIN_TIME: {
1302           pstr_filter_cascade_t_domain = &pstr_eq_set->str_filter_cascade_t_domain[group];
1303           for (idx_b = 0; idx_b < pstr_filter_cascade_t_domain->block_count; idx_b++) {
1304             pstr_eq_filter_block = &pstr_filter_cascade_t_domain->str_eq_filter_block[idx_b];
1305             for (i = 0; i < pstr_eq_filter_block->element_count; i++) {
1306               pstr_eq_filter_element = &pstr_eq_filter_block->str_eq_filter_element[i];
1307               switch (pstr_eq_filter_element->format) {
1308                 case FILTER_ELEMENT_FORMAT_POLE_ZERO:
1309                   zero_pole_pair_count_complexity +=
1310                       pstr_eq_filter_element->str_pole_zero_filter.section_count * 2;
1311                   if (pstr_eq_filter_element->str_pole_zero_filter.fir_coeffs_present) {
1312                     fir_order_complexity +=
1313                         pstr_eq_filter_element->str_pole_zero_filter.str_fir_filter.coeff_count -
1314                         1;
1315                   }
1316                   break;
1317                 case FILTER_ELEMENT_FORMAT_FIR:
1318                   fir_order_complexity += pstr_eq_filter_element->str_fir_filter.coeff_count - 1;
1319                   break;
1320                 default:
1321                   break;
1322               }
1323               for (j = 0; j < pstr_eq_filter_element->phase_alignment_filter_count; j++) {
1324                 zero_pole_pair_count_complexity +=
1325                     pstr_eq_filter_element->str_phase_alignment_filter[j].section_count * 2;
1326               }
1327             }
1328           }
1329           for (idx_b = 0; idx_b < pstr_filter_cascade_t_domain->phase_alignment_filter_count;
1330                idx_b++) {
1331             zero_pole_pair_count_complexity +=
1332                 pstr_filter_cascade_t_domain->str_phase_alignment_filter[idx_b].section_count * 2;
1333           }
1334         } break;
1335         case EQ_FILTER_DOMAIN_SUBBAND:
1336           subband_filter_complexity++;
1337           break;
1338         case EQ_FILTER_DOMAIN_NONE:
1339         default:
1340           break;
1341       }
1342     }
1343   }
1344   complexity = COMPLEXITY_W_SUBBAND_EQ * subband_filter_complexity;
1345   complexity += COMPLEXITY_W_FIR * fir_order_complexity;
1346   complexity += COMPLEXITY_W_IIR * zero_pole_pair_count_complexity;
1347   complexity = (FLOAT32)(log10(complexity / pstr_eq_set->audio_channel_count) / log10(2.0f));
1348   *eq_complexity_level = (WORD32)MAX(0, ceil(complexity));
1349   if (*eq_complexity_level > EQ_COMPLEXITY_LEVEL_MAX) {
1350     return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
1351   }
1352 
1353   return IA_NO_ERROR;
1354 }
1355 
impd_drc_derive_eq_set(ia_drc_eq_coefficients_struct * pstr_eq_coefficients,ia_drc_eq_instructions_struct * pstr_eq_instructions,const FLOAT32 audio_sample_rate,const WORD32 drc_frame_size,const WORD32 sub_band_domain_mode,ia_drc_eq_set_struct * pstr_eq_set,VOID * ptr_scratch,WORD32 * scratch_used)1356 IA_ERRORCODE impd_drc_derive_eq_set(ia_drc_eq_coefficients_struct *pstr_eq_coefficients,
1357                                     ia_drc_eq_instructions_struct *pstr_eq_instructions,
1358                                     const FLOAT32 audio_sample_rate, const WORD32 drc_frame_size,
1359                                     const WORD32 sub_band_domain_mode,
1360                                     ia_drc_eq_set_struct *pstr_eq_set, VOID *ptr_scratch,
1361                                     WORD32 *scratch_used) {
1362   IA_ERRORCODE err_code = IA_NO_ERROR;
1363   LOOPIDX idx;
1364   WORD32 eq_frame_size_subband;
1365 
1366   pstr_eq_set->domain = EQ_FILTER_DOMAIN_NONE;
1367 
1368   if (sub_band_domain_mode != SUBBAND_DOMAIN_MODE_OFF) {
1369     switch (sub_band_domain_mode) {
1370       case SUBBAND_DOMAIN_MODE_STFT256:
1371         if (pstr_eq_coefficients->eq_subband_gain_count != STFT256_AUDIO_CODEC_SUBBAND_COUNT) {
1372           return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
1373         }
1374         eq_frame_size_subband = drc_frame_size / STFT256_AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR;
1375         break;
1376       case SUBBAND_DOMAIN_MODE_QMF71:
1377         if (pstr_eq_coefficients->eq_subband_gain_count != QMF71_AUDIO_CODEC_SUBBAND_COUNT) {
1378           return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
1379         }
1380         eq_frame_size_subband = drc_frame_size / QMF71_AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR;
1381         break;
1382       case SUBBAND_DOMAIN_MODE_QMF64:
1383         if (pstr_eq_coefficients->eq_subband_gain_count != QMF64_AUDIO_CODEC_SUBBAND_COUNT) {
1384           return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
1385         }
1386         eq_frame_size_subband = drc_frame_size / QMF64_AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR;
1387         break;
1388       default:
1389         return IA_EXHEAACE_CONFIG_FATAL_DRC_INVALID_CONFIG;
1390         break;
1391     }
1392     if (pstr_eq_instructions->subband_gains_present == 1) {
1393       err_code = impd_drc_derive_subband_gains(
1394           pstr_eq_coefficients, pstr_eq_instructions->eq_channel_group_count,
1395           pstr_eq_instructions->subband_gains_index, audio_sample_rate, eq_frame_size_subband,
1396           pstr_eq_set->str_subband_filter, ptr_scratch);
1397       if (err_code & IA_FATAL_ERROR) {
1398         return err_code;
1399       }
1400     } else {
1401       if (pstr_eq_instructions->td_filter_cascade_present == 1) {
1402         err_code = impd_drc_derive_subband_gains_from_td_cascade(
1403             pstr_eq_coefficients->str_unique_td_filter_element,
1404             pstr_eq_coefficients->str_filter_block, &pstr_eq_instructions->str_td_filter_cascade,
1405             pstr_eq_coefficients->eq_subband_gain_format,
1406             pstr_eq_instructions->eq_channel_group_count, audio_sample_rate,
1407             eq_frame_size_subband, pstr_eq_set->str_subband_filter, ptr_scratch);
1408         if (err_code & IA_FATAL_ERROR) {
1409           return err_code;
1410         }
1411       } else {
1412         err_code = IA_EXHEAACE_CONFIG_NONFATAL_DRC_MISSING_CONFIG;
1413       }
1414     }
1415     pstr_eq_set->domain |= EQ_FILTER_DOMAIN_SUBBAND;
1416   } else {
1417     if (pstr_eq_instructions->td_filter_cascade_present == 1) {
1418       err_code = impd_drc_derive_filter_cascade(
1419           pstr_eq_coefficients->str_unique_td_filter_element,
1420           pstr_eq_coefficients->str_filter_block, &pstr_eq_instructions->str_td_filter_cascade,
1421           pstr_eq_instructions->eq_channel_group_count, pstr_eq_set->str_filter_cascade_t_domain,
1422           ptr_scratch, scratch_used);
1423       if (err_code & IA_FATAL_ERROR) {
1424         return err_code;
1425       }
1426     }
1427     pstr_eq_set->domain |= EQ_FILTER_DOMAIN_TIME;
1428   }
1429 
1430   pstr_eq_set->audio_channel_count = pstr_eq_instructions->eq_channel_count;
1431   pstr_eq_set->eq_channel_group_count = pstr_eq_instructions->eq_channel_group_count;
1432 
1433   for (idx = 0; idx < pstr_eq_instructions->eq_channel_count; idx++) {
1434     pstr_eq_set->eq_channel_group_for_channel[idx] =
1435         pstr_eq_instructions->eq_channel_group_for_channel[idx];
1436   }
1437 
1438   return err_code;
1439 }
1440