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