1/******************************************************************************
2 *
3 * Copyright (C) 2018 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#include <string.h>
24
25#include "impd_type_def.h"
26#include "impd_drc_extr_delta_coded_info.h"
27#include "impd_drc_common.h"
28#include "impd_drc_struct.h"
29#include "impd_parametric_drc_dec.h"
30#include "impd_drc_filter_bank.h"
31#include "impd_drc_multi_band.h"
32#include "impd_drc_gain_dec.h"
33#include "impd_drc_process_audio.h"
34#include "impd_drc_interface.h"
35#include "impd_drc_gain_dec.h"
36#include "impd_drc_eq.h"
37#include "impd_drc_gain_decoder.h"
38#include "impd_drc_rom.h"
39
40WORD32 impd_shape_filt_block_adapt(const FLOAT32 drc_gain,
41                                   shape_filter_block* shape_filter_block) {
42  //    WORD32 err = 0;
43  WORD32 i;
44  FLOAT32 warpedGain, x1, y1;
45  shape_filter_block->drc_gain_last = drc_gain;
46  for (i = 0; i < 4; i++) {
47    if (shape_filter_block->shape_filter[i].type == SHAPE_FILTER_TYPE_OFF)
48      continue;
49    else if (shape_filter_block->shape_filter[i].type ==
50                 SHAPE_FILTER_TYPE_LF_CUT ||
51             shape_filter_block->shape_filter[i].type ==
52                 SHAPE_FILTER_TYPE_HF_CUT) {
53      if (drc_gain < 1.0f)
54        warpedGain = -1.0f;
55      else
56        warpedGain =
57            (drc_gain - 1.0f) /
58            (drc_gain - 1.0f + shape_filter_block->shape_filter[i].gain_offset);
59      x1 = shape_filter_block->shape_filter[i].a1;
60    } else if (shape_filter_block->shape_filter[i].type ==
61                   SHAPE_FILTER_TYPE_LF_BOOST ||
62               shape_filter_block->shape_filter[i].type ==
63                   SHAPE_FILTER_TYPE_HF_BOOST) {
64      if (drc_gain >= 1.0f)
65        warpedGain = -1.0f;
66      else
67        warpedGain =
68            (1.0f - drc_gain) /
69            (1.0f +
70             drc_gain *
71                 (shape_filter_block->shape_filter[i].gain_offset - 1.0f));
72      x1 = shape_filter_block->shape_filter[i].b1;
73    }
74
75    if (warpedGain <= 0.0f) {
76      y1 = x1;
77    } else if (warpedGain <
78               shape_filter_block->shape_filter[i].warped_gain_max) {
79      y1 = x1 + shape_filter_block->shape_filter[i].factor * warpedGain;
80    } else {
81      y1 = shape_filter_block->shape_filter[i].y1_bound;
82    }
83    if (shape_filter_block->shape_filter[i].type == SHAPE_FILTER_TYPE_LF_CUT) {
84      shape_filter_block->shape_filter[i].b1 = y1;
85    } else if (shape_filter_block->shape_filter[i].type ==
86               SHAPE_FILTER_TYPE_HF_CUT) {
87      shape_filter_block->shape_filter[i].g_norm =
88          shape_filter_block->shape_filter[i].coeff_sum /
89          (shape_filter_block->shape_filter[i].partial_coeff_sum + y1);
90      shape_filter_block->shape_filter[i].b1 = y1;
91    } else if (shape_filter_block->shape_filter[i].type ==
92               SHAPE_FILTER_TYPE_HF_BOOST) {
93      shape_filter_block->shape_filter[i].g_norm =
94          (shape_filter_block->shape_filter[i].partial_coeff_sum + y1) /
95          shape_filter_block->shape_filter[i].coeff_sum;
96      shape_filter_block->shape_filter[i].a1 = y1;
97    } else if (shape_filter_block->shape_filter[i].type ==
98               SHAPE_FILTER_TYPE_LF_BOOST) {
99      shape_filter_block->shape_filter[i].a1 = y1;
100    }
101  }
102  return (0);
103}
104
105WORD32 resetshape_flter_block(shape_filter_block* shape_filter_block) {
106  WORD32 i, c;
107  shape_filter_block->drc_gain_last = -1.0f;
108  impd_shape_filt_block_adapt(1.0f, shape_filter_block);
109  for (i = 0; i < 4; i++) {
110    for (c = 0; c < MAX_CHANNEL_COUNT; c++) {
111      shape_filter_block->shape_filter[i].audio_in_state_1[c] = 0.0f;
112      shape_filter_block->shape_filter[i].audio_in_state_2[c] = 0.0f;
113      shape_filter_block->shape_filter[i].audio_out_state_1[c] = 0.0f;
114      shape_filter_block->shape_filter[i].audio_out_state_2[c] = 0.0f;
115    }
116  }
117  return (0);
118}
119
120WORD32 impd_shape_filt_block_init(
121    ia_shape_filter_block_params_struct* shape_flter_block_params,
122    shape_filter_block* shape_filter_block) {
123  // WORD32 err = 0;
124  FLOAT32 x1;
125  FLOAT32 x2 = 0.0f;
126  FLOAT32 radius;
127  if (shape_flter_block_params->lf_cut_filter_present) {
128    ia_shape_filter_params_struct* params =
129        &shape_flter_block_params->str_lf_cut_params;
130    shape_filter_block->shape_filter[0].type = SHAPE_FILTER_TYPE_LF_CUT;
131    shape_filter_block->shape_filter[0].gain_offset =
132        shape_filt_lf_gain_offset_tbl[params->corner_freq_index]
133                                     [params->filter_strength_index];
134    shape_filter_block->shape_filter[0].y1_bound =
135        shape_filt_lf_y1_bound_tbl[params->corner_freq_index]
136                                  [params->filter_strength_index];
137    x1 = -shape_filt_lf_radius_tbl[params->corner_freq_index];
138    shape_filter_block->shape_filter[0].warped_gain_max =
139        SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE /
140        (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE +
141         shape_filter_block->shape_filter[0].gain_offset);
142    shape_filter_block->shape_filter[0].factor =
143        (shape_filter_block->shape_filter[0].y1_bound - x1) /
144        shape_filter_block->shape_filter[0].warped_gain_max;
145    shape_filter_block->shape_filter[0].a1 = x1;
146
147  } else {
148    shape_filter_block->shape_filter[0].type = SHAPE_FILTER_TYPE_OFF;
149  }
150  if (shape_flter_block_params->lf_boost_filter_present) {
151    ia_shape_filter_params_struct* params =
152        &shape_flter_block_params->str_lf_boost_params;
153    shape_filter_block->shape_filter[1].type = SHAPE_FILTER_TYPE_LF_BOOST;
154    shape_filter_block->shape_filter[1].gain_offset =
155        shape_filt_lf_gain_offset_tbl[params->corner_freq_index]
156                                     [params->filter_strength_index];
157    shape_filter_block->shape_filter[1].y1_bound =
158        shape_filt_lf_y1_bound_tbl[params->corner_freq_index]
159                                  [params->filter_strength_index];
160    x1 = -shape_filt_lf_radius_tbl[params->corner_freq_index];
161    shape_filter_block->shape_filter[1].warped_gain_max =
162        SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE /
163        (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE +
164         shape_filter_block->shape_filter[1].gain_offset);
165    shape_filter_block->shape_filter[1].factor =
166        (shape_filter_block->shape_filter[1].y1_bound - x1) /
167        shape_filter_block->shape_filter[1].warped_gain_max;
168    shape_filter_block->shape_filter[1].b1 = x1;
169
170  } else {
171    shape_filter_block->shape_filter[1].type = SHAPE_FILTER_TYPE_OFF;
172  }
173  if (shape_flter_block_params->hf_cut_filter_present) {
174    ia_shape_filter_params_struct* params =
175        &shape_flter_block_params->str_hfCutParams;
176    shape_filter_block->shape_filter[2].type = SHAPE_FILTER_TYPE_HF_CUT;
177    shape_filter_block->shape_filter[2].gain_offset =
178        shape_filt_hf_gain_offset_tbl[params->corner_freq_index]
179                                     [params->filter_strength_index];
180    shape_filter_block->shape_filter[2].y1_bound =
181        shape_filt_hf_y1_bound_tbl[params->corner_freq_index]
182                                  [params->filter_strength_index];
183    radius = shape_filt_hf_radius_tbl[params->corner_freq_index];
184    x1 = (FLOAT32)(
185        -2.0f * radius *
186        cos(2.0f * M_PI *
187            shape_filt_cutoff_freq_norm_hf_tbl[params->corner_freq_index]));
188    x2 = radius * radius;
189    shape_filter_block->shape_filter[2].warped_gain_max =
190        SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE /
191        (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE +
192         shape_filter_block->shape_filter[2].gain_offset);
193    shape_filter_block->shape_filter[2].factor =
194        (shape_filter_block->shape_filter[2].y1_bound - x1) /
195        shape_filter_block->shape_filter[2].warped_gain_max;
196    shape_filter_block->shape_filter[2].coeff_sum = 1.0f + x1 + x2;
197    shape_filter_block->shape_filter[2].partial_coeff_sum = 1.0f + x2;
198    shape_filter_block->shape_filter[2].a1 = x1;
199    shape_filter_block->shape_filter[2].a2 = x2;
200    shape_filter_block->shape_filter[2].b2 = x2;
201  } else {
202    shape_filter_block->shape_filter[2].type = SHAPE_FILTER_TYPE_OFF;
203  }
204  if (shape_flter_block_params->hf_boost_filter_present) {
205    ia_shape_filter_params_struct* params =
206        &shape_flter_block_params->str_hf_boost_params;
207    shape_filter_block->shape_filter[3].type = SHAPE_FILTER_TYPE_HF_BOOST;
208    shape_filter_block->shape_filter[3].gain_offset =
209        shape_filt_hf_gain_offset_tbl[params->corner_freq_index]
210                                     [params->filter_strength_index];
211    shape_filter_block->shape_filter[3].y1_bound =
212        shape_filt_hf_y1_bound_tbl[params->corner_freq_index]
213                                  [params->filter_strength_index];
214    radius = shape_filt_hf_radius_tbl[params->corner_freq_index];
215    x1 = (FLOAT32)(
216        -2.0f * radius *
217        cos(2.0f * M_PI *
218            shape_filt_cutoff_freq_norm_hf_tbl[params->corner_freq_index]));
219    x2 = radius * radius;
220    shape_filter_block->shape_filter[3].warped_gain_max =
221        SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE /
222        (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE +
223         shape_filter_block->shape_filter[3].gain_offset);
224    shape_filter_block->shape_filter[3].factor =
225        (shape_filter_block->shape_filter[3].y1_bound - x1) /
226        shape_filter_block->shape_filter[3].warped_gain_max;
227    shape_filter_block->shape_filter[3].coeff_sum = 1.0f + x1 + x2;
228    shape_filter_block->shape_filter[3].partial_coeff_sum = 1.0f + x2;
229    shape_filter_block->shape_filter[3].b1 = x1;
230    shape_filter_block->shape_filter[3].b2 = x2;
231    shape_filter_block->shape_filter[3].a2 = x2;
232
233  } else {
234    shape_filter_block->shape_filter[3].type = SHAPE_FILTER_TYPE_OFF;
235  }
236  resetshape_flter_block(shape_filter_block);
237  shape_filter_block->shape_flter_block_flag = 1;
238  return (0);
239}
240
241WORD32 impd_shape_filt_block_time_process(
242    shape_filter_block* shape_filter_block, FLOAT32* drc_gain,
243    const WORD32 channel, FLOAT32* audio_in, WORD32 start, WORD32 end) {
244  WORD32 i, j, err = 0;
245  FLOAT32 audio_out;
246
247  if (shape_filter_block->shape_flter_block_flag) {
248    for (i = start; i < end; i++) {
249      FLOAT32 tmp = audio_in[i];
250      for (j = 0; j < 4; j++) {
251        if (shape_filter_block->shape_filter[j].type ==
252                SHAPE_FILTER_TYPE_LF_CUT ||
253            shape_filter_block->shape_filter[j].type ==
254                SHAPE_FILTER_TYPE_LF_BOOST) {
255          audio_out = tmp +
256                      shape_filter_block->shape_filter[j].b1 *
257                          shape_filter_block->shape_filter[j]
258                              .audio_in_state_1[channel] -
259                      shape_filter_block->shape_filter[j].a1 *
260                          shape_filter_block->shape_filter[j]
261                              .audio_out_state_1[channel];
262          shape_filter_block->shape_filter[j].audio_in_state_1[channel] = tmp;
263          shape_filter_block->shape_filter[j].audio_out_state_1[channel] =
264              audio_out;
265
266        } else if (shape_filter_block->shape_filter[j].type ==
267                       SHAPE_FILTER_TYPE_HF_CUT ||
268                   shape_filter_block->shape_filter[j].type ==
269                       SHAPE_FILTER_TYPE_HF_BOOST) {
270          audio_out = shape_filter_block->shape_filter[j].g_norm * tmp +
271                      shape_filter_block->shape_filter[j].b1 *
272                          shape_filter_block->shape_filter[j]
273                              .audio_in_state_1[channel] +
274                      shape_filter_block->shape_filter[j].b2 *
275                          shape_filter_block->shape_filter[j]
276                              .audio_in_state_2[channel] -
277                      shape_filter_block->shape_filter[j].a1 *
278                          shape_filter_block->shape_filter[j]
279                              .audio_out_state_1[channel] -
280                      shape_filter_block->shape_filter[j].a2 *
281                          shape_filter_block->shape_filter[j]
282                              .audio_out_state_2[channel];
283          shape_filter_block->shape_filter[j].audio_in_state_2[channel] =
284              shape_filter_block->shape_filter[j].audio_in_state_1[channel];
285          shape_filter_block->shape_filter[j].audio_in_state_1[channel] =
286              shape_filter_block->shape_filter[j].g_norm * tmp;
287          shape_filter_block->shape_filter[j].audio_out_state_2[channel] =
288              shape_filter_block->shape_filter[j].audio_out_state_1[channel];
289          shape_filter_block->shape_filter[j].audio_out_state_1[channel] =
290              audio_out;
291        } else {
292          audio_out = tmp;
293        }
294        tmp = audio_out;
295      }
296
297      audio_in[i] = audio_out * drc_gain[i];
298    }
299
300  } else {
301    for (i = start; i < end; i++) {
302      audio_in[i] = audio_in[i] * drc_gain[i];
303    }
304  }
305
306  return err;
307}
308