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