Coverage Report

Created: 2024-06-21 06:45

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