1/******************************************************************************
2 *
3 * Copyright (C) 2015 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#include <stdio.h>
21#include <stdlib.h>
22#include <math.h>
23
24#include "impd_type_def.h"
25#include "impd_drc_uni_tables.h"
26#include "impd_drc_uni_common.h"
27#include "impd_drc_struct.h"
28#include "impd_drc_filter_bank.h"
29#include "impd_drc_rom.h"
30
31VOID impd_compute_filt_coeff(WORD32 crossover_freq_idx,
32                             ia_iir_filter_struct* pstr_lp_filt_coeff,
33                             ia_iir_filter_struct* pstr_hp_filt_coeff,
34                             ia_iir_filter_struct* pstr_ap_filt_coeff,
35                             WORD32 filter_type) {
36  FLOAT32 gamma = normal_cross_freq[crossover_freq_idx].gamma;
37  FLOAT32 delta = normal_cross_freq[crossover_freq_idx].delta;
38
39  if (filter_type == 0 || filter_type == 2) {
40    pstr_lp_filt_coeff->a0 = 1.0f;
41    pstr_lp_filt_coeff->a1 = 2.0f * (gamma - delta);
42    pstr_lp_filt_coeff->a2 = 2.0f * (gamma + delta) - 1.0f;
43    pstr_lp_filt_coeff->b0 = gamma;
44    pstr_lp_filt_coeff->b1 = 2.0f * gamma;
45    pstr_lp_filt_coeff->b2 = gamma;
46
47    pstr_hp_filt_coeff->a0 = 1.0f;
48    pstr_hp_filt_coeff->a1 = pstr_lp_filt_coeff->a1;
49    pstr_hp_filt_coeff->a2 = pstr_lp_filt_coeff->a2;
50    pstr_hp_filt_coeff->b0 = delta;
51    pstr_hp_filt_coeff->b1 = -2.0f * delta;
52    pstr_hp_filt_coeff->b2 = delta;
53  }
54
55  if (filter_type == 1 || filter_type == 2) {
56    pstr_ap_filt_coeff->a0 = 1.0f;
57    pstr_ap_filt_coeff->a1 = 2.0f * (gamma - delta);
58    ;
59    pstr_ap_filt_coeff->a2 = 2.0f * (gamma + delta) - 1.0f;
60    ;
61    pstr_ap_filt_coeff->b0 = pstr_ap_filt_coeff->a2;
62    pstr_ap_filt_coeff->b1 = pstr_ap_filt_coeff->a1;
63    pstr_ap_filt_coeff->b2 = pstr_ap_filt_coeff->a0;
64  }
65
66  return;
67}
68
69WORD32 impd_initialize_filt_bank(WORD32 num_sub_bands,
70                                 ia_gain_params_struct* gain_params,
71                                 ia_drc_filter_bank_struct* drc_filter_bank) {
72  ia_two_band_filt_struct* str_two_band_bank;
73  ia_three_band_filt_struct* str_three_band_bank;
74  ia_four_band_filt_struct* str_four_band_bank;
75  drc_filter_bank->complexity = 0;
76  drc_filter_bank->num_bands = num_sub_bands;
77
78  if (num_sub_bands == 1) {
79    return 0;
80  } else if (num_sub_bands == 2) {
81    str_two_band_bank = &drc_filter_bank->str_two_band_bank;
82    impd_compute_filt_coeff(gain_params[1].crossover_freq_idx,
83                            &(str_two_band_bank->low_pass),
84                            &(str_two_band_bank->high_pass), NULL, 0);
85  } else if (num_sub_bands == 3) {
86    str_three_band_bank = &drc_filter_bank->str_three_band_bank;
87
88    impd_compute_filt_coeff(gain_params[1].crossover_freq_idx,
89                            &(str_three_band_bank->str_low_pass_stage_2),
90                            &(str_three_band_bank->str_high_pass_stage_2),
91                            &(str_three_band_bank->str_all_pass_stage_2), 2);
92    impd_compute_filt_coeff(gain_params[2].crossover_freq_idx,
93                            &(str_three_band_bank->str_low_pass_stage_1),
94                            &(str_three_band_bank->str_high_pass_stage_1), NULL,
95                            0);
96  }
97
98  else if (num_sub_bands == 4) {
99    str_four_band_bank = &drc_filter_bank->str_four_band_bank;
100
101    impd_compute_filt_coeff(gain_params[1].crossover_freq_idx,
102                            &(str_four_band_bank->str_low_pass_stage_3_low),
103                            &(str_four_band_bank->str_high_pass_stage_3_low),
104                            &(str_four_band_bank->str_all_pass_stage_2_high),
105                            2);
106    impd_compute_filt_coeff(gain_params[2].crossover_freq_idx,
107                            &(str_four_band_bank->str_low_pass_stage_1),
108                            &(str_four_band_bank->str_high_pass_stage_1), NULL,
109                            0);
110    impd_compute_filt_coeff(gain_params[3].crossover_freq_idx,
111                            &(str_four_band_bank->str_low_pass_stage_3_high),
112                            &(str_four_band_bank->str_high_pass_stage_3_high),
113                            &(str_four_band_bank->str_all_pass_stage_2_low), 2);
114  } else {
115    return -1;
116  }
117
118  return 0;
119}
120
121WORD32 impd_init_all_filter_banks(
122    ia_uni_drc_coeffs_struct* str_p_loc_drc_coefficients_uni_drc,
123    ia_drc_instructions_struct* str_drc_instruction_str,
124    ia_filter_banks_struct* ia_filter_banks_struct) {
125  WORD32 err_code = 0;
126  WORD32 b, g, i, k, m, s, crossover_freq_idx, num_ch_in_groups,
127      num_ph_align_ch_groups;
128  WORD32 match_found = 0, num_filter;
129  WORD32 cascade_cross_idx[CHANNEL_GROUP_COUNT_MAX + 1]
130                          [CHANNEL_GROUP_COUNT_MAX * 3];
131  WORD32 count[CHANNEL_GROUP_COUNT_MAX + 1];
132
133  num_ch_in_groups = 0;
134  num_ph_align_ch_groups = str_drc_instruction_str->num_drc_ch_groups;
135
136  for (g = 0; g < str_drc_instruction_str->num_drc_ch_groups; g++) {
137    num_ch_in_groups += str_drc_instruction_str->num_chan_per_ch_group[g];
138  }
139
140  if (num_ch_in_groups < str_drc_instruction_str->audio_num_chan) {
141    num_ph_align_ch_groups++;
142  }
143
144  ia_filter_banks_struct->nfilter_banks =
145      str_drc_instruction_str->num_drc_ch_groups;
146  ia_filter_banks_struct->num_ph_align_ch_groups = num_ph_align_ch_groups;
147
148  if (str_p_loc_drc_coefficients_uni_drc == NULL) {
149    ia_filter_banks_struct->str_drc_filter_bank->num_bands = 1;
150  } else {
151    for (g = 0; g < str_drc_instruction_str->num_drc_ch_groups; g++) {
152      err_code = impd_initialize_filt_bank(
153          str_p_loc_drc_coefficients_uni_drc
154              ->gain_set_params[str_drc_instruction_str
155                                    ->gain_set_index_for_channel_group[g]]
156              .band_count,
157          str_p_loc_drc_coefficients_uni_drc
158              ->gain_set_params[str_drc_instruction_str
159                                    ->gain_set_index_for_channel_group[g]]
160              .gain_params,
161          &(ia_filter_banks_struct->str_drc_filter_bank[g]));
162      if (err_code != 0) return (err_code);
163    }
164  }
165
166  for (g = 0; g < CHANNEL_GROUP_COUNT_MAX + 1; g++) {
167    count[g] = 0;
168  }
169  for (g = 0; g < str_drc_instruction_str->num_drc_ch_groups; g++) {
170    for (b = 1;
171         b < str_p_loc_drc_coefficients_uni_drc
172                 ->gain_set_params[str_drc_instruction_str
173                                       ->gain_set_index_for_channel_group[g]]
174                 .band_count;
175         b++) {
176      crossover_freq_idx =
177          str_p_loc_drc_coefficients_uni_drc
178              ->gain_set_params[str_drc_instruction_str
179                                    ->gain_set_index_for_channel_group[g]]
180              .gain_params[b]
181              .crossover_freq_idx;
182      for (k = 0; k < num_ph_align_ch_groups; k++) {
183        if (k != g) {
184          cascade_cross_idx[k][count[k]] = crossover_freq_idx;
185          count[k]++;
186          if (count[k] > CHANNEL_GROUP_COUNT_MAX * 3) {
187            return -1;
188          }
189        }
190      }
191    }
192  }
193
194  i = 0;
195  while (i < count[0]) {
196    crossover_freq_idx = cascade_cross_idx[0][i];
197    match_found = 0;
198    for (g = 1; g < num_ph_align_ch_groups; g++) {
199      match_found = 0;
200      for (k = 0; k < count[g]; k++) {
201        if (cascade_cross_idx[g][k] == crossover_freq_idx) {
202          match_found = 1;
203          break;
204        }
205      }
206      if (match_found == 0) break;
207    }
208    if (match_found == 1) {
209      for (g = 0; g < num_ph_align_ch_groups; g++) {
210        for (m = 0; m < count[g]; m++) {
211          if (cascade_cross_idx[g][m] == crossover_freq_idx) {
212            for (s = m + 1; s < count[g]; s++) {
213              cascade_cross_idx[g][s - 1] = cascade_cross_idx[g][s];
214            }
215            count[g]--;
216            break;
217          }
218        }
219      }
220      i = 0;
221    } else {
222      i++;
223    }
224  }
225
226  for (g = 0; g < num_ph_align_ch_groups; g++) {
227    num_filter = count[g];
228    if (num_filter > 0) {
229      for (i = 0; i < num_filter; i++) {
230        impd_compute_filt_coeff(
231            cascade_cross_idx[g][i], NULL, NULL,
232            &(ia_filter_banks_struct->str_drc_filter_bank[g]
233                  .str_all_pass_cascade.str_all_pass_cascade_filter[i]
234                  .str_all_pass_stage),
235            1);
236      }
237      ia_filter_banks_struct->str_drc_filter_bank[g]
238          .str_all_pass_cascade.num_filter = num_filter;
239    }
240
241    if (err_code != 0) return (err_code);
242  }
243
244  return 0;
245}
246
247VOID impd_iir_second_order_filter_all_pass(ia_iir_filter_struct* filter,
248                                           WORD32 chan_idx, WORD32 frame_len,
249                                           FLOAT32* input, FLOAT32* output) {
250  WORD32 i;
251  FLOAT32 tmp;
252  FLOAT32 a1 = filter->a1;
253  FLOAT32 a2 = filter->a2;
254  FLOAT32 b0 = filter->b0;
255  FLOAT32 b1 = filter->b1;
256  FLOAT32 b2 = filter->b2;
257
258  FLOAT32 st1 = filter->x_p[chan_idx * 2];
259  FLOAT32 st2 = filter->y_p[chan_idx * 2];
260
261  for (i = 0; i < frame_len; i++) {
262    tmp = input[i];
263    output[i] = b0 * tmp + st1;
264    st1 = b1 * tmp - a1 * output[i] + st2;
265    st2 = b2 * tmp - a2 * output[i];
266  }
267  filter->x_p[chan_idx * 2] = st1;
268  filter->y_p[chan_idx * 2] = st2;
269
270  return;
271}
272
273VOID impd_apply_low_high_filter(ia_iir_filter_struct* pstr_lp_filt_coeff,
274                                ia_iir_filter_struct* pstr_hp_filt_coeff,
275                                WORD32 chan_idx, WORD32 frame_len,
276                                FLOAT32* input, FLOAT32* output[]) {
277  WORD32 i;
278  FLOAT32 tmp, tmp1;
279  FLOAT32 a1_l = pstr_lp_filt_coeff->a1;
280  FLOAT32 a2_l = pstr_lp_filt_coeff->a2;
281  FLOAT32 b0_l = pstr_lp_filt_coeff->b0;
282  FLOAT32 b1_l = pstr_lp_filt_coeff->b1;
283  FLOAT32 b2_l = pstr_lp_filt_coeff->b2;
284
285  FLOAT32 st1_l = pstr_lp_filt_coeff->x_p[chan_idx * 2 + 0];
286  FLOAT32 st2_l = pstr_lp_filt_coeff->x_p[chan_idx * 2 + 1];
287  FLOAT32 st3_l = pstr_lp_filt_coeff->y_p[chan_idx * 2 + 0];
288  FLOAT32 st4_l = pstr_lp_filt_coeff->y_p[chan_idx * 2 + 1];
289
290  FLOAT32 a1_h = pstr_hp_filt_coeff->a1;
291  FLOAT32 a2_h = pstr_hp_filt_coeff->a2;
292  FLOAT32 b0_h = pstr_hp_filt_coeff->b0;
293  FLOAT32 b1_h = pstr_hp_filt_coeff->b1;
294  FLOAT32 b2_h = pstr_hp_filt_coeff->b2;
295
296  FLOAT32 st1_h = pstr_hp_filt_coeff->x_p[chan_idx * 2 + 0];
297  FLOAT32 st2_h = pstr_hp_filt_coeff->x_p[chan_idx * 2 + 1];
298  FLOAT32 st3_h = pstr_hp_filt_coeff->y_p[chan_idx * 2 + 0];
299  FLOAT32 st4_h = pstr_hp_filt_coeff->y_p[chan_idx * 2 + 1];
300
301  FLOAT32* output_low = output[0];
302  FLOAT32* output_high = output[1];
303
304  for (i = 0; i < frame_len; i++) {
305    tmp1 = input[i];
306    tmp = b0_l * tmp1 + st1_l;
307    st1_l = b1_l * tmp1 - a1_l * tmp + st2_l;
308    st2_l = b2_l * tmp1 - a2_l * tmp;
309
310    output_low[i] = b0_l * tmp + st3_l;
311    st3_l = b1_l * tmp - a1_l * output_low[i] + st4_l;
312    st4_l = b2_l * tmp - a2_l * output_low[i];
313
314    tmp = b0_h * tmp1 + st1_h;
315    st1_h = b1_h * tmp1 - a1_h * tmp + st2_h;
316    st2_h = b2_h * tmp1 - a2_h * tmp;
317
318    output_high[i] = b0_h * tmp + st3_h;
319    st3_h = b1_h * tmp - a1_h * output_high[i] + st4_h;
320    st4_h = b2_h * tmp - a2_h * output_high[i];
321  }
322  pstr_lp_filt_coeff->x_p[chan_idx * 2 + 0] = st1_l;
323  pstr_lp_filt_coeff->x_p[chan_idx * 2 + 1] = st2_l;
324  pstr_lp_filt_coeff->y_p[chan_idx * 2 + 0] = st3_l;
325  pstr_lp_filt_coeff->y_p[chan_idx * 2 + 1] = st4_l;
326
327  pstr_hp_filt_coeff->x_p[chan_idx * 2 + 0] = st1_h;
328  pstr_hp_filt_coeff->x_p[chan_idx * 2 + 1] = st2_h;
329  pstr_hp_filt_coeff->y_p[chan_idx * 2 + 0] = st3_h;
330  pstr_hp_filt_coeff->y_p[chan_idx * 2 + 1] = st4_h;
331
332  return;
333}
334VOID impd_two_band_filter_process(ia_two_band_filt_struct* str_two_band_bank,
335                                  WORD32 chan_idx, WORD32 frame_len,
336                                  FLOAT32* input, FLOAT32* output[]) {
337  ia_iir_filter_struct* pstr_lp_filt_coeff = &str_two_band_bank->low_pass;
338  ia_iir_filter_struct* pstr_hp_filt_coeff = &str_two_band_bank->high_pass;
339
340  impd_apply_low_high_filter(pstr_lp_filt_coeff, pstr_hp_filt_coeff, chan_idx,
341                             frame_len, input, output);
342  return;
343}
344
345VOID impd_three_band_filter_process(
346    ia_three_band_filt_struct* str_three_band_bank, WORD32 c, WORD32 size,
347    FLOAT32* input, FLOAT32* output[]) {
348  WORD32 err_code = 0;
349  ia_iir_filter_struct* all_pass_filter;
350  ia_iir_filter_struct* pstr_lp_filt_coeff =
351      &str_three_band_bank->str_low_pass_stage_1;
352  ia_iir_filter_struct* pstr_hp_filt_coeff =
353      &str_three_band_bank->str_high_pass_stage_1;
354  FLOAT32* output1[2];
355  output1[0] = output[0];
356  output1[1] = output[1];
357
358  impd_apply_low_high_filter(pstr_lp_filt_coeff, pstr_hp_filt_coeff, c, size,
359                             input, output1);
360
361  all_pass_filter = &str_three_band_bank->str_all_pass_stage_2;
362
363  impd_iir_second_order_filter_all_pass(all_pass_filter, c, size, output1[1],
364                                        output[2]);
365  pstr_lp_filt_coeff = &str_three_band_bank->str_low_pass_stage_2;
366  pstr_hp_filt_coeff = &str_three_band_bank->str_high_pass_stage_2;
367
368  impd_apply_low_high_filter(pstr_lp_filt_coeff, pstr_hp_filt_coeff, c, size,
369                             output1[0], output1);
370
371  return;
372}
373
374VOID impd_four_band_filter_process(ia_four_band_filt_struct* str_four_band_bank,
375                                   WORD32 cha_idx, WORD32 win_size,
376                                   FLOAT32* input, FLOAT32* output[]) {
377  WORD32 err_code = 0;
378  ia_iir_filter_struct* all_pass_filter;
379  ia_iir_filter_struct* pstr_lp_filt_coeff =
380      &str_four_band_bank->str_low_pass_stage_1;
381  ia_iir_filter_struct* pstr_hp_filt_coeff =
382      &str_four_band_bank->str_high_pass_stage_1;
383  FLOAT32* output1[2];
384  FLOAT32* output2[2];
385  output1[0] = output[0];
386  output1[1] = output[1];
387  output2[0] = output[2];
388  output2[1] = output[3];
389
390  impd_apply_low_high_filter(pstr_lp_filt_coeff, pstr_hp_filt_coeff, cha_idx,
391                             win_size, input, output1);
392
393  all_pass_filter = &str_four_band_bank->str_all_pass_stage_2_low;
394
395  impd_iir_second_order_filter_all_pass(all_pass_filter, cha_idx, win_size,
396                                        output1[0], output1[0]);
397
398  all_pass_filter = &str_four_band_bank->str_all_pass_stage_2_high;
399
400  impd_iir_second_order_filter_all_pass(all_pass_filter, cha_idx, win_size,
401                                        output1[1], output2[0]);
402
403  pstr_lp_filt_coeff = &str_four_band_bank->str_low_pass_stage_3_low;
404  pstr_hp_filt_coeff = &str_four_band_bank->str_high_pass_stage_3_low;
405
406  impd_apply_low_high_filter(pstr_lp_filt_coeff, pstr_hp_filt_coeff, cha_idx,
407                             win_size, output1[0], output1);
408
409  pstr_lp_filt_coeff = &str_four_band_bank->str_low_pass_stage_3_high;
410  pstr_hp_filt_coeff = &str_four_band_bank->str_high_pass_stage_3_high;
411
412  impd_apply_low_high_filter(pstr_lp_filt_coeff, pstr_hp_filt_coeff, cha_idx,
413                             win_size, output2[0], output2);
414
415  return;
416}
417
418VOID impd_all_pass_cascade_process(
419    ia_all_pass_cascade_struct* str_all_pass_cascade, WORD32 ch_idx,
420    WORD32 win_size, FLOAT32* input) {
421  WORD32 i;
422
423  for (i = 0; i < str_all_pass_cascade->num_filter; i++) {
424    impd_iir_second_order_filter_all_pass(
425        &(str_all_pass_cascade->str_all_pass_cascade_filter[i]
426              .str_all_pass_stage),
427        ch_idx, win_size, input, input);
428  }
429
430  return;
431}