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
37extern ia_cicp_sigmoid_characteristic_param_struct
38    pstr_cicp_sigmoid_characteristic_param[];
39
40WORD32 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
99WORD32
100impd_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
124WORD32
125impd_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
148WORD32
149impd_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
170WORD32
171impd_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
194WORD32
195impd_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
244WORD32
245impd_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
296WORD32
297impd_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
416WORD32 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  if (interp_params_str->gain_interpolation_type ==
437      GAIN_INTERPOLATION_TYPE_SPLINE) {
438    err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain0, slope0,
439                                     &gain_t1, &slope_t1);
440    if (err) return (err);
441    err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain1, slope1,
442                                     &gain_t2, &slope_t2);
443    if (err) return (err);
444
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    err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain1, slope1,
526                                     &gain_t2, &slope_t2);
527    if (err) return (err);
528
529    a = 0;
530    b = gain_t2;
531
532    result[0] = gain_t2;
533    result[gain_step_tdomain] = gain_t2;
534    for (n = 1; n < gain_step_tdomain; n++) {
535      FLOAT32 t = (FLOAT32)n;
536      result[n] = a * t + b;
537    }
538  }
539  return 0;
540}
541
542WORD32
543impd_advance_buf(WORD32 drc_frame_size, ia_gain_buffer_struct* pstr_gain_buf) {
544  WORD32 n;
545  ia_interp_buf_struct* buf_interpolation;
546
547  for (n = 0; n < pstr_gain_buf->buf_interpolation_count; n++) {
548    buf_interpolation = &(pstr_gain_buf->buf_interpolation[n]);
549    buf_interpolation->prev_node = buf_interpolation->str_node;
550    buf_interpolation->prev_node.time -= drc_frame_size;
551    memmove(buf_interpolation->lpcm_gains,
552            buf_interpolation->lpcm_gains + drc_frame_size,
553            sizeof(FLOAT32) * (drc_frame_size + MAX_SIGNAL_DELAY));
554  }
555  return (0);
556}
557WORD32
558impd_concatenate_segments(WORD32 drc_frame_size, WORD32 drc_band,
559                          ia_interp_params_struct* interp_params_str,
560                          ia_spline_nodes_struct* str_spline_nodes,
561                          ia_interp_buf_struct* buf_interpolation) {
562  WORD32 timePrev, duration, n, err = 0;
563  FLOAT32 loc_db_gain = 0.0f, prev_db_gain, slope = 0.0f, slopePrev;
564
565  timePrev = buf_interpolation->prev_node.time;
566  prev_db_gain = buf_interpolation->prev_node.loc_db_gain;
567  slopePrev = buf_interpolation->prev_node.slope;
568  for (n = 0; n < str_spline_nodes->num_nodes; n++) {
569    duration = str_spline_nodes->str_node[n].time - timePrev;
570    loc_db_gain = str_spline_nodes->str_node[n].loc_db_gain;
571    slope = str_spline_nodes->str_node[n].slope;
572
573    err = impd_interpolate_drc_gain(
574        interp_params_str, drc_band, duration, prev_db_gain, loc_db_gain,
575        slopePrev, slope, buf_interpolation->lpcm_gains + MAX_SIGNAL_DELAY +
576                              drc_frame_size + timePrev);
577    if (err) return (err);
578
579    timePrev = str_spline_nodes->str_node[n].time;
580    prev_db_gain = loc_db_gain;
581    slopePrev = slope;
582  }
583
584  buf_interpolation->str_node.loc_db_gain = loc_db_gain;
585  buf_interpolation->str_node.slope = slope;
586  buf_interpolation->str_node.time = timePrev;
587
588  return (0);
589}
590
591WORD32
592impd_get_drc_gain(ia_drc_gain_dec_struct* p_drc_gain_dec_structs,
593                  ia_drc_config* pstr_drc_config,
594                  ia_drc_gain_struct* pstr_drc_gain, FLOAT32 compress,
595                  FLOAT32 boost, WORD32 characteristic_index,
596                  FLOAT32 loudness_normalization_gain_db, WORD32 sel_drc_index,
597                  ia_drc_gain_buffers_struct* drc_gain_buffers) {
598  ia_drc_params_struct* ia_drc_params_struct =
599      &(p_drc_gain_dec_structs->ia_drc_params_struct);
600  WORD32 drc_instructions_index =
601      ia_drc_params_struct->sel_drc_array[sel_drc_index].drc_instructions_index;
602  if (drc_instructions_index >= 0) {
603    WORD32 b, g, gainElementIndex, err = 0;
604    WORD32 parametricDrcInstanceIndex = 0;
605    ia_interp_params_struct interp_params_str = {0};
606
607    ia_drc_instructions_struct* str_drc_instruction_str =
608        &(pstr_drc_config->str_drc_instruction_str[drc_instructions_index]);
609    WORD32 drc_set_effect = str_drc_instruction_str->drc_set_effect;
610    WORD32 num_drc_ch_groups = str_drc_instruction_str->num_drc_ch_groups;
611    ia_uni_drc_coeffs_struct* str_p_loc_drc_coefficients_uni_drc = NULL;
612    WORD32 drc_coeff_idx =
613        ia_drc_params_struct->sel_drc_array[sel_drc_index].drc_coeff_idx;
614    if (drc_coeff_idx >= 0) {
615      str_p_loc_drc_coefficients_uni_drc =
616          &(pstr_drc_config->str_p_loc_drc_coefficients_uni_drc[drc_coeff_idx]);
617      interp_params_str.interpolation_loud_eq = 0;
618    } else {
619      return (UNEXPECTED_ERROR);
620    }
621
622    interp_params_str.loudness_normalization_gain_db =
623        loudness_normalization_gain_db;
624    interp_params_str.characteristic_index = characteristic_index;
625    interp_params_str.compress = compress;
626    interp_params_str.boost = boost;
627    interp_params_str.limiter_peak_target_present =
628        str_drc_instruction_str->limiter_peak_target_present;
629    interp_params_str.limiter_peak_target =
630        str_drc_instruction_str->limiter_peak_target;
631
632    if (((drc_set_effect & (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) ==
633         0) &&
634        (drc_set_effect != EFFECT_BIT_FADE) &&
635        (drc_set_effect != EFFECT_BIT_CLIPPING)) {
636      interp_params_str.gain_modification_flag = 1;
637    } else {
638      interp_params_str.gain_modification_flag = 0;
639    }
640    if (drc_set_effect & (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) {
641      interp_params_str.ducking_flag = 1;
642    } else {
643      interp_params_str.ducking_flag = 0;
644    }
645    if (drc_set_effect == EFFECT_BIT_CLIPPING) {
646      interp_params_str.clipping_flag = 1;
647    } else {
648      interp_params_str.clipping_flag = 0;
649    }
650
651    err = impd_advance_buf(ia_drc_params_struct->drc_frame_size,
652                           &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]));
653    if (err) return (err);
654
655    gainElementIndex = 0;
656    for (g = 0; g < num_drc_ch_groups; g++) {
657      WORD32 gainSet = 0;
658      WORD32 num_drc_bands = 0;
659      interp_params_str.gain_interpolation_type =
660          str_drc_instruction_str->gain_interpolation_type_for_channel_group[g];
661      interp_params_str.delta_tmin =
662          str_drc_instruction_str->time_delta_min_for_channel_group[g];
663      interp_params_str.pstr_ducking_modifiers = &(
664          str_drc_instruction_str->str_ducking_modifiers_for_channel_group[g]);
665      interp_params_str.pstr_gain_modifiers =
666          &(str_drc_instruction_str->str_gain_modifiers_of_ch_group[g]);
667      if (str_drc_instruction_str->ch_group_parametric_drc_flag[g] == 0) {
668        gainSet = str_drc_instruction_str->gain_set_index_for_channel_group[g];
669        num_drc_bands = str_drc_instruction_str->band_count_of_ch_group[g];
670        for (b = 0; b < num_drc_bands; b++) {
671          ia_gain_params_struct* gain_params =
672              &(str_p_loc_drc_coefficients_uni_drc->gain_set_params[gainSet]
673                    .gain_params[b]);
674          WORD32 seq = gain_params->gain_seq_idx;
675          interp_params_str.drc_characteristic_present =
676              gain_params->drc_characteristic_present;
677          interp_params_str.drc_source_characteristic_cicp_format =
678              gain_params->drc_characteristic_format_is_cicp;
679          interp_params_str.source_drc_characteristic =
680              gain_params->drc_characteristic;
681          interp_params_str.split_source_characteristic_left = &(
682              str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_left
683                  [gain_params->drc_characteristic_left_index]);
684          interp_params_str.split_source_characteristic_right = &(
685              str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_right
686                  [gain_params->drc_characteristic_right_index]);
687          interp_params_str.split_target_characteristic_left = &(
688              str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_left
689                  [interp_params_str.pstr_gain_modifiers
690                       ->target_characteristic_left_index[b]]);
691          interp_params_str.split_target_characteristic_right = &(
692              str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_right
693                  [interp_params_str.pstr_gain_modifiers
694                       ->target_characteristic_right_index[b]]);
695          err = impd_concatenate_segments(
696              ia_drc_params_struct->drc_frame_size, b, &interp_params_str,
697              &(pstr_drc_gain->drc_gain_sequence[seq].str_spline_nodes[0]),
698              &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
699                    .buf_interpolation[gainElementIndex]));
700          if (err) return (err);
701          gainElementIndex++;
702        }
703      } else {
704        if (ia_drc_params_struct->sub_band_domain_mode ==
705                SUBBAND_DOMAIN_MODE_OFF &&
706            !(p_drc_gain_dec_structs->parametricdrc_params
707                  .str_parametric_drc_instance_params
708                      [parametricDrcInstanceIndex]
709                  .parametric_drc_type == PARAM_DRC_TYPE_LIM)) {
710          err = impd_parametric_drc_instance_process(
711              p_drc_gain_dec_structs->audio_in_out_buf.audio_in_out_buf, NULL,
712              NULL, &p_drc_gain_dec_structs->parametricdrc_params,
713              &p_drc_gain_dec_structs->parametricdrc_params
714                   .str_parametric_drc_instance_params
715                       [parametricDrcInstanceIndex]);
716          if (err) return (err);
717
718          err = impd_concatenate_segments(
719              ia_drc_params_struct->drc_frame_size, 0, &interp_params_str,
720              &p_drc_gain_dec_structs->parametricdrc_params
721                   .str_parametric_drc_instance_params
722                       [parametricDrcInstanceIndex]
723                   .str_spline_nodes,
724              &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
725                    .buf_interpolation[gainElementIndex]));
726          if (err) return (err);
727        } else if (ia_drc_params_struct->sub_band_domain_mode ==
728                       SUBBAND_DOMAIN_MODE_OFF &&
729                   p_drc_gain_dec_structs->parametricdrc_params
730                           .str_parametric_drc_instance_params
731                               [parametricDrcInstanceIndex]
732                           .parametric_drc_type == PARAM_DRC_TYPE_LIM) {
733          FLOAT32* lpcm_gains = (drc_gain_buffers->pstr_gain_buf[sel_drc_index]
734                                     .buf_interpolation[gainElementIndex])
735                                    .lpcm_gains +
736                                MAX_SIGNAL_DELAY;
737          err = impd_parametric_lim_type_drc_process(
738              p_drc_gain_dec_structs->audio_in_out_buf.audio_in_out_buf,
739              loudness_normalization_gain_db,
740              &p_drc_gain_dec_structs->parametricdrc_params
741                   .str_parametric_drc_instance_params
742                       [parametricDrcInstanceIndex]
743                   .str_parametric_drc_type_lim_params,
744              lpcm_gains);
745          if (err) return (err);
746        } else if (ia_drc_params_struct->sub_band_domain_mode !=
747                       SUBBAND_DOMAIN_MODE_OFF &&
748                   !(p_drc_gain_dec_structs->parametricdrc_params
749                         .str_parametric_drc_instance_params
750                             [parametricDrcInstanceIndex]
751                         .parametric_drc_type == PARAM_DRC_TYPE_LIM)) {
752          err = impd_parametric_drc_instance_process(
753              NULL, p_drc_gain_dec_structs->audio_in_out_buf.audio_real_buff,
754              p_drc_gain_dec_structs->audio_in_out_buf.audio_imag_buff,
755              &p_drc_gain_dec_structs->parametricdrc_params,
756              &p_drc_gain_dec_structs->parametricdrc_params
757                   .str_parametric_drc_instance_params
758                       [parametricDrcInstanceIndex]);
759          if (err) return (err);
760
761          err = impd_concatenate_segments(
762              ia_drc_params_struct->drc_frame_size, 0, &interp_params_str,
763              &p_drc_gain_dec_structs->parametricdrc_params
764                   .str_parametric_drc_instance_params
765                       [parametricDrcInstanceIndex]
766                   .str_spline_nodes,
767              &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
768                    .buf_interpolation[gainElementIndex]));
769          if (err) return (err);
770
771        } else {
772          return (UNEXPECTED_ERROR);
773        }
774        gainElementIndex++;
775        parametricDrcInstanceIndex++;
776      }
777    }
778  }
779  return (0);
780}
781