xref: /aosp_15_r20/external/libxaac/decoder/drc_src/impd_drc_gain_dec.c (revision 15dc779a375ca8b5125643b829a8aa4b70d7f451)
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 #include "impd_type_def.h"
25 #include "impd_drc_extr_delta_coded_info.h"
26 #include "impd_drc_common.h"
27 #include "impd_drc_struct.h"
28 #include "impd_drc_interface.h"
29 #include "impd_drc_filter_bank.h"
30 #include "impd_drc_gain_dec.h"
31 #include "impd_parametric_drc_dec.h"
32 #include "impd_drc_multi_band.h"
33 #include "impd_drc_process_audio.h"
34 #include "impd_drc_eq.h"
35 #include "impd_drc_gain_decoder.h"
36 
37 extern const ia_cicp_sigmoid_characteristic_param_struct
38     pstr_cicp_sigmoid_characteristic_param[];
39 
impd_gain_db_to_lin(ia_interp_params_struct * interp_params_str,WORD32 drc_band,FLOAT32 in_param_db_gain,FLOAT32 in_param_db_slope,FLOAT32 * out_param_lin_gain,FLOAT32 * out_param_lin_slope)40 VOID impd_gain_db_to_lin(ia_interp_params_struct* interp_params_str,
41                          WORD32 drc_band, FLOAT32 in_param_db_gain,
42                          FLOAT32 in_param_db_slope, FLOAT32* out_param_lin_gain,
43                          FLOAT32* out_param_lin_slope) {
44   FLOAT32 loc_db_gain = in_param_db_gain;
45   FLOAT32 gain_ratio = 1.0;
46 
47   ia_gain_modifiers_struct* pstr_gain_modifiers =
48       interp_params_str->pstr_gain_modifiers;
49   if (interp_params_str->gain_modification_flag) {
50     if ((interp_params_str->characteristic_index > 0) &&
51         (loc_db_gain != 0.0f)) {
52       gain_ratio = 1.0f;
53     }
54 
55     if (loc_db_gain < 0.0f) {
56       gain_ratio *= interp_params_str->compress;
57     } else {
58       gain_ratio *= interp_params_str->boost;
59     }
60   }
61   if (pstr_gain_modifiers->gain_scaling_flag[drc_band] == 1) {
62     if (loc_db_gain < 0.0) {
63       gain_ratio *= pstr_gain_modifiers->attn_scaling[drc_band];
64     } else {
65       gain_ratio *= pstr_gain_modifiers->ampl_scaling[drc_band];
66     }
67   }
68   if ((interp_params_str->pstr_ducking_modifiers->ducking_scaling_flag == 1) &&
69       (interp_params_str->ducking_flag == 1)) {
70     gain_ratio *= interp_params_str->pstr_ducking_modifiers->ducking_scaling;
71   }
72 
73   {
74     *out_param_lin_gain =
75         (FLOAT32)pow(2.0, (FLOAT64)(gain_ratio * loc_db_gain / 6.0f));
76     *out_param_lin_slope = SLOPE_FACTOR_DB_TO_LINEAR * gain_ratio *
77                            *out_param_lin_gain * in_param_db_slope;
78 
79     if (pstr_gain_modifiers->gain_offset_flag[drc_band] == 1) {
80       *out_param_lin_gain *= (FLOAT32)pow(
81           2.0, (FLOAT64)(pstr_gain_modifiers->gain_offset[drc_band] / 6.0f));
82     }
83     if ((interp_params_str->limiter_peak_target_present == 1) &&
84         (interp_params_str->clipping_flag == 1)) {
85       *out_param_lin_gain *= (FLOAT32)pow(
86           2.0, max(0.0, -interp_params_str->limiter_peak_target -
87                             interp_params_str->loudness_normalization_gain_db) /
88                    6.0);
89       if (*out_param_lin_gain >= 1.0) {
90         *out_param_lin_gain = 1.0;
91         *out_param_lin_slope = 0.0;
92       }
93     }
94   }
95   return;
96 }
97 
98 WORD32
impd_compressor_io_sigmoid(ia_split_drc_characteristic_struct * split_drc_characteristic,FLOAT32 in_db_level,FLOAT32 * out_db_gain)99 impd_compressor_io_sigmoid(
100     ia_split_drc_characteristic_struct* split_drc_characteristic,
101     FLOAT32 in_db_level, FLOAT32* out_db_gain) {
102   FLOAT32 tmp;
103   FLOAT32 in_out_ratio = split_drc_characteristic->in_out_ratio;
104   FLOAT32 gainDbLimit = split_drc_characteristic->gain;
105   FLOAT32 exp = split_drc_characteristic->exp;
106 
107   tmp = (DRC_INPUT_LOUDNESS_TARGET - in_db_level) * in_out_ratio;
108   if (exp < 1000.0f) {
109     FLOAT32 x = tmp / gainDbLimit;
110     if (x < 0.0f) {
111       return (UNEXPECTED_ERROR);
112     }
113     *out_db_gain = (FLOAT32)(tmp / pow(1.0f + pow(x, exp), 1.0f / exp));
114   } else {
115     *out_db_gain = tmp;
116   }
117   if (split_drc_characteristic->flip_sign == 1) {
118     *out_db_gain = -*out_db_gain;
119   }
120   return (0);
121 }
122 
123 WORD32
impd_compressor_io_sigmoid_inv(ia_split_drc_characteristic_struct * split_drc_characteristic,FLOAT32 loc_db_gain,FLOAT32 * in_level)124 impd_compressor_io_sigmoid_inv(
125     ia_split_drc_characteristic_struct* split_drc_characteristic,
126     FLOAT32 loc_db_gain, FLOAT32* in_level) {
127   FLOAT32 in_out_ratio = split_drc_characteristic->in_out_ratio;
128   FLOAT32 gainDbLimit = split_drc_characteristic->gain;
129   FLOAT32 exp = split_drc_characteristic->exp;
130   FLOAT32 tmp = loc_db_gain;
131 
132   if (split_drc_characteristic->flip_sign == 1) {
133     tmp = -loc_db_gain;
134   }
135   if (exp < 1000.0f) {
136     FLOAT32 x = tmp / gainDbLimit;
137     if (x < 0.0f) {
138       return (UNEXPECTED_ERROR);
139     }
140     tmp = (FLOAT32)(tmp / pow(1.0f - pow(x, exp), 1.0f / exp));
141   }
142   *in_level = DRC_INPUT_LOUDNESS_TARGET - tmp / in_out_ratio;
143 
144   return (0);
145 }
146 
147 WORD32
impd_compressor_io_nodes_lt(ia_split_drc_characteristic_struct * split_drc_characteristic,FLOAT32 in_db_level,FLOAT32 * out_db_gain)148 impd_compressor_io_nodes_lt(
149     ia_split_drc_characteristic_struct* split_drc_characteristic,
150     FLOAT32 in_db_level, FLOAT32* out_db_gain) {
151   WORD32 n;
152   FLOAT32 w;
153   FLOAT32* node_level = split_drc_characteristic->node_level;
154   FLOAT32* node_gain = split_drc_characteristic->node_gain;
155 
156   if (in_db_level > DRC_INPUT_LOUDNESS_TARGET) {
157     return (UNEXPECTED_ERROR);
158   }
159   for (n = 1; n <= split_drc_characteristic->characteristic_node_count; n++) {
160     if ((in_db_level <= node_level[n - 1]) && (in_db_level > node_level[n])) {
161       w = (node_level[n] - in_db_level) / (node_level[n] - node_level[n - 1]);
162       *out_db_gain = (FLOAT32)(w * node_gain[n - 1] + (1.0 - w) * node_gain[n]);
163     }
164   }
165   *out_db_gain = node_gain[split_drc_characteristic->characteristic_node_count];
166   return (0);
167 }
168 
169 WORD32
impd_compressor_io_nodes_rt(ia_split_drc_characteristic_struct * split_drc_characteristic,FLOAT32 in_db_level,FLOAT32 * out_db_gain)170 impd_compressor_io_nodes_rt(
171     ia_split_drc_characteristic_struct* split_drc_characteristic,
172     FLOAT32 in_db_level, FLOAT32* out_db_gain) {
173   WORD32 n;
174   FLOAT32 w;
175   FLOAT32* node_level = split_drc_characteristic->node_level;
176   FLOAT32* node_gain = split_drc_characteristic->node_gain;
177 
178   if (in_db_level < DRC_INPUT_LOUDNESS_TARGET) {
179     return (UNEXPECTED_ERROR);
180   }
181   for (n = 1; n <= split_drc_characteristic->characteristic_node_count; n++) {
182     if ((in_db_level >= node_level[n - 1]) && (in_db_level < node_level[n])) {
183       w = (FLOAT32)(node_level[n] - in_db_level) /
184           (node_level[n] - node_level[n - 1]);
185       *out_db_gain = (FLOAT32)(w * node_gain[n - 1] + (1.0 - w) * node_gain[n]);
186     }
187   }
188   *out_db_gain =
189       (node_gain[split_drc_characteristic->characteristic_node_count]);
190   return (0);
191 }
192 
impd_compressor_io_nodes_inverse(ia_split_drc_characteristic_struct * split_drc_characteristic,FLOAT32 loc_db_gain,FLOAT32 * in_level)193 VOID impd_compressor_io_nodes_inverse(
194     ia_split_drc_characteristic_struct* split_drc_characteristic,
195     FLOAT32 loc_db_gain, FLOAT32* in_level) {
196   WORD32 n;
197   FLOAT32 w;
198   FLOAT32* node_level = split_drc_characteristic->node_level;
199   FLOAT32* node_gain = split_drc_characteristic->node_gain;
200   WORD32 node_count = split_drc_characteristic->characteristic_node_count;
201 
202   if (node_gain[1] < 0.0f) {
203     if (loc_db_gain <= node_gain[node_count]) {
204       *in_level = node_level[node_count];
205     } else {
206       if (loc_db_gain >= 0.0f) {
207         *in_level = DRC_INPUT_LOUDNESS_TARGET;
208       } else {
209         for (n = 1; n <= node_count; n++) {
210           if ((loc_db_gain <= node_gain[n - 1]) &&
211               (loc_db_gain > node_gain[n])) {
212             w = (node_gain[n] - loc_db_gain) /
213                 (node_gain[n] - node_gain[n - 1]);
214             *in_level =
215                 (FLOAT32)(w * node_level[n - 1] + (1.0 - w) * node_level[n]);
216           }
217         }
218       }
219     }
220   } else {
221     if (loc_db_gain >= node_gain[node_count]) {
222       *in_level = node_level[node_count];
223     } else {
224       if (loc_db_gain <= 0.0f) {
225         *in_level = DRC_INPUT_LOUDNESS_TARGET;
226       } else {
227         for (n = 1; n <= node_count; n++) {
228           if ((loc_db_gain >= node_gain[n - 1]) &&
229               (loc_db_gain < node_gain[n])) {
230             w = (FLOAT32)(node_gain[n] - loc_db_gain) /
231                 (node_gain[n] - node_gain[n - 1]);
232             *in_level =
233                 (FLOAT32)(w * node_level[n - 1] + (1.0 - w) * node_level[n]);
234           }
235         }
236       }
237     }
238   }
239   return;
240 }
241 
242 WORD32
impd_map_gain(ia_split_drc_characteristic_struct * split_drc_characteristic_source,ia_split_drc_characteristic_struct * split_drc_characteristic_target,FLOAT32 gain_in_db,FLOAT32 * gain_out_db)243 impd_map_gain(
244     ia_split_drc_characteristic_struct* split_drc_characteristic_source,
245     ia_split_drc_characteristic_struct* split_drc_characteristic_target,
246     FLOAT32 gain_in_db, FLOAT32* gain_out_db) {
247   FLOAT32 in_level=0;
248   WORD32 err = 0;
249 
250   switch (split_drc_characteristic_source->characteristic_format) {
251     case CHARACTERISTIC_SIGMOID:
252       err = impd_compressor_io_sigmoid_inv(split_drc_characteristic_source,
253                                            gain_in_db, &in_level);
254       if (err) return (err);
255       break;
256     case CHARACTERISTIC_NODES:
257       impd_compressor_io_nodes_inverse(split_drc_characteristic_source,
258                                        gain_in_db, &in_level);
259 
260       break;
261     case CHARACTERISTIC_PASS_THRU:
262       in_level = gain_in_db;
263       break;
264     default:
265       return (UNEXPECTED_ERROR);
266       break;
267   }
268   switch (split_drc_characteristic_target->characteristic_format) {
269     case CHARACTERISTIC_SIGMOID:
270       err = impd_compressor_io_sigmoid(split_drc_characteristic_target, in_level,
271                                        gain_out_db);
272       if (err) return (err);
273       break;
274     case CHARACTERISTIC_NODES:
275       if (in_level < DRC_INPUT_LOUDNESS_TARGET) {
276         err = impd_compressor_io_nodes_lt(split_drc_characteristic_target,
277                                           in_level, gain_out_db);
278         if (err) return (err);
279       } else {
280         err = impd_compressor_io_nodes_rt(split_drc_characteristic_target,
281                                           in_level, gain_out_db);
282         if (err) return (err);
283       }
284       break;
285     case CHARACTERISTIC_PASS_THRU:
286       *gain_out_db = in_level;
287       break;
288     default:
289       break;
290   }
291   return (0);
292 }
293 
294 WORD32
impd_conv_to_linear_domain(ia_interp_params_struct * interp_params_str,WORD32 drc_band,FLOAT32 in_param_db_gain,FLOAT32 in_param_db_slope,FLOAT32 * out_param_lin_gain,FLOAT32 * out_param_lin_slope)295 impd_conv_to_linear_domain(ia_interp_params_struct* interp_params_str,
296                            WORD32 drc_band, FLOAT32 in_param_db_gain,
297                            FLOAT32 in_param_db_slope,
298                            FLOAT32* out_param_lin_gain,
299                            FLOAT32* out_param_lin_slope) {
300   WORD32 err = 0;
301   FLOAT32 loc_db_gain = in_param_db_gain;
302   FLOAT32 gain_ratio = 1.0;
303   FLOAT32 mapped_db_gain;
304   ia_gain_modifiers_struct* pstr_gain_modifiers =
305       interp_params_str->pstr_gain_modifiers;
306   if (interp_params_str->gain_modification_flag) {
307     ia_split_drc_characteristic_struct* split_drc_characteristic_source;
308 
309     WORD32 slopeIsNegative;
310 
311     if (interp_params_str->drc_characteristic_present) {
312       if (interp_params_str->drc_source_characteristic_cicp_format) {
313       } else {
314         slopeIsNegative = 0;
315         split_drc_characteristic_source =
316             interp_params_str->split_source_characteristic_left;
317         if (split_drc_characteristic_source->characteristic_format == 0) {
318           slopeIsNegative = 1;
319         } else {
320           if (split_drc_characteristic_source->node_gain[1] > 0.0f) {
321             slopeIsNegative = 1;
322           }
323         }
324         if (loc_db_gain == 0.0f) {
325           if (((pstr_gain_modifiers
326                     ->target_characteristic_left_present[drc_band] == 1) &&
327                (interp_params_str->split_target_characteristic_left
328                     ->characteristic_format == CHARACTERISTIC_PASS_THRU)) ||
329               ((pstr_gain_modifiers
330                     ->target_characteristic_right_present[drc_band] == 1) &&
331                (interp_params_str->split_target_characteristic_right
332                     ->characteristic_format == CHARACTERISTIC_PASS_THRU))) {
333             mapped_db_gain = DRC_INPUT_LOUDNESS_TARGET;
334             loc_db_gain = DRC_INPUT_LOUDNESS_TARGET;
335           }
336         } else {
337           if (((loc_db_gain > 0.0f) && (slopeIsNegative == 1)) ||
338               ((loc_db_gain < 0.0f) && (slopeIsNegative == 0))) {
339             if (pstr_gain_modifiers
340                     ->target_characteristic_left_present[drc_band] == 1) {
341               err = impd_map_gain(
342                   split_drc_characteristic_source,
343                   interp_params_str->split_target_characteristic_left,
344                   loc_db_gain, &mapped_db_gain);
345               if (err) return (err);
346               gain_ratio = mapped_db_gain / loc_db_gain;
347             }
348 
349           } else if (((loc_db_gain < 0.0f) && (slopeIsNegative == 1)) ||
350                      ((loc_db_gain > 0.0f) && (slopeIsNegative == 0))) {
351             if (pstr_gain_modifiers
352                     ->target_characteristic_right_present[drc_band] == 1) {
353               split_drc_characteristic_source =
354                   interp_params_str->split_source_characteristic_right;
355               err = impd_map_gain(
356                   split_drc_characteristic_source,
357                   interp_params_str->split_target_characteristic_right,
358                   loc_db_gain, &mapped_db_gain);
359               if (err) return (err);
360               gain_ratio = mapped_db_gain / loc_db_gain;
361             }
362           }
363         }
364       }
365     }
366 
367     if (loc_db_gain < 0.0f) {
368       gain_ratio *= interp_params_str->compress;
369     } else {
370       gain_ratio *= interp_params_str->boost;
371     }
372   }
373   if (pstr_gain_modifiers->gain_scaling_flag[drc_band] == 1) {
374     if (loc_db_gain < 0.0) {
375       gain_ratio *= pstr_gain_modifiers->attn_scaling[drc_band];
376     } else {
377       gain_ratio *= pstr_gain_modifiers->ampl_scaling[drc_band];
378     }
379   }
380   if ((interp_params_str->pstr_ducking_modifiers->ducking_scaling_flag == 1) &&
381       (interp_params_str->ducking_flag == 1)) {
382     gain_ratio *= interp_params_str->pstr_ducking_modifiers->ducking_scaling;
383   }
384 
385   if (interp_params_str->interpolation_loud_eq == 1) {
386     *out_param_lin_gain =
387         gain_ratio * loc_db_gain + pstr_gain_modifiers->gain_offset[drc_band];
388     *out_param_lin_slope = 0.0f;
389   } else {
390     *out_param_lin_gain =
391         (FLOAT32)pow(2.0, (FLOAT64)(gain_ratio * loc_db_gain / 6.0f));
392     *out_param_lin_slope = SLOPE_FACTOR_DB_TO_LINEAR * gain_ratio *
393                            *out_param_lin_gain * in_param_db_slope;
394 
395     if (pstr_gain_modifiers->gain_offset_flag[drc_band] == 1) {
396       *out_param_lin_gain *= (FLOAT32)pow(
397           2.0, (FLOAT64)(pstr_gain_modifiers->gain_offset[drc_band] / 6.0f));
398     }
399     if ((interp_params_str->limiter_peak_target_present == 1) &&
400         (interp_params_str->clipping_flag == 1)) {
401       *out_param_lin_gain *= (FLOAT32)pow(
402           2.0, max(0.0, -interp_params_str->limiter_peak_target -
403                             interp_params_str->loudness_normalization_gain_db) /
404                    6.0);
405       if (*out_param_lin_gain >= 1.0) {
406         *out_param_lin_gain = 1.0;
407         *out_param_lin_slope = 0.0;
408       }
409     }
410   }
411   return (0);
412 }
413 
impd_interpolate_drc_gain(ia_interp_params_struct * interp_params_str,WORD32 drc_band,WORD32 gain_step_tdomain,FLOAT32 gain0,FLOAT32 gain1,FLOAT32 slope0,FLOAT32 slope1,FLOAT32 * result)414 WORD32 impd_interpolate_drc_gain(ia_interp_params_struct* interp_params_str,
415                                  WORD32 drc_band, WORD32 gain_step_tdomain,
416                                  FLOAT32 gain0, FLOAT32 gain1, FLOAT32 slope0,
417                                  FLOAT32 slope1, FLOAT32* result) {
418   WORD32 err = 0;
419   WORD32 n;
420   FLOAT32 k1, k2, a, b, c, d;
421   FLOAT32 slope_t1;
422   FLOAT32 slope_t2;
423   FLOAT32 gain_t1;
424   FLOAT32 gain_t2;
425 
426   WORD32 cubic_interpolation = 1;
427   WORD32 node_inser;
428   FLOAT32 node_inser_float;
429 
430   if (gain_step_tdomain <= 0) {
431     return (UNEXPECTED_ERROR);
432   }
433 
434   err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain0, slope0,
435                                    &gain_t1, &slope_t1);
436   if (err) return (err);
437   err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain1, slope1,
438                                    &gain_t2, &slope_t2);
439   if (err) return (err);
440 
441   if (interp_params_str->gain_interpolation_type ==
442       GAIN_INTERPOLATION_TYPE_SPLINE) {
443     slope_t1 = slope_t1 / (FLOAT32)interp_params_str->delta_tmin;
444     slope_t2 = slope_t2 / (FLOAT32)interp_params_str->delta_tmin;
445     if ((FLOAT32)fabs((FLOAT64)slope_t1) > (FLOAT32)fabs((FLOAT64)slope_t2)) {
446       node_inser_float = 2.0f *
447                          (gain_t2 - gain_t1 - slope_t2 * gain_step_tdomain) /
448                          (slope_t1 - slope_t2);
449       node_inser = (WORD32)(0.5f + node_inser_float);
450       if ((node_inser >= 0) && (node_inser < gain_step_tdomain)) {
451         cubic_interpolation = 0;
452 
453         result[0] = gain_t1;
454         result[gain_step_tdomain] = gain_t2;
455 
456         a = 0.5f * (slope_t2 - slope_t1) / node_inser_float;
457         b = slope_t1;
458         c = gain_t1;
459         for (n = 1; n < node_inser; n++) {
460           FLOAT32 t = (FLOAT32)n;
461           result[n] = (a * t + b) * t + c;
462           result[n] = max(0.0f, result[n]);
463         }
464         a = slope_t2;
465         b = gain_t2;
466         for (; n < gain_step_tdomain; n++) {
467           FLOAT32 t = (FLOAT32)(n - gain_step_tdomain);
468           result[n] = a * t + b;
469         }
470       }
471     } else if ((FLOAT32)fabs((FLOAT64)slope_t1) <
472                (FLOAT32)fabs((FLOAT64)slope_t2)) {
473       node_inser_float = 2.0f *
474                          (gain_t1 - gain_t2 + slope_t1 * gain_step_tdomain) /
475                          (slope_t1 - slope_t2);
476       node_inser_float = gain_step_tdomain - node_inser_float;
477       node_inser = (WORD32)(0.5f + node_inser_float);
478       if ((node_inser >= 0) && (node_inser < gain_step_tdomain)) {
479         cubic_interpolation = 0;
480 
481         result[0] = gain_t1;
482         result[gain_step_tdomain] = gain_t2;
483 
484         a = slope_t1;
485         b = gain_t1;
486         for (n = 1; n < node_inser; n++) {
487           FLOAT32 t = (FLOAT32)n;
488           result[n] = a * t + b;
489         }
490         a = (slope_t2 - slope_t1) /
491             (2.0f * (gain_step_tdomain - node_inser_float));
492         b = -slope_t2;
493         c = gain_t2;
494         for (; n < gain_step_tdomain; n++) {
495           FLOAT32 t = (FLOAT32)(gain_step_tdomain - n);
496           result[n] = (a * t + b) * t + c;
497           result[n] = max(0.0f, result[n]);
498         }
499       }
500     }
501 
502     if (cubic_interpolation == 1) {
503       FLOAT32 gain_step_inv = 1.0f / (FLOAT32)gain_step_tdomain;
504       FLOAT32 gain_step_inv2 = gain_step_inv * gain_step_inv;
505 
506       k1 = (gain_t2 - gain_t1) * gain_step_inv2;
507       k2 = slope_t2 + slope_t1;
508 
509       a = gain_step_inv * (gain_step_inv * k2 - 2.0f * k1);
510       b = 3.0f * k1 - gain_step_inv * (k2 + slope_t1);
511       c = slope_t1;
512       d = gain_t1;
513 
514       result[0] = gain_t1;
515       result[gain_step_tdomain] = gain_t2;
516       for (n = 1; n < gain_step_tdomain; n++) {
517         FLOAT32 t = (FLOAT32)n;
518         result[n] = (((a * t + b) * t + c) * t) + d;
519         result[n] = max(0.0f, result[n]);
520       }
521     }
522   } else {
523     a = (gain_t2 - gain_t1) / (FLOAT32)gain_step_tdomain;
524     b = gain_t1;
525     result[0] = gain_t1;
526     result[gain_step_tdomain] = gain_t2;
527     for (n = 1; n < gain_step_tdomain; n++) {
528       FLOAT32 t = (FLOAT32)n;
529       result[n] = a * t + b;
530     }
531   }
532   return 0;
533 }
534 
impd_advance_buf(WORD32 drc_frame_size,ia_gain_buffer_struct * pstr_gain_buf)535 VOID impd_advance_buf(WORD32 drc_frame_size,
536                       ia_gain_buffer_struct* pstr_gain_buf) {
537   WORD32 n;
538   ia_interp_buf_struct* buf_interpolation;
539 
540   for (n = 0; n < pstr_gain_buf->buf_interpolation_count; n++) {
541     buf_interpolation = &(pstr_gain_buf->buf_interpolation[n]);
542     buf_interpolation->prev_node = buf_interpolation->str_node;
543     buf_interpolation->prev_node.time -= drc_frame_size;
544     memmove(buf_interpolation->lpcm_gains,
545             buf_interpolation->lpcm_gains + drc_frame_size,
546             sizeof(FLOAT32) * (drc_frame_size + MAX_SIGNAL_DELAY));
547   }
548   return;
549 }
550 WORD32
impd_concatenate_segments(WORD32 drc_frame_size,WORD32 drc_band,ia_interp_params_struct * interp_params_str,ia_spline_nodes_struct * str_spline_nodes,ia_interp_buf_struct * buf_interpolation,WORD32 sel_drc_index,WORD32 is_config_changed,WORD32 loudness_changed)551 impd_concatenate_segments(WORD32 drc_frame_size, WORD32 drc_band,
552                           ia_interp_params_struct* interp_params_str,
553                           ia_spline_nodes_struct* str_spline_nodes,
554                           ia_interp_buf_struct* buf_interpolation,
555                           WORD32 sel_drc_index, WORD32 is_config_changed,
556                           WORD32 loudness_changed) {
557   WORD32 time_prev, duration, n, err = 0;
558   FLOAT32 loc_db_gain = 0.0f, prev_db_gain, slope = 0.0f, slope_prev;
559 
560   time_prev = buf_interpolation->prev_node.time;
561   prev_db_gain = buf_interpolation->prev_node.loc_db_gain;
562   slope_prev = buf_interpolation->prev_node.slope;
563   for (n = 0; n < str_spline_nodes->num_nodes; n++) {
564     duration = str_spline_nodes->str_node[n].time - time_prev;
565     loc_db_gain = str_spline_nodes->str_node[n].loc_db_gain;
566     if (loudness_changed) {
567       if (sel_drc_index == 0 && is_config_changed == 1) {
568         loc_db_gain = str_spline_nodes->str_node[n].loc_db_gain +
569                       interp_params_str->loudness_normalization_gain_db;
570         if (prev_db_gain == 0) {
571           prev_db_gain = buf_interpolation->prev_node.loc_db_gain +
572                          interp_params_str->loudness_normalization_gain_db;
573         }
574       }
575     }
576     slope = str_spline_nodes->str_node[n].slope;
577 
578     err = impd_interpolate_drc_gain(
579         interp_params_str, drc_band, duration, prev_db_gain, loc_db_gain,
580         slope_prev, slope, buf_interpolation->lpcm_gains + MAX_SIGNAL_DELAY +
581                               drc_frame_size + time_prev);
582     if (err) return (err);
583 
584     time_prev = str_spline_nodes->str_node[n].time;
585     prev_db_gain = loc_db_gain;
586     slope_prev = slope;
587   }
588 
589   buf_interpolation->str_node.loc_db_gain = loc_db_gain;
590   buf_interpolation->str_node.slope = slope;
591   buf_interpolation->str_node.time = time_prev;
592 
593   return (0);
594 }
595 
596 WORD32
impd_get_drc_gain(ia_drc_gain_dec_struct * p_drc_gain_dec_structs,ia_drc_config * pstr_drc_config,ia_drc_gain_struct * pstr_drc_gain,FLOAT32 compress,FLOAT32 boost,WORD32 characteristic_index,FLOAT32 loudness_normalization_gain_db,WORD32 sel_drc_index,ia_drc_gain_buffers_struct * drc_gain_buffers)597 impd_get_drc_gain(ia_drc_gain_dec_struct* p_drc_gain_dec_structs,
598                   ia_drc_config* pstr_drc_config,
599                   ia_drc_gain_struct* pstr_drc_gain, FLOAT32 compress,
600                   FLOAT32 boost, WORD32 characteristic_index,
601                   FLOAT32 loudness_normalization_gain_db, WORD32 sel_drc_index,
602                   ia_drc_gain_buffers_struct* drc_gain_buffers) {
603   ia_drc_params_struct* ia_drc_params_struct =
604       &(p_drc_gain_dec_structs->ia_drc_params_struct);
605   WORD32 drc_instructions_index =
606       ia_drc_params_struct->sel_drc_array[sel_drc_index].drc_instructions_index;
607   if (drc_instructions_index >= 0) {
608     WORD32 b, g, gain_element_index, err = 0;
609     WORD32 parametric_drc_instance_index = 0;
610     ia_interp_params_struct interp_params_str = {0};
611 
612     ia_drc_instructions_struct* str_drc_instruction_str =
613         &(pstr_drc_config->str_drc_instruction_str[drc_instructions_index]);
614     WORD32 drc_set_effect = str_drc_instruction_str->drc_set_effect;
615     WORD32 num_drc_ch_groups = str_drc_instruction_str->num_drc_ch_groups;
616     ia_uni_drc_coeffs_struct* str_p_loc_drc_coefficients_uni_drc = NULL;
617     WORD32 drc_coeff_idx =
618         ia_drc_params_struct->sel_drc_array[sel_drc_index].drc_coeff_idx;
619     if (drc_coeff_idx >= 0) {
620       str_p_loc_drc_coefficients_uni_drc =
621           &(pstr_drc_config->str_p_loc_drc_coefficients_uni_drc[drc_coeff_idx]);
622       interp_params_str.interpolation_loud_eq = 0;
623     } else {
624       return (UNEXPECTED_ERROR);
625     }
626 
627     interp_params_str.loudness_normalization_gain_db =
628         loudness_normalization_gain_db;
629     interp_params_str.characteristic_index = characteristic_index;
630     interp_params_str.compress = compress;
631     interp_params_str.boost = boost;
632     interp_params_str.limiter_peak_target_present =
633         str_drc_instruction_str->limiter_peak_target_present;
634     interp_params_str.limiter_peak_target =
635         str_drc_instruction_str->limiter_peak_target;
636 
637     if (((drc_set_effect & (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) ==
638          0) &&
639         (drc_set_effect != EFFECT_BIT_FADE) &&
640         (drc_set_effect != EFFECT_BIT_CLIPPING)) {
641       interp_params_str.gain_modification_flag = 1;
642     } else {
643       interp_params_str.gain_modification_flag = 0;
644     }
645     if (drc_set_effect & (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) {
646       interp_params_str.ducking_flag = 1;
647     } else {
648       interp_params_str.ducking_flag = 0;
649     }
650     if (drc_set_effect == EFFECT_BIT_CLIPPING) {
651       interp_params_str.clipping_flag = 1;
652     } else {
653       interp_params_str.clipping_flag = 0;
654     }
655 
656     impd_advance_buf(ia_drc_params_struct->drc_frame_size,
657                      &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]));
658 
659     gain_element_index = 0;
660     for (g = 0; g < num_drc_ch_groups; g++) {
661       WORD32 gainSet = 0;
662       WORD32 num_drc_bands = 0;
663       interp_params_str.gain_interpolation_type =
664           str_drc_instruction_str->gain_interpolation_type_for_channel_group[g];
665       interp_params_str.delta_tmin =
666           str_drc_instruction_str->time_delta_min_for_channel_group[g];
667       interp_params_str.pstr_ducking_modifiers = &(
668           str_drc_instruction_str->str_ducking_modifiers_for_channel_group[g]);
669       interp_params_str.pstr_gain_modifiers =
670           &(str_drc_instruction_str->str_gain_modifiers_of_ch_group[g]);
671       if (str_drc_instruction_str->ch_group_parametric_drc_flag[g] == 0) {
672         gainSet = str_drc_instruction_str->gain_set_index_for_channel_group[g];
673         num_drc_bands = str_drc_instruction_str->band_count_of_ch_group[g];
674         for (b = 0; b < num_drc_bands; b++) {
675           ia_gain_params_struct* gain_params =
676               &(str_p_loc_drc_coefficients_uni_drc->gain_set_params[gainSet]
677                     .gain_params[b]);
678           WORD32 seq = gain_params->gain_seq_idx;
679           interp_params_str.drc_characteristic_present =
680               gain_params->drc_characteristic_present;
681           interp_params_str.drc_source_characteristic_cicp_format =
682               gain_params->drc_characteristic_format_is_cicp;
683           interp_params_str.source_drc_characteristic =
684               gain_params->drc_characteristic;
685           interp_params_str.split_source_characteristic_left = &(
686               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_left
687                   [gain_params->drc_characteristic_left_index]);
688           interp_params_str.split_source_characteristic_right = &(
689               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_right
690                   [gain_params->drc_characteristic_right_index]);
691           interp_params_str.split_target_characteristic_left = &(
692               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_left
693                   [interp_params_str.pstr_gain_modifiers
694                        ->target_characteristic_left_index[b]]);
695           interp_params_str.split_target_characteristic_right = &(
696               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_right
697                   [interp_params_str.pstr_gain_modifiers
698                        ->target_characteristic_right_index[b]]);
699           err = impd_concatenate_segments(
700               ia_drc_params_struct->drc_frame_size, b, &interp_params_str,
701               &(pstr_drc_gain->drc_gain_sequence[seq].str_spline_nodes[0]),
702               &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
703                     .buf_interpolation[gain_element_index]),
704               sel_drc_index, pstr_drc_config->is_config_changed,
705               pstr_drc_config->ln_gain_changed);
706           if (err) return (err);
707           gain_element_index++;
708         }
709       } else {
710         if (ia_drc_params_struct->sub_band_domain_mode ==
711                 SUBBAND_DOMAIN_MODE_OFF &&
712             !(p_drc_gain_dec_structs->parametricdrc_params
713                   .str_parametric_drc_instance_params
714                       [parametric_drc_instance_index]
715                   .parametric_drc_type == PARAM_DRC_TYPE_LIM)) {
716           err = impd_parametric_drc_instance_process(
717               p_drc_gain_dec_structs->audio_in_out_buf.audio_in_out_buf, NULL,
718               NULL, &p_drc_gain_dec_structs->parametricdrc_params,
719               &p_drc_gain_dec_structs->parametricdrc_params
720                    .str_parametric_drc_instance_params
721                        [parametric_drc_instance_index]);
722           if (err) return (err);
723 
724           err = impd_concatenate_segments(
725               ia_drc_params_struct->drc_frame_size, 0, &interp_params_str,
726               &p_drc_gain_dec_structs->parametricdrc_params
727                    .str_parametric_drc_instance_params
728                        [parametric_drc_instance_index]
729                    .str_spline_nodes,
730               &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
731                     .buf_interpolation[gain_element_index]),
732               sel_drc_index, pstr_drc_config->is_config_changed,
733               pstr_drc_config->ln_gain_changed);
734           if (err) return (err);
735         } else if (ia_drc_params_struct->sub_band_domain_mode ==
736                        SUBBAND_DOMAIN_MODE_OFF &&
737                    p_drc_gain_dec_structs->parametricdrc_params
738                            .str_parametric_drc_instance_params
739                                [parametric_drc_instance_index]
740                            .parametric_drc_type == PARAM_DRC_TYPE_LIM) {
741           FLOAT32* lpcm_gains = (drc_gain_buffers->pstr_gain_buf[sel_drc_index]
742                                      .buf_interpolation[gain_element_index])
743                                     .lpcm_gains +
744                                 MAX_SIGNAL_DELAY;
745           impd_parametric_lim_type_drc_process(
746               p_drc_gain_dec_structs->audio_in_out_buf.audio_in_out_buf,
747               loudness_normalization_gain_db,
748               &p_drc_gain_dec_structs->parametricdrc_params
749                    .str_parametric_drc_instance_params
750                        [parametric_drc_instance_index]
751                    .str_parametric_drc_type_lim_params,
752               lpcm_gains);
753 
754         } else if (ia_drc_params_struct->sub_band_domain_mode !=
755                        SUBBAND_DOMAIN_MODE_OFF &&
756                    !(p_drc_gain_dec_structs->parametricdrc_params
757                          .str_parametric_drc_instance_params
758                              [parametric_drc_instance_index]
759                          .parametric_drc_type == PARAM_DRC_TYPE_LIM)) {
760           err = impd_parametric_drc_instance_process(
761               NULL, p_drc_gain_dec_structs->audio_in_out_buf.audio_real_buff,
762               p_drc_gain_dec_structs->audio_in_out_buf.audio_imag_buff,
763               &p_drc_gain_dec_structs->parametricdrc_params,
764               &p_drc_gain_dec_structs->parametricdrc_params
765                    .str_parametric_drc_instance_params
766                        [parametric_drc_instance_index]);
767           if (err) return (err);
768 
769           err = impd_concatenate_segments(
770               ia_drc_params_struct->drc_frame_size, 0, &interp_params_str,
771               &p_drc_gain_dec_structs->parametricdrc_params
772                    .str_parametric_drc_instance_params
773                        [parametric_drc_instance_index]
774                    .str_spline_nodes,
775               &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
776                     .buf_interpolation[gain_element_index]),
777                     sel_drc_index, pstr_drc_config->is_config_changed,
778                     pstr_drc_config->ln_gain_changed);
779           if (err) return (err);
780 
781         } else {
782           return (UNEXPECTED_ERROR);
783         }
784         gain_element_index++;
785         parametric_drc_instance_index++;
786       }
787     }
788   }
789   return (0);
790 }
791