xref: /aosp_15_r20/external/libxaac/encoder/drc_src/impd_drc_gain_calculator.c (revision 15dc779a375ca8b5125643b829a8aa4b70d7f451)
1 /******************************************************************************
2  *                                                                            *
3  * Copyright (C) 2023 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19  */
20 #include <math.h>
21 #include <float.h>
22 #include "ixheaac_type_def.h"
23 #include "ixheaac_error_standards.h"
24 #include "ixheaace_error_codes.h"
25 
26 #include "iusace_cnst.h"
27 #include "iusace_block_switch_const.h"
28 #include "iusace_bitbuffer.h"
29 
30 #include "impd_drc_common_enc.h"
31 #include "impd_drc_uni_drc.h"
32 #include "impd_drc_tables.h"
33 #include "impd_drc_api.h"
34 
35 #include "iusace_tns_usac.h"
36 #include "iusace_psy_mod.h"
37 #include "ixheaace_sbr_header.h"
38 #include "ixheaace_config.h"
39 #include "iusace_config.h"
40 
41 #include "iusace_rom.h"
42 #include "iusace_fft.h"
43 
44 #include "impd_drc_uni_drc_eq.h"
45 #include "impd_drc_uni_drc_filter_bank.h"
46 #include "impd_drc_gain_enc.h"
47 #include "impd_drc_struct_def.h"
48 #include "impd_drc_enc.h"
49 #include "ixheaace_common_utils.h"
50 
impd_drc_compand_update_volume(ia_drc_compand_chan_param_struct * pstr_channel_param,FLOAT64 in_value)51 static VOID impd_drc_compand_update_volume(ia_drc_compand_chan_param_struct *pstr_channel_param,
52                                            FLOAT64 in_value) {
53   FLOAT64 delta = in_value - pstr_channel_param->volume;
54 
55   if (delta <= 0.0) {
56     pstr_channel_param->volume += delta * pstr_channel_param->decay;
57   } else {
58     pstr_channel_param->volume += delta * pstr_channel_param->attack;
59   }
60 }
61 
impd_drc_compand_get_volume(ia_drc_compand_struct * pstr_drc_compand,FLOAT64 in_lin)62 static FLOAT64 impd_drc_compand_get_volume(ia_drc_compand_struct *pstr_drc_compand,
63                                            FLOAT64 in_lin) {
64   ULOOPIDX idx;
65   FLOAT64 in_log, out_log;
66   ia_drc_compand_segment_struct *pstr_compand_segment;
67 
68   if (in_lin < pstr_drc_compand->in_min_lin) {
69     return pstr_drc_compand->out_min_lin;
70   }
71 
72   if (fabs(in_lin) <= FLT_EPSILON) {
73     in_log = log(FLT_EPSILON);
74   }
75   else {
76     in_log = log(fabs(in_lin));
77   }
78 
79   for (idx = 1; idx < pstr_drc_compand->nb_segments; idx++) {
80     if (in_log <= pstr_drc_compand->str_segment[idx].x) {
81       break;
82     }
83   }
84 
85   pstr_compand_segment = &pstr_drc_compand->str_segment[idx - 1];
86   in_log -= pstr_compand_segment->x;
87   out_log = pstr_compand_segment->y +
88             in_log * (pstr_compand_segment->a * in_log + pstr_compand_segment->b);
89 
90   return exp(out_log);
91 }
92 
impd_drc_td_drc_gain_calc_process(ia_drc_gain_enc_struct * pstr_drc_gain_enc,WORD32 drc_coefficients_uni_drc_idx,WORD32 gain_set_idx,WORD32 num_samples,FLOAT32 * in_buff,FLOAT32 * out_buff)93 VOID impd_drc_td_drc_gain_calc_process(ia_drc_gain_enc_struct *pstr_drc_gain_enc,
94                                        WORD32 drc_coefficients_uni_drc_idx, WORD32 gain_set_idx,
95                                        WORD32 num_samples, FLOAT32 *in_buff, FLOAT32 *out_buff) {
96   LOOPIDX idx;
97   FLOAT64 gain;
98   ia_drc_compand_chan_param_struct *pstr_channel_param;
99   ia_drc_compand_struct *pstr_drc_compand =
100       &pstr_drc_gain_enc->str_drc_compand[drc_coefficients_uni_drc_idx][gain_set_idx];
101 
102   pstr_channel_param = &pstr_drc_compand->str_channel_param;
103 
104   for (idx = 0; idx < num_samples; idx++) {
105     impd_drc_compand_update_volume(pstr_channel_param, fabs((FLOAT64)in_buff[idx] / 32768.0));
106 
107     gain = impd_drc_compand_get_volume(pstr_drc_compand, pstr_channel_param->volume);
108     out_buff[idx] = (FLOAT32)(20.0 * log10(gain));
109   }
110 }
111 
impd_drc_td_drc_gain_calc_init(ia_drc_gain_enc_struct * pstr_drc_gain_enc,WORD32 drc_coefficients_uni_drc_idx,WORD32 gain_set_idx)112 IA_ERRORCODE impd_drc_td_drc_gain_calc_init(ia_drc_gain_enc_struct *pstr_drc_gain_enc,
113                                             WORD32 drc_coefficients_uni_drc_idx,
114                                             WORD32 gain_set_idx) {
115   ULOOPIDX i, j;
116   UWORD32 num_points;
117   FLOAT64 g1, g2;
118   FLOAT64 x, y, cx, cy, r;
119   FLOAT64 inp_1, inp_2, out_1, out_2, theta, length, radius;
120   ia_drc_compand_struct *pstr_drc_compand;
121   ia_drc_compand_chan_param_struct *pstr_chan_param;
122 
123   if ((drc_coefficients_uni_drc_idx >= MAX_DRC_COEFF_COUNT) ||
124       (gain_set_idx >= GAIN_SET_COUNT_MAX)) {
125     return IA_EXHEAACE_CONFIG_FATAL_DRC_COMPAND_FAILED;
126   }
127 
128   pstr_drc_compand =
129       &pstr_drc_gain_enc->str_drc_compand[drc_coefficients_uni_drc_idx][gain_set_idx];
130 
131   for (i = 0; i < pstr_drc_compand->nb_points; i++) {
132     if (i && pstr_drc_compand->str_segment[2 * ((i - 1) + 1)].x >
133                  pstr_drc_compand->str_segment[2 * ((i) + 1)].x) {
134       return IA_EXHEAACE_CONFIG_FATAL_DRC_COMPAND_FAILED;
135     }
136     pstr_drc_compand->str_segment[2 * (i + 1)].y -= pstr_drc_compand->str_segment[2 * (i + 1)].x;
137   }
138   num_points = pstr_drc_compand->nb_points;
139 
140   if (num_points == 0 || pstr_drc_compand->str_segment[2 * ((num_points - 1) + 1)].x) {
141     num_points++;
142   }
143 
144   pstr_drc_compand->str_segment[0].x =
145       pstr_drc_compand->str_segment[2].x - 2 * pstr_drc_compand->width_db;
146   pstr_drc_compand->str_segment[0].y = pstr_drc_compand->str_segment[2].y;
147   num_points++;
148 
149   radius = pstr_drc_compand->width_db * M_LN10_DIV_20;
150 
151   for (i = 2; i < num_points; i++) {
152     g1 = (pstr_drc_compand->str_segment[2 * (i - 1)].y -
153           pstr_drc_compand->str_segment[2 * (i - 2)].y) *
154          (pstr_drc_compand->str_segment[2 * i].x - pstr_drc_compand->str_segment[2 * (i - 1)].x);
155     g2 = (pstr_drc_compand->str_segment[2 * i].y - pstr_drc_compand->str_segment[2 * (i - 1)].y) *
156          (pstr_drc_compand->str_segment[2 * (i - 1)].x -
157           pstr_drc_compand->str_segment[2 * (i - 2)].x);
158 
159     if (fabs(g1 - g2)) {
160       continue;
161     }
162     num_points--;
163 
164     for (j = --i; j < num_points; j++) {
165       pstr_drc_compand->str_segment[2 * j] = pstr_drc_compand->str_segment[2 * (j + 1)];
166     }
167   }
168 
169   pstr_drc_compand->nb_segments = num_points * 2;
170   for (i = 0; i < pstr_drc_compand->nb_segments; i += 2) {
171     pstr_drc_compand->str_segment[i].y += pstr_drc_compand->gain_db;
172     pstr_drc_compand->str_segment[i].x *= M_LN10_DIV_20;
173     pstr_drc_compand->str_segment[i].y *= M_LN10_DIV_20;
174   }
175 
176   for (i = 4; i < pstr_drc_compand->nb_segments; i += 2) {
177     FLOAT64 num = 0.0;
178     FLOAT64 den = 0.0f;
179 
180     num = pstr_drc_compand->str_segment[i - 2].y - pstr_drc_compand->str_segment[i - 4].y;
181     den = pstr_drc_compand->str_segment[i - 2].x - pstr_drc_compand->str_segment[i - 4].x;
182     length = hypot(num, den);
183     if (length < FLT_EPSILON) {
184       return IA_EXHEAACE_EXE_NONFATAL_USAC_INVALID_GAIN_POINTS;
185     }
186     pstr_drc_compand->str_segment[i - 4].a = 0;
187     pstr_drc_compand->str_segment[i - 4].b = ixheaace_div64(num, den);
188     theta = atan2(num, den);
189     r = MIN(radius, length);
190     pstr_drc_compand->str_segment[i - 3].x =
191         pstr_drc_compand->str_segment[i - 2].x - r * cos(theta);
192     pstr_drc_compand->str_segment[i - 3].y =
193         pstr_drc_compand->str_segment[i - 2].y - r * sin(theta);
194 
195     num = pstr_drc_compand->str_segment[i].y - pstr_drc_compand->str_segment[i - 2].y;
196     den = pstr_drc_compand->str_segment[i].x - pstr_drc_compand->str_segment[i - 2].x;
197     length = hypot(num, den);
198     if (length < FLT_EPSILON) {
199       return IA_EXHEAACE_EXE_NONFATAL_USAC_INVALID_GAIN_POINTS;
200     }
201     pstr_drc_compand->str_segment[i - 2].a = 0;
202     pstr_drc_compand->str_segment[i - 2].b = ixheaace_div64(num, den);
203     theta = atan2(num, den);
204     r = MIN(radius, length / 2);
205     x = pstr_drc_compand->str_segment[i - 2].x + r * cos(theta);
206     y = pstr_drc_compand->str_segment[i - 2].y + r * sin(theta);
207 
208     cx =
209         (pstr_drc_compand->str_segment[i - 3].x + pstr_drc_compand->str_segment[i - 2].x + x) / 3;
210     cy =
211         (pstr_drc_compand->str_segment[i - 3].y + pstr_drc_compand->str_segment[i - 2].y + y) / 3;
212 
213     pstr_drc_compand->str_segment[i - 2].x = x;
214     pstr_drc_compand->str_segment[i - 2].y = y;
215 
216     inp_1 = cx - pstr_drc_compand->str_segment[i - 3].x;
217     out_1 = cy - pstr_drc_compand->str_segment[i - 3].y;
218     inp_2 = pstr_drc_compand->str_segment[i - 2].x - pstr_drc_compand->str_segment[i - 3].x;
219     out_2 = pstr_drc_compand->str_segment[i - 2].y - pstr_drc_compand->str_segment[i - 3].y;
220 
221     num = (out_2 * inp_1) - (inp_2 * out_1);
222     den = (inp_2 - inp_1) * inp_1 * inp_2;
223     pstr_drc_compand->str_segment[i - 3].a = ixheaace_div64(num, den);
224 
225     num = out_1 - (pstr_drc_compand->str_segment[i - 3].a * inp_1 * inp_1);
226     den = inp_1;
227     pstr_drc_compand->str_segment[i - 3].b = ixheaace_div64(num, den);
228   }
229   pstr_drc_compand->str_segment[i - 3].x = 0;
230   pstr_drc_compand->str_segment[i - 3].y = pstr_drc_compand->str_segment[i - 3].y;
231 
232   pstr_drc_compand->in_min_lin = exp(pstr_drc_compand->str_segment[1].x);
233   pstr_drc_compand->out_min_lin = exp(pstr_drc_compand->str_segment[1].y);
234 
235   pstr_chan_param = &pstr_drc_compand->str_channel_param;
236 
237   if (pstr_chan_param->attack < 1.0 / pstr_drc_gain_enc->sample_rate) {
238     pstr_chan_param->attack = 1.0;
239   } else {
240     pstr_chan_param->attack =
241         1.0 - exp(-1.0 / (pstr_drc_gain_enc->sample_rate * pstr_chan_param->attack));
242   }
243 
244   if (pstr_chan_param->decay < 1.0 / pstr_drc_gain_enc->sample_rate) {
245     pstr_chan_param->decay = 1.0;
246   } else {
247     pstr_chan_param->decay =
248         1.0 - exp(-1.0 / (pstr_drc_gain_enc->sample_rate * pstr_chan_param->decay));
249   }
250   pstr_chan_param->volume = EXP10(pstr_drc_compand->initial_volume / 20);
251 
252   return IA_NO_ERROR;
253 }
254 
impd_drc_stft_drc_compand_get_volume(ia_drc_stft_gain_calc_struct * pstr_drc_stft_gain_handle,FLOAT32 in_db)255 static FLOAT32 impd_drc_stft_drc_compand_get_volume(
256     ia_drc_stft_gain_calc_struct *pstr_drc_stft_gain_handle, FLOAT32 in_db) {
257   ULOOPIDX idx;
258   FLOAT32 in_log, out_log;
259   ia_drc_compand_segment_struct *pstr_compand_segment;
260 
261   if (in_db < pstr_drc_stft_gain_handle->in_min_db) {
262     return pstr_drc_stft_gain_handle->out_min_db;
263   }
264 
265   in_log = (FLOAT32)(in_db * M_LN10_DIV_20);
266 
267   for (idx = 1; idx < pstr_drc_stft_gain_handle->nb_segments; idx++) {
268     if (in_log <= pstr_drc_stft_gain_handle->str_segment[idx].x) {
269       break;
270     }
271   }
272 
273   pstr_compand_segment = &pstr_drc_stft_gain_handle->str_segment[idx - 1];
274   in_log -= (FLOAT32)(pstr_compand_segment->x);
275   out_log = (FLOAT32)(pstr_compand_segment->y +
276                       in_log * (pstr_compand_segment->a * in_log + pstr_compand_segment->b));
277 
278   return (FLOAT32)(out_log * M_LOG10_E * 20.0f);
279 }
280 
impd_drc_stft_drc_gain_calc_process(ia_drc_gain_enc_struct * pstr_drc_gain_enc,WORD32 drc_coefficients_uni_drc_idx,WORD32 gain_set_idx,WORD32 band_idx,WORD32 start_sub_band_index,WORD32 stop_sub_band_index,UWORD32 num_frames,FLOAT32 * in_buff,FLOAT32 * gain_values)281 VOID impd_drc_stft_drc_gain_calc_process(ia_drc_gain_enc_struct *pstr_drc_gain_enc,
282                                          WORD32 drc_coefficients_uni_drc_idx, WORD32 gain_set_idx,
283                                          WORD32 band_idx, WORD32 start_sub_band_index,
284                                          WORD32 stop_sub_band_index, UWORD32 num_frames,
285                                          FLOAT32 *in_buff, FLOAT32 *gain_values) {
286   ULOOPIDX idx;
287   LOOPIDX band;
288   FLOAT32 xg, xl, yl, cdb;
289   FLOAT32 in_real, in_imag;
290   FLOAT32 abs_val_sqr;
291   UWORD32 num_time_slot = num_frames / STFT256_HOP_SIZE;
292 
293   ia_drc_stft_gain_calc_struct *pstr_drc_stft_gain_handle =
294       &pstr_drc_gain_enc
295            ->str_drc_stft_gain_handle[drc_coefficients_uni_drc_idx][gain_set_idx][band_idx];
296 
297   for (idx = 0; idx < num_time_slot; idx++) {
298     abs_val_sqr = 0.0f;
299     for (band = start_sub_band_index; band <= stop_sub_band_index; band++) {
300       in_imag = in_buff[((idx * STFT256_HOP_SIZE + band) << 1) + 1];
301       in_real = in_buff[(idx * STFT256_HOP_SIZE + band) << 1];
302 
303       abs_val_sqr += sqrtf(powf(in_real, 2.0f) + powf(in_imag, 2.0f));
304     }
305 
306     abs_val_sqr /= (FLOAT32)((stop_sub_band_index - start_sub_band_index + 1) << 4);
307 
308     abs_val_sqr = powf(abs_val_sqr, 2.0f);
309     xg = 10.0f * log10f((abs_val_sqr) + 2e-13f);
310 
311     xl = -impd_drc_stft_drc_compand_get_volume(pstr_drc_stft_gain_handle, xg);
312 
313     if (xl > pstr_drc_stft_gain_handle->yl_z1[band]) {
314       yl = (pstr_drc_stft_gain_handle->alpha_a * pstr_drc_stft_gain_handle->yl_z1[band]) +
315            ((1.0f - pstr_drc_stft_gain_handle->alpha_a) * xl);
316     } else {
317       yl = (pstr_drc_stft_gain_handle->alpha_r * pstr_drc_stft_gain_handle->yl_z1[band]) +
318            ((1.0f - pstr_drc_stft_gain_handle->alpha_r) * xl);
319     }
320 
321     pstr_drc_stft_gain_handle->yl_z1[band] = yl;
322     cdb = -yl;
323     cdb = MAX(IMPD_DRCSPECTRAL_FLOOR, (powf(10.0f, cdb / 20.0f)));
324     cdb = 20.0f * log10f(cdb);
325 
326     for (band = 0; band < STFT256_HOP_SIZE; band++) {
327       gain_values[idx * STFT256_HOP_SIZE + band] = cdb;
328     }
329   }
330 }
331 
impd_drc_stft_drc_gain_calc_init(ia_drc_gain_enc_struct * pstr_drc_gain_enc,WORD32 drc_coefficients_uni_drc_idx,WORD32 gain_set_idx,WORD32 band_idx)332 IA_ERRORCODE impd_drc_stft_drc_gain_calc_init(ia_drc_gain_enc_struct *pstr_drc_gain_enc,
333                                               WORD32 drc_coefficients_uni_drc_idx,
334                                               WORD32 gain_set_idx, WORD32 band_idx) {
335   ULOOPIDX i, j;
336   UWORD32 num_points;
337   FLOAT32 width_e, tmp;
338   FLOAT64 g1, g2;
339   FLOAT64 x, y, cx, cy, r;
340   FLOAT64 inp_1, inp_2, out_1, out_2, theta, len;
341   ia_drc_compand_chan_param_struct *pstr_chan_param;
342   ia_drc_stft_gain_calc_struct *pstr_drc_stft_gain_handle;
343 
344   if ((drc_coefficients_uni_drc_idx >= MAX_DRC_COEFF_COUNT) ||
345       (gain_set_idx >= GAIN_SET_COUNT_MAX) || (band_idx >= MAX_BAND_COUNT)) {
346     return IA_EXHEAACE_CONFIG_FATAL_DRC_COMPAND_FAILED;
347   }
348 
349   pstr_drc_stft_gain_handle =
350       &pstr_drc_gain_enc
351            ->str_drc_stft_gain_handle[drc_coefficients_uni_drc_idx][gain_set_idx][band_idx];
352 
353   width_e = (FLOAT32)(pstr_drc_stft_gain_handle->width_db * M_LN10_DIV_20);
354 
355   for (i = 0; i < pstr_drc_stft_gain_handle->nb_points; i++) {
356     if (i && pstr_drc_stft_gain_handle->str_segment[2 * ((i - 1) + 1)].x >
357                  pstr_drc_stft_gain_handle->str_segment[2 * (i + 1)].x) {
358       return IA_EXHEAACE_CONFIG_FATAL_DRC_COMPAND_FAILED;
359     }
360     pstr_drc_stft_gain_handle->str_segment[2 * (i + 1)].y -=
361         pstr_drc_stft_gain_handle->str_segment[2 * (i + 1)].x;
362   }
363   num_points = pstr_drc_stft_gain_handle->nb_points;
364 
365   if (num_points == 0 || pstr_drc_stft_gain_handle->str_segment[2 * ((num_points - 1) + 1)].x) {
366     num_points++;
367   }
368 
369   pstr_drc_stft_gain_handle->str_segment[0].x =
370       pstr_drc_stft_gain_handle->str_segment[2].x - pstr_drc_stft_gain_handle->width_db;
371   pstr_drc_stft_gain_handle->str_segment[0].y = pstr_drc_stft_gain_handle->str_segment[2].y;
372   num_points++;
373 
374   for (i = 2; i < num_points; i++) {
375     g1 = (pstr_drc_stft_gain_handle->str_segment[2 * (i - 1)].y -
376           pstr_drc_stft_gain_handle->str_segment[2 * (i - 2)].y) *
377          (pstr_drc_stft_gain_handle->str_segment[2 * i].x -
378           pstr_drc_stft_gain_handle->str_segment[2 * (i - 1)].x);
379     g2 = (pstr_drc_stft_gain_handle->str_segment[2 * i].y -
380           pstr_drc_stft_gain_handle->str_segment[2 * (i - 1)].y) *
381          (pstr_drc_stft_gain_handle->str_segment[2 * (i - 1)].x -
382           pstr_drc_stft_gain_handle->str_segment[2 * (i - 2)].x);
383 
384     if (fabs(g1 - g2)) {
385       continue;
386     }
387     num_points--;
388 
389     for (j = --i; j < num_points; j++) {
390       pstr_drc_stft_gain_handle->str_segment[2 * j] =
391           pstr_drc_stft_gain_handle->str_segment[2 * (j + 1)];
392     }
393   }
394   pstr_drc_stft_gain_handle->nb_segments = num_points * 2;
395   for (i = 0; i < pstr_drc_stft_gain_handle->nb_segments; i += 2) {
396     pstr_drc_stft_gain_handle->str_segment[i].y += pstr_drc_stft_gain_handle->gain_db;
397     pstr_drc_stft_gain_handle->str_segment[i].x *= M_LN10_DIV_20;
398     pstr_drc_stft_gain_handle->str_segment[i].y *= M_LN10_DIV_20;
399   }
400 
401   for (i = 4; i < pstr_drc_stft_gain_handle->nb_segments; i += 2) {
402     FLOAT64 denominator;
403     FLOAT64 numerator;
404 
405     denominator = pstr_drc_stft_gain_handle->str_segment[i - 2].x -
406                   pstr_drc_stft_gain_handle->str_segment[i - 4].x;
407     numerator = pstr_drc_stft_gain_handle->str_segment[i - 2].y -
408                 pstr_drc_stft_gain_handle->str_segment[i - 4].y;
409     len = hypot(denominator , numerator);
410     if (len < FLT_EPSILON) {
411       return IA_EXHEAACE_EXE_NONFATAL_USAC_INVALID_GAIN_POINTS;
412     }
413     pstr_drc_stft_gain_handle->str_segment[i - 4].a = 0;
414     pstr_drc_stft_gain_handle->str_segment[i - 4].b = ixheaace_div64(numerator, denominator);
415     theta = atan2(numerator, denominator);
416     r = MIN(width_e / (2.0f * cos(theta)), len / 2);
417 
418     pstr_drc_stft_gain_handle->str_segment[i - 3].x =
419       pstr_drc_stft_gain_handle->str_segment[i - 2].x - r * cos(theta);
420     pstr_drc_stft_gain_handle->str_segment[i - 3].y =
421       pstr_drc_stft_gain_handle->str_segment[i - 2].y - r * sin(theta);
422 
423     denominator = pstr_drc_stft_gain_handle->str_segment[i].x -
424                   pstr_drc_stft_gain_handle->str_segment[i - 2].x;
425     numerator = pstr_drc_stft_gain_handle->str_segment[i].y -
426                 pstr_drc_stft_gain_handle->str_segment[i - 2].y;
427     len = hypot(denominator, numerator);
428     if (len < FLT_EPSILON) {
429       return IA_EXHEAACE_EXE_NONFATAL_USAC_INVALID_GAIN_POINTS;
430     }
431     pstr_drc_stft_gain_handle->str_segment[i - 2].a = 0;
432     pstr_drc_stft_gain_handle->str_segment[i - 2].b = ixheaace_div64(numerator, denominator);
433 
434     theta = atan2(numerator, denominator);
435     r = MIN(width_e / (2.0f * cos(theta)), len / 2);
436     x = pstr_drc_stft_gain_handle->str_segment[i - 2].x + r * cos(theta);
437     y = pstr_drc_stft_gain_handle->str_segment[i - 2].y + r * sin(theta);
438 
439     cx = (pstr_drc_stft_gain_handle->str_segment[i - 3].x +
440           pstr_drc_stft_gain_handle->str_segment[i - 2].x + x) /
441          3;
442     cy = (pstr_drc_stft_gain_handle->str_segment[i - 3].y +
443           pstr_drc_stft_gain_handle->str_segment[i - 2].y + y) /
444          3;
445 
446     pstr_drc_stft_gain_handle->str_segment[i - 2].x = x;
447     pstr_drc_stft_gain_handle->str_segment[i - 2].y = y;
448 
449     inp_1 = cx - pstr_drc_stft_gain_handle->str_segment[i - 3].x;
450     out_1 = cy - pstr_drc_stft_gain_handle->str_segment[i - 3].y;
451     inp_2 = pstr_drc_stft_gain_handle->str_segment[i - 2].x -
452             pstr_drc_stft_gain_handle->str_segment[i - 3].x;
453     out_2 = pstr_drc_stft_gain_handle->str_segment[i - 2].y -
454             pstr_drc_stft_gain_handle->str_segment[i - 3].y;
455     numerator = (out_2 * inp_1) - (inp_2 * out_1);
456     denominator = (inp_2 - inp_1) * inp_2 * inp_1;
457     pstr_drc_stft_gain_handle->str_segment[i - 3].a = ixheaace_div64(numerator, denominator);
458 
459     numerator = out_1 - (pstr_drc_stft_gain_handle->str_segment[i - 3].a * inp_1 * inp_1);
460     denominator = inp_1;
461     pstr_drc_stft_gain_handle->str_segment[i - 3].b = ixheaace_div64(numerator, denominator);
462   }
463   pstr_drc_stft_gain_handle->str_segment[i - 3].x = 0;
464   pstr_drc_stft_gain_handle->str_segment[i - 3].y =
465       pstr_drc_stft_gain_handle->str_segment[i - 2].y;
466 
467   pstr_drc_stft_gain_handle->in_min_db =
468       (FLOAT32)(pstr_drc_stft_gain_handle->str_segment[1].x * M_LOG10_E * 20.0f);
469   pstr_drc_stft_gain_handle->out_min_db =
470       (FLOAT32)(pstr_drc_stft_gain_handle->str_segment[1].y * M_LOG10_E * 20.0f);
471 
472   pstr_chan_param = &pstr_drc_stft_gain_handle->str_channel_param;
473 
474   pstr_chan_param->volume = EXP10(pstr_drc_stft_gain_handle->initial_volume / 20.0f);
475 
476   for (i = 0; i < STFT256_HOP_SIZE; i++) {
477     pstr_drc_stft_gain_handle->yl_z1[i] = 0.0f;
478   }
479 
480   tmp = (pstr_drc_stft_gain_handle->attack_ms / STFT256_HOP_SIZE) *
481       pstr_drc_gain_enc->sample_rate * 0.001f;
482   if ((fabs(tmp) < FLT_EPSILON) && (tmp >= 0.0f)) {
483     pstr_drc_stft_gain_handle->alpha_a = 0;
484   }
485   else {
486     pstr_drc_stft_gain_handle->alpha_a = expf(ixheaace_div32(-1.0f, tmp));
487   }
488 
489   tmp = (pstr_drc_stft_gain_handle->release_ms / STFT256_HOP_SIZE) *
490       pstr_drc_gain_enc->sample_rate * 0.001f;
491   if ((fabs(tmp) < FLT_EPSILON) && (tmp >= 0.0f)) {
492     pstr_drc_stft_gain_handle->alpha_r = 0;
493   }
494   else {
495     pstr_drc_stft_gain_handle->alpha_r = expf(ixheaace_div32(-1.0f, tmp));
496   }
497 
498   return IA_NO_ERROR;
499 }
500 
impd_drc_stft_drc_convert_to_fd(ia_drc_gain_enc_struct * pstr_drc_gain_enc,FLOAT32 * ptr_input,UWORD32 ch_idx,UWORD32 frame_size,FLOAT32 * ptr_output,VOID * pstr_scratch)501 VOID impd_drc_stft_drc_convert_to_fd(ia_drc_gain_enc_struct *pstr_drc_gain_enc,
502                                      FLOAT32 *ptr_input, UWORD32 ch_idx, UWORD32 frame_size,
503                                      FLOAT32 *ptr_output, VOID *pstr_scratch) {
504   ULOOPIDX i, j;
505   UWORD32 num_time_slot = frame_size / STFT256_HOP_SIZE;
506   FLOAT32 time_sample_vector;
507   iusace_scratch_mem *ptr_scratch = (iusace_scratch_mem *)(pstr_scratch);
508   pFLOAT32 scratch_buff = ptr_scratch->ptr_drc_scratch_buf;
509 
510   for (i = 0; i < num_time_slot; i++) {
511     for (j = 0; j < STFT256_HOP_SIZE; j++) {
512       time_sample_vector = (FLOAT32)(ptr_input[i * STFT256_HOP_SIZE + j] / (32768.0));
513 
514       scratch_buff[(j << 1)] =
515           (FLOAT32)(pstr_drc_gain_enc->stft_tmp_in_buf_time[ch_idx][j] * iusace_sine_win_256[j]);
516       scratch_buff[(j << 1) + 1] = 0.0f;
517 
518       scratch_buff[(STFT256_HOP_SIZE + j) << 1] =
519           (FLOAT32)(iusace_sine_win_256[STFT256_HOP_SIZE - 1 - j] * time_sample_vector);
520       scratch_buff[((STFT256_HOP_SIZE + j) << 1) + 1] = 0.0f;
521 
522       pstr_drc_gain_enc->stft_tmp_in_buf_time[ch_idx][j] = time_sample_vector;
523     }
524 
525     iusace_complex_fft(scratch_buff, STFT256_HOP_SIZE << 1, ptr_scratch);
526 
527     ptr_output[(i * STFT256_HOP_SIZE) << 1] = scratch_buff[0];
528     ptr_output[((i * STFT256_HOP_SIZE) << 1) + 1] = scratch_buff[STFT256_HOP_SIZE << 1];
529 
530     for (j = 1; j < STFT256_HOP_SIZE; j++) {
531       ptr_output[(i * STFT256_HOP_SIZE + j) << 1] = scratch_buff[j << 1];
532       ptr_output[((i * STFT256_HOP_SIZE + j) << 1) + 1] = scratch_buff[(j << 1) + 1];
533     }
534   }
535 }
536