773 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			773 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
| /******************************************************************************
 | |
|  *
 | |
|  * Copyright (C) 2018 The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at:
 | |
|  *
 | |
|  * http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  *
 | |
|  *****************************************************************************
 | |
|  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
 | |
| */
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <math.h>
 | |
| #include <string.h>
 | |
| #include "impd_type_def.h"
 | |
| #include "impd_drc_extr_delta_coded_info.h"
 | |
| #include "impd_drc_common.h"
 | |
| #include "impd_drc_struct.h"
 | |
| #include "impd_drc_interface.h"
 | |
| #include "impd_drc_filter_bank.h"
 | |
| #include "impd_drc_gain_dec.h"
 | |
| #include "impd_parametric_drc_dec.h"
 | |
| #include "impd_drc_multi_band.h"
 | |
| #include "impd_drc_process_audio.h"
 | |
| #include "impd_drc_eq.h"
 | |
| #include "impd_drc_gain_decoder.h"
 | |
| 
 | |
| extern const ia_cicp_sigmoid_characteristic_param_struct
 | |
|     pstr_cicp_sigmoid_characteristic_param[];
 | |
| 
 | |
| VOID 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) {
 | |
|   FLOAT32 loc_db_gain = in_param_db_gain;
 | |
|   FLOAT32 gain_ratio = 1.0;
 | |
| 
 | |
|   ia_gain_modifiers_struct* pstr_gain_modifiers =
 | |
|       interp_params_str->pstr_gain_modifiers;
 | |
|   if (interp_params_str->gain_modification_flag) {
 | |
|     if ((interp_params_str->characteristic_index > 0) &&
 | |
|         (loc_db_gain != 0.0f)) {
 | |
|       gain_ratio = 1.0f;
 | |
|     }
 | |
| 
 | |
|     if (loc_db_gain < 0.0f) {
 | |
|       gain_ratio *= interp_params_str->compress;
 | |
|     } else {
 | |
|       gain_ratio *= interp_params_str->boost;
 | |
|     }
 | |
|   }
 | |
|   if (pstr_gain_modifiers->gain_scaling_flag[drc_band] == 1) {
 | |
|     if (loc_db_gain < 0.0) {
 | |
|       gain_ratio *= pstr_gain_modifiers->attn_scaling[drc_band];
 | |
|     } else {
 | |
|       gain_ratio *= pstr_gain_modifiers->ampl_scaling[drc_band];
 | |
|     }
 | |
|   }
 | |
|   if ((interp_params_str->pstr_ducking_modifiers->ducking_scaling_flag == 1) &&
 | |
|       (interp_params_str->ducking_flag == 1)) {
 | |
|     gain_ratio *= interp_params_str->pstr_ducking_modifiers->ducking_scaling;
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     *out_param_lin_gain =
 | |
|         (FLOAT32)pow(2.0, (FLOAT64)(gain_ratio * loc_db_gain / 6.0f));
 | |
|     *out_param_lin_slope = SLOPE_FACTOR_DB_TO_LINEAR * gain_ratio *
 | |
|                            *out_param_lin_gain * in_param_db_slope;
 | |
| 
 | |
|     if (pstr_gain_modifiers->gain_offset_flag[drc_band] == 1) {
 | |
|       *out_param_lin_gain *= (FLOAT32)pow(
 | |
|           2.0, (FLOAT64)(pstr_gain_modifiers->gain_offset[drc_band] / 6.0f));
 | |
|     }
 | |
|     if ((interp_params_str->limiter_peak_target_present == 1) &&
 | |
|         (interp_params_str->clipping_flag == 1)) {
 | |
|       *out_param_lin_gain *= (FLOAT32)pow(
 | |
|           2.0, max(0.0, -interp_params_str->limiter_peak_target -
 | |
|                             interp_params_str->loudness_normalization_gain_db) /
 | |
|                    6.0);
 | |
|       if (*out_param_lin_gain >= 1.0) {
 | |
|         *out_param_lin_gain = 1.0;
 | |
|         *out_param_lin_slope = 0.0;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return;
 | |
| }
 | |
| 
 | |
| WORD32
 | |
| impd_compressor_io_sigmoid(
 | |
|     ia_split_drc_characteristic_struct* split_drc_characteristic,
 | |
|     FLOAT32 in_db_level, FLOAT32* out_db_gain) {
 | |
|   FLOAT32 tmp;
 | |
|   FLOAT32 in_out_ratio = split_drc_characteristic->in_out_ratio;
 | |
|   FLOAT32 gainDbLimit = split_drc_characteristic->gain;
 | |
|   FLOAT32 exp = split_drc_characteristic->exp;
 | |
| 
 | |
|   tmp = (DRC_INPUT_LOUDNESS_TARGET - in_db_level) * in_out_ratio;
 | |
|   if (exp < 1000.0f) {
 | |
|     FLOAT32 x = tmp / gainDbLimit;
 | |
|     if (x < 0.0f) {
 | |
|       return (UNEXPECTED_ERROR);
 | |
|     }
 | |
|     *out_db_gain = (FLOAT32)(tmp / pow(1.0f + pow(x, exp), 1.0f / exp));
 | |
|   } else {
 | |
|     *out_db_gain = tmp;
 | |
|   }
 | |
|   if (split_drc_characteristic->flip_sign == 1) {
 | |
|     *out_db_gain = -*out_db_gain;
 | |
|   }
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| WORD32
 | |
| impd_compressor_io_sigmoid_inv(
 | |
|     ia_split_drc_characteristic_struct* split_drc_characteristic,
 | |
|     FLOAT32 loc_db_gain, FLOAT32* in_level) {
 | |
|   FLOAT32 in_out_ratio = split_drc_characteristic->in_out_ratio;
 | |
|   FLOAT32 gainDbLimit = split_drc_characteristic->gain;
 | |
|   FLOAT32 exp = split_drc_characteristic->exp;
 | |
|   FLOAT32 tmp = loc_db_gain;
 | |
| 
 | |
|   if (split_drc_characteristic->flip_sign == 1) {
 | |
|     tmp = -loc_db_gain;
 | |
|   }
 | |
|   if (exp < 1000.0f) {
 | |
|     FLOAT32 x = tmp / gainDbLimit;
 | |
|     if (x < 0.0f) {
 | |
|       return (UNEXPECTED_ERROR);
 | |
|     }
 | |
|     tmp = (FLOAT32)(tmp / pow(1.0f - pow(x, exp), 1.0f / exp));
 | |
|   }
 | |
|   *in_level = DRC_INPUT_LOUDNESS_TARGET - tmp / in_out_ratio;
 | |
| 
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| WORD32
 | |
| impd_compressor_io_nodes_lt(
 | |
|     ia_split_drc_characteristic_struct* split_drc_characteristic,
 | |
|     FLOAT32 in_db_level, FLOAT32* out_db_gain) {
 | |
|   WORD32 n;
 | |
|   FLOAT32 w;
 | |
|   FLOAT32* node_level = split_drc_characteristic->node_level;
 | |
|   FLOAT32* node_gain = split_drc_characteristic->node_gain;
 | |
| 
 | |
|   if (in_db_level > DRC_INPUT_LOUDNESS_TARGET) {
 | |
|     return (UNEXPECTED_ERROR);
 | |
|   }
 | |
|   for (n = 1; n <= split_drc_characteristic->characteristic_node_count; n++) {
 | |
|     if ((in_db_level <= node_level[n - 1]) && (in_db_level > node_level[n])) {
 | |
|       w = (node_level[n] - in_db_level) / (node_level[n] - node_level[n - 1]);
 | |
|       *out_db_gain = (FLOAT32)(w * node_gain[n - 1] + (1.0 - w) * node_gain[n]);
 | |
|     }
 | |
|   }
 | |
|   *out_db_gain = node_gain[split_drc_characteristic->characteristic_node_count];
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| WORD32
 | |
| impd_compressor_io_nodes_rt(
 | |
|     ia_split_drc_characteristic_struct* split_drc_characteristic,
 | |
|     FLOAT32 in_db_level, FLOAT32* out_db_gain) {
 | |
|   WORD32 n;
 | |
|   FLOAT32 w;
 | |
|   FLOAT32* node_level = split_drc_characteristic->node_level;
 | |
|   FLOAT32* node_gain = split_drc_characteristic->node_gain;
 | |
| 
 | |
|   if (in_db_level < DRC_INPUT_LOUDNESS_TARGET) {
 | |
|     return (UNEXPECTED_ERROR);
 | |
|   }
 | |
|   for (n = 1; n <= split_drc_characteristic->characteristic_node_count; n++) {
 | |
|     if ((in_db_level >= node_level[n - 1]) && (in_db_level < node_level[n])) {
 | |
|       w = (FLOAT32)(node_level[n] - in_db_level) /
 | |
|           (node_level[n] - node_level[n - 1]);
 | |
|       *out_db_gain = (FLOAT32)(w * node_gain[n - 1] + (1.0 - w) * node_gain[n]);
 | |
|     }
 | |
|   }
 | |
|   *out_db_gain =
 | |
|       (node_gain[split_drc_characteristic->characteristic_node_count]);
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| VOID impd_compressor_io_nodes_inverse(
 | |
|     ia_split_drc_characteristic_struct* split_drc_characteristic,
 | |
|     FLOAT32 loc_db_gain, FLOAT32* in_level) {
 | |
|   WORD32 n;
 | |
|   FLOAT32 w;
 | |
|   FLOAT32* node_level = split_drc_characteristic->node_level;
 | |
|   FLOAT32* node_gain = split_drc_characteristic->node_gain;
 | |
|   WORD32 node_count = split_drc_characteristic->characteristic_node_count;
 | |
| 
 | |
|   if (node_gain[1] < 0.0f) {
 | |
|     if (loc_db_gain <= node_gain[node_count]) {
 | |
|       *in_level = node_level[node_count];
 | |
|     } else {
 | |
|       if (loc_db_gain >= 0.0f) {
 | |
|         *in_level = DRC_INPUT_LOUDNESS_TARGET;
 | |
|       } else {
 | |
|         for (n = 1; n <= node_count; n++) {
 | |
|           if ((loc_db_gain <= node_gain[n - 1]) &&
 | |
|               (loc_db_gain > node_gain[n])) {
 | |
|             w = (node_gain[n] - loc_db_gain) /
 | |
|                 (node_gain[n] - node_gain[n - 1]);
 | |
|             *in_level =
 | |
|                 (FLOAT32)(w * node_level[n - 1] + (1.0 - w) * node_level[n]);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     if (loc_db_gain >= node_gain[node_count]) {
 | |
|       *in_level = node_level[node_count];
 | |
|     } else {
 | |
|       if (loc_db_gain <= 0.0f) {
 | |
|         *in_level = DRC_INPUT_LOUDNESS_TARGET;
 | |
|       } else {
 | |
|         for (n = 1; n <= node_count; n++) {
 | |
|           if ((loc_db_gain >= node_gain[n - 1]) &&
 | |
|               (loc_db_gain < node_gain[n])) {
 | |
|             w = (FLOAT32)(node_gain[n] - loc_db_gain) /
 | |
|                 (node_gain[n] - node_gain[n - 1]);
 | |
|             *in_level =
 | |
|                 (FLOAT32)(w * node_level[n - 1] + (1.0 - w) * node_level[n]);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   FLOAT32 inLevel;
 | |
|   WORD32 err = 0;
 | |
| 
 | |
|   switch (split_drc_characteristic_source->characteristic_format) {
 | |
|     case CHARACTERISTIC_SIGMOID:
 | |
|       err = impd_compressor_io_sigmoid_inv(split_drc_characteristic_source,
 | |
|                                            gain_in_db, &inLevel);
 | |
|       if (err) return (err);
 | |
|       break;
 | |
|     case CHARACTERISTIC_NODES:
 | |
|       impd_compressor_io_nodes_inverse(split_drc_characteristic_source,
 | |
|                                        gain_in_db, &inLevel);
 | |
| 
 | |
|       break;
 | |
|     case CHARACTERISTIC_PASS_THRU:
 | |
|       inLevel = gain_in_db;
 | |
|       break;
 | |
|     default:
 | |
|       return (UNEXPECTED_ERROR);
 | |
|       break;
 | |
|   }
 | |
|   switch (split_drc_characteristic_target->characteristic_format) {
 | |
|     case CHARACTERISTIC_SIGMOID:
 | |
|       err = impd_compressor_io_sigmoid(split_drc_characteristic_target, inLevel,
 | |
|                                        gain_out_db);
 | |
|       if (err) return (err);
 | |
|       break;
 | |
|     case CHARACTERISTIC_NODES:
 | |
|       if (inLevel < DRC_INPUT_LOUDNESS_TARGET) {
 | |
|         err = impd_compressor_io_nodes_lt(split_drc_characteristic_target,
 | |
|                                           inLevel, gain_out_db);
 | |
|         if (err) return (err);
 | |
|       } else {
 | |
|         err = impd_compressor_io_nodes_rt(split_drc_characteristic_target,
 | |
|                                           inLevel, gain_out_db);
 | |
|         if (err) return (err);
 | |
|       }
 | |
|       break;
 | |
|     case CHARACTERISTIC_PASS_THRU:
 | |
|       *gain_out_db = inLevel;
 | |
|       break;
 | |
|     default:
 | |
|       break;
 | |
|   }
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   WORD32 err = 0;
 | |
|   FLOAT32 loc_db_gain = in_param_db_gain;
 | |
|   FLOAT32 gain_ratio = 1.0;
 | |
|   FLOAT32 mapped_db_gain;
 | |
|   ia_gain_modifiers_struct* pstr_gain_modifiers =
 | |
|       interp_params_str->pstr_gain_modifiers;
 | |
|   if (interp_params_str->gain_modification_flag) {
 | |
|     ia_split_drc_characteristic_struct* split_drc_characteristic_source;
 | |
| 
 | |
|     WORD32 slopeIsNegative;
 | |
| 
 | |
|     if (interp_params_str->drc_characteristic_present) {
 | |
|       if (interp_params_str->drc_source_characteristic_cicp_format) {
 | |
|       } else {
 | |
|         slopeIsNegative = 0;
 | |
|         split_drc_characteristic_source =
 | |
|             interp_params_str->split_source_characteristic_left;
 | |
|         if (split_drc_characteristic_source->characteristic_format == 0) {
 | |
|           slopeIsNegative = 1;
 | |
|         } else {
 | |
|           if (split_drc_characteristic_source->node_gain[1] > 0.0f) {
 | |
|             slopeIsNegative = 1;
 | |
|           }
 | |
|         }
 | |
|         if (loc_db_gain == 0.0f) {
 | |
|           if (((pstr_gain_modifiers
 | |
|                     ->target_characteristic_left_present[drc_band] == 1) &&
 | |
|                (interp_params_str->split_target_characteristic_left
 | |
|                     ->characteristic_format == CHARACTERISTIC_PASS_THRU)) ||
 | |
|               ((pstr_gain_modifiers
 | |
|                     ->target_characteristic_right_present[drc_band] == 1) &&
 | |
|                (interp_params_str->split_target_characteristic_right
 | |
|                     ->characteristic_format == CHARACTERISTIC_PASS_THRU))) {
 | |
|             mapped_db_gain = DRC_INPUT_LOUDNESS_TARGET;
 | |
|             loc_db_gain = DRC_INPUT_LOUDNESS_TARGET;
 | |
|           }
 | |
|         } else {
 | |
|           if (((loc_db_gain > 0.0f) && (slopeIsNegative == 1)) ||
 | |
|               ((loc_db_gain < 0.0f) && (slopeIsNegative == 0))) {
 | |
|             if (pstr_gain_modifiers
 | |
|                     ->target_characteristic_left_present[drc_band] == 1) {
 | |
|               err = impd_map_gain(
 | |
|                   split_drc_characteristic_source,
 | |
|                   interp_params_str->split_target_characteristic_left,
 | |
|                   loc_db_gain, &mapped_db_gain);
 | |
|               if (err) return (err);
 | |
|               gain_ratio = mapped_db_gain / loc_db_gain;
 | |
|             }
 | |
| 
 | |
|           } else if (((loc_db_gain < 0.0f) && (slopeIsNegative == 1)) ||
 | |
|                      ((loc_db_gain > 0.0f) && (slopeIsNegative == 0))) {
 | |
|             if (pstr_gain_modifiers
 | |
|                     ->target_characteristic_right_present[drc_band] == 1) {
 | |
|               split_drc_characteristic_source =
 | |
|                   interp_params_str->split_source_characteristic_right;
 | |
|               err = impd_map_gain(
 | |
|                   split_drc_characteristic_source,
 | |
|                   interp_params_str->split_target_characteristic_right,
 | |
|                   loc_db_gain, &mapped_db_gain);
 | |
|               if (err) return (err);
 | |
|               gain_ratio = mapped_db_gain / loc_db_gain;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (loc_db_gain < 0.0f) {
 | |
|       gain_ratio *= interp_params_str->compress;
 | |
|     } else {
 | |
|       gain_ratio *= interp_params_str->boost;
 | |
|     }
 | |
|   }
 | |
|   if (pstr_gain_modifiers->gain_scaling_flag[drc_band] == 1) {
 | |
|     if (loc_db_gain < 0.0) {
 | |
|       gain_ratio *= pstr_gain_modifiers->attn_scaling[drc_band];
 | |
|     } else {
 | |
|       gain_ratio *= pstr_gain_modifiers->ampl_scaling[drc_band];
 | |
|     }
 | |
|   }
 | |
|   if ((interp_params_str->pstr_ducking_modifiers->ducking_scaling_flag == 1) &&
 | |
|       (interp_params_str->ducking_flag == 1)) {
 | |
|     gain_ratio *= interp_params_str->pstr_ducking_modifiers->ducking_scaling;
 | |
|   }
 | |
| 
 | |
|   if (interp_params_str->interpolation_loud_eq == 1) {
 | |
|     *out_param_lin_gain =
 | |
|         gain_ratio * loc_db_gain + pstr_gain_modifiers->gain_offset[drc_band];
 | |
|     *out_param_lin_slope = 0.0f;
 | |
|   } else {
 | |
|     *out_param_lin_gain =
 | |
|         (FLOAT32)pow(2.0, (FLOAT64)(gain_ratio * loc_db_gain / 6.0f));
 | |
|     *out_param_lin_slope = SLOPE_FACTOR_DB_TO_LINEAR * gain_ratio *
 | |
|                            *out_param_lin_gain * in_param_db_slope;
 | |
| 
 | |
|     if (pstr_gain_modifiers->gain_offset_flag[drc_band] == 1) {
 | |
|       *out_param_lin_gain *= (FLOAT32)pow(
 | |
|           2.0, (FLOAT64)(pstr_gain_modifiers->gain_offset[drc_band] / 6.0f));
 | |
|     }
 | |
|     if ((interp_params_str->limiter_peak_target_present == 1) &&
 | |
|         (interp_params_str->clipping_flag == 1)) {
 | |
|       *out_param_lin_gain *= (FLOAT32)pow(
 | |
|           2.0, max(0.0, -interp_params_str->limiter_peak_target -
 | |
|                             interp_params_str->loudness_normalization_gain_db) /
 | |
|                    6.0);
 | |
|       if (*out_param_lin_gain >= 1.0) {
 | |
|         *out_param_lin_gain = 1.0;
 | |
|         *out_param_lin_slope = 0.0;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| WORD32 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) {
 | |
|   WORD32 err = 0;
 | |
|   WORD32 n;
 | |
|   FLOAT32 k1, k2, a, b, c, d;
 | |
|   FLOAT32 slope_t1;
 | |
|   FLOAT32 slope_t2;
 | |
|   FLOAT32 gain_t1;
 | |
|   FLOAT32 gain_t2;
 | |
| 
 | |
|   WORD32 cubic_interpolation = 1;
 | |
|   WORD32 node_inser;
 | |
|   FLOAT32 node_inser_float;
 | |
| 
 | |
|   if (gain_step_tdomain <= 0) {
 | |
|     return (UNEXPECTED_ERROR);
 | |
|   }
 | |
| 
 | |
|   err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain0, slope0,
 | |
|                                    &gain_t1, &slope_t1);
 | |
|   if (err) return (err);
 | |
|   err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain1, slope1,
 | |
|                                    &gain_t2, &slope_t2);
 | |
|   if (err) return (err);
 | |
| 
 | |
|   if (interp_params_str->gain_interpolation_type ==
 | |
|       GAIN_INTERPOLATION_TYPE_SPLINE) {
 | |
|     slope_t1 = slope_t1 / (FLOAT32)interp_params_str->delta_tmin;
 | |
|     slope_t2 = slope_t2 / (FLOAT32)interp_params_str->delta_tmin;
 | |
|     if ((FLOAT32)fabs((FLOAT64)slope_t1) > (FLOAT32)fabs((FLOAT64)slope_t2)) {
 | |
|       node_inser_float = 2.0f *
 | |
|                          (gain_t2 - gain_t1 - slope_t2 * gain_step_tdomain) /
 | |
|                          (slope_t1 - slope_t2);
 | |
|       node_inser = (WORD32)(0.5f + node_inser_float);
 | |
|       if ((node_inser >= 0) && (node_inser < gain_step_tdomain)) {
 | |
|         cubic_interpolation = 0;
 | |
| 
 | |
|         result[0] = gain_t1;
 | |
|         result[gain_step_tdomain] = gain_t2;
 | |
| 
 | |
|         a = 0.5f * (slope_t2 - slope_t1) / node_inser_float;
 | |
|         b = slope_t1;
 | |
|         c = gain_t1;
 | |
|         for (n = 1; n < node_inser; n++) {
 | |
|           FLOAT32 t = (FLOAT32)n;
 | |
|           result[n] = (a * t + b) * t + c;
 | |
|           result[n] = max(0.0f, result[n]);
 | |
|         }
 | |
|         a = slope_t2;
 | |
|         b = gain_t2;
 | |
|         for (; n < gain_step_tdomain; n++) {
 | |
|           FLOAT32 t = (FLOAT32)(n - gain_step_tdomain);
 | |
|           result[n] = a * t + b;
 | |
|         }
 | |
|       }
 | |
|     } else if ((FLOAT32)fabs((FLOAT64)slope_t1) <
 | |
|                (FLOAT32)fabs((FLOAT64)slope_t2)) {
 | |
|       node_inser_float = 2.0f *
 | |
|                          (gain_t1 - gain_t2 + slope_t1 * gain_step_tdomain) /
 | |
|                          (slope_t1 - slope_t2);
 | |
|       node_inser_float = gain_step_tdomain - node_inser_float;
 | |
|       node_inser = (WORD32)(0.5f + node_inser_float);
 | |
|       if ((node_inser >= 0) && (node_inser < gain_step_tdomain)) {
 | |
|         cubic_interpolation = 0;
 | |
| 
 | |
|         result[0] = gain_t1;
 | |
|         result[gain_step_tdomain] = gain_t2;
 | |
| 
 | |
|         a = slope_t1;
 | |
|         b = gain_t1;
 | |
|         for (n = 1; n < node_inser; n++) {
 | |
|           FLOAT32 t = (FLOAT32)n;
 | |
|           result[n] = a * t + b;
 | |
|         }
 | |
|         a = (slope_t2 - slope_t1) /
 | |
|             (2.0f * (gain_step_tdomain - node_inser_float));
 | |
|         b = -slope_t2;
 | |
|         c = gain_t2;
 | |
|         for (; n < gain_step_tdomain; n++) {
 | |
|           FLOAT32 t = (FLOAT32)(gain_step_tdomain - n);
 | |
|           result[n] = (a * t + b) * t + c;
 | |
|           result[n] = max(0.0f, result[n]);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (cubic_interpolation == 1) {
 | |
|       FLOAT32 gain_step_inv = 1.0f / (FLOAT32)gain_step_tdomain;
 | |
|       FLOAT32 gain_step_inv2 = gain_step_inv * gain_step_inv;
 | |
| 
 | |
|       k1 = (gain_t2 - gain_t1) * gain_step_inv2;
 | |
|       k2 = slope_t2 + slope_t1;
 | |
| 
 | |
|       a = gain_step_inv * (gain_step_inv * k2 - 2.0f * k1);
 | |
|       b = 3.0f * k1 - gain_step_inv * (k2 + slope_t1);
 | |
|       c = slope_t1;
 | |
|       d = gain_t1;
 | |
| 
 | |
|       result[0] = gain_t1;
 | |
|       result[gain_step_tdomain] = gain_t2;
 | |
|       for (n = 1; n < gain_step_tdomain; n++) {
 | |
|         FLOAT32 t = (FLOAT32)n;
 | |
|         result[n] = (((a * t + b) * t + c) * t) + d;
 | |
|         result[n] = max(0.0f, result[n]);
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     a = (gain_t2 - gain_t1) / (FLOAT32)gain_step_tdomain;
 | |
|     b = gain_t1;
 | |
|     result[0] = gain_t1;
 | |
|     result[gain_step_tdomain] = gain_t2;
 | |
|     for (n = 1; n < gain_step_tdomain; n++) {
 | |
|       FLOAT32 t = (FLOAT32)n;
 | |
|       result[n] = a * t + b;
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| VOID impd_advance_buf(WORD32 drc_frame_size,
 | |
|                       ia_gain_buffer_struct* pstr_gain_buf) {
 | |
|   WORD32 n;
 | |
|   ia_interp_buf_struct* buf_interpolation;
 | |
| 
 | |
|   for (n = 0; n < pstr_gain_buf->buf_interpolation_count; n++) {
 | |
|     buf_interpolation = &(pstr_gain_buf->buf_interpolation[n]);
 | |
|     buf_interpolation->prev_node = buf_interpolation->str_node;
 | |
|     buf_interpolation->prev_node.time -= drc_frame_size;
 | |
|     memmove(buf_interpolation->lpcm_gains,
 | |
|             buf_interpolation->lpcm_gains + drc_frame_size,
 | |
|             sizeof(FLOAT32) * (drc_frame_size + MAX_SIGNAL_DELAY));
 | |
|   }
 | |
|   return;
 | |
| }
 | |
| WORD32
 | |
| impd_concatenate_segments(WORD32 drc_frame_size, WORD32 drc_band,
 | |
|                           ia_interp_params_struct* interp_params_str,
 | |
|                           ia_spline_nodes_struct* str_spline_nodes,
 | |
|                           ia_interp_buf_struct* buf_interpolation) {
 | |
|   WORD32 timePrev, duration, n, err = 0;
 | |
|   FLOAT32 loc_db_gain = 0.0f, prev_db_gain, slope = 0.0f, slopePrev;
 | |
| 
 | |
|   timePrev = buf_interpolation->prev_node.time;
 | |
|   prev_db_gain = buf_interpolation->prev_node.loc_db_gain;
 | |
|   slopePrev = buf_interpolation->prev_node.slope;
 | |
|   for (n = 0; n < str_spline_nodes->num_nodes; n++) {
 | |
|     duration = str_spline_nodes->str_node[n].time - timePrev;
 | |
|     loc_db_gain = str_spline_nodes->str_node[n].loc_db_gain;
 | |
|     slope = str_spline_nodes->str_node[n].slope;
 | |
| 
 | |
|     err = impd_interpolate_drc_gain(
 | |
|         interp_params_str, drc_band, duration, prev_db_gain, loc_db_gain,
 | |
|         slopePrev, slope, buf_interpolation->lpcm_gains + MAX_SIGNAL_DELAY +
 | |
|                               drc_frame_size + timePrev);
 | |
|     if (err) return (err);
 | |
| 
 | |
|     timePrev = str_spline_nodes->str_node[n].time;
 | |
|     prev_db_gain = loc_db_gain;
 | |
|     slopePrev = slope;
 | |
|   }
 | |
| 
 | |
|   buf_interpolation->str_node.loc_db_gain = loc_db_gain;
 | |
|   buf_interpolation->str_node.slope = slope;
 | |
|   buf_interpolation->str_node.time = timePrev;
 | |
| 
 | |
|   return (0);
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   ia_drc_params_struct* ia_drc_params_struct =
 | |
|       &(p_drc_gain_dec_structs->ia_drc_params_struct);
 | |
|   WORD32 drc_instructions_index =
 | |
|       ia_drc_params_struct->sel_drc_array[sel_drc_index].drc_instructions_index;
 | |
|   if (drc_instructions_index >= 0) {
 | |
|     WORD32 b, g, gainElementIndex, err = 0;
 | |
|     WORD32 parametricDrcInstanceIndex = 0;
 | |
|     ia_interp_params_struct interp_params_str = {0};
 | |
| 
 | |
|     ia_drc_instructions_struct* str_drc_instruction_str =
 | |
|         &(pstr_drc_config->str_drc_instruction_str[drc_instructions_index]);
 | |
|     WORD32 drc_set_effect = str_drc_instruction_str->drc_set_effect;
 | |
|     WORD32 num_drc_ch_groups = str_drc_instruction_str->num_drc_ch_groups;
 | |
|     ia_uni_drc_coeffs_struct* str_p_loc_drc_coefficients_uni_drc = NULL;
 | |
|     WORD32 drc_coeff_idx =
 | |
|         ia_drc_params_struct->sel_drc_array[sel_drc_index].drc_coeff_idx;
 | |
|     if (drc_coeff_idx >= 0) {
 | |
|       str_p_loc_drc_coefficients_uni_drc =
 | |
|           &(pstr_drc_config->str_p_loc_drc_coefficients_uni_drc[drc_coeff_idx]);
 | |
|       interp_params_str.interpolation_loud_eq = 0;
 | |
|     } else {
 | |
|       return (UNEXPECTED_ERROR);
 | |
|     }
 | |
| 
 | |
|     interp_params_str.loudness_normalization_gain_db =
 | |
|         loudness_normalization_gain_db;
 | |
|     interp_params_str.characteristic_index = characteristic_index;
 | |
|     interp_params_str.compress = compress;
 | |
|     interp_params_str.boost = boost;
 | |
|     interp_params_str.limiter_peak_target_present =
 | |
|         str_drc_instruction_str->limiter_peak_target_present;
 | |
|     interp_params_str.limiter_peak_target =
 | |
|         str_drc_instruction_str->limiter_peak_target;
 | |
| 
 | |
|     if (((drc_set_effect & (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) ==
 | |
|          0) &&
 | |
|         (drc_set_effect != EFFECT_BIT_FADE) &&
 | |
|         (drc_set_effect != EFFECT_BIT_CLIPPING)) {
 | |
|       interp_params_str.gain_modification_flag = 1;
 | |
|     } else {
 | |
|       interp_params_str.gain_modification_flag = 0;
 | |
|     }
 | |
|     if (drc_set_effect & (EFFECT_BIT_DUCK_OTHER | EFFECT_BIT_DUCK_SELF)) {
 | |
|       interp_params_str.ducking_flag = 1;
 | |
|     } else {
 | |
|       interp_params_str.ducking_flag = 0;
 | |
|     }
 | |
|     if (drc_set_effect == EFFECT_BIT_CLIPPING) {
 | |
|       interp_params_str.clipping_flag = 1;
 | |
|     } else {
 | |
|       interp_params_str.clipping_flag = 0;
 | |
|     }
 | |
| 
 | |
|     impd_advance_buf(ia_drc_params_struct->drc_frame_size,
 | |
|                      &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]));
 | |
| 
 | |
|     gainElementIndex = 0;
 | |
|     for (g = 0; g < num_drc_ch_groups; g++) {
 | |
|       WORD32 gainSet = 0;
 | |
|       WORD32 num_drc_bands = 0;
 | |
|       interp_params_str.gain_interpolation_type =
 | |
|           str_drc_instruction_str->gain_interpolation_type_for_channel_group[g];
 | |
|       interp_params_str.delta_tmin =
 | |
|           str_drc_instruction_str->time_delta_min_for_channel_group[g];
 | |
|       interp_params_str.pstr_ducking_modifiers = &(
 | |
|           str_drc_instruction_str->str_ducking_modifiers_for_channel_group[g]);
 | |
|       interp_params_str.pstr_gain_modifiers =
 | |
|           &(str_drc_instruction_str->str_gain_modifiers_of_ch_group[g]);
 | |
|       if (str_drc_instruction_str->ch_group_parametric_drc_flag[g] == 0) {
 | |
|         gainSet = str_drc_instruction_str->gain_set_index_for_channel_group[g];
 | |
|         num_drc_bands = str_drc_instruction_str->band_count_of_ch_group[g];
 | |
|         for (b = 0; b < num_drc_bands; b++) {
 | |
|           ia_gain_params_struct* gain_params =
 | |
|               &(str_p_loc_drc_coefficients_uni_drc->gain_set_params[gainSet]
 | |
|                     .gain_params[b]);
 | |
|           WORD32 seq = gain_params->gain_seq_idx;
 | |
|           interp_params_str.drc_characteristic_present =
 | |
|               gain_params->drc_characteristic_present;
 | |
|           interp_params_str.drc_source_characteristic_cicp_format =
 | |
|               gain_params->drc_characteristic_format_is_cicp;
 | |
|           interp_params_str.source_drc_characteristic =
 | |
|               gain_params->drc_characteristic;
 | |
|           interp_params_str.split_source_characteristic_left = &(
 | |
|               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_left
 | |
|                   [gain_params->drc_characteristic_left_index]);
 | |
|           interp_params_str.split_source_characteristic_right = &(
 | |
|               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_right
 | |
|                   [gain_params->drc_characteristic_right_index]);
 | |
|           interp_params_str.split_target_characteristic_left = &(
 | |
|               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_left
 | |
|                   [interp_params_str.pstr_gain_modifiers
 | |
|                        ->target_characteristic_left_index[b]]);
 | |
|           interp_params_str.split_target_characteristic_right = &(
 | |
|               str_p_loc_drc_coefficients_uni_drc->str_split_characteristic_right
 | |
|                   [interp_params_str.pstr_gain_modifiers
 | |
|                        ->target_characteristic_right_index[b]]);
 | |
|           err = impd_concatenate_segments(
 | |
|               ia_drc_params_struct->drc_frame_size, b, &interp_params_str,
 | |
|               &(pstr_drc_gain->drc_gain_sequence[seq].str_spline_nodes[0]),
 | |
|               &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
 | |
|                     .buf_interpolation[gainElementIndex]));
 | |
|           if (err) return (err);
 | |
|           gainElementIndex++;
 | |
|         }
 | |
|       } else {
 | |
|         if (ia_drc_params_struct->sub_band_domain_mode ==
 | |
|                 SUBBAND_DOMAIN_MODE_OFF &&
 | |
|             !(p_drc_gain_dec_structs->parametricdrc_params
 | |
|                   .str_parametric_drc_instance_params
 | |
|                       [parametricDrcInstanceIndex]
 | |
|                   .parametric_drc_type == PARAM_DRC_TYPE_LIM)) {
 | |
|           err = impd_parametric_drc_instance_process(
 | |
|               p_drc_gain_dec_structs->audio_in_out_buf.audio_in_out_buf, NULL,
 | |
|               NULL, &p_drc_gain_dec_structs->parametricdrc_params,
 | |
|               &p_drc_gain_dec_structs->parametricdrc_params
 | |
|                    .str_parametric_drc_instance_params
 | |
|                        [parametricDrcInstanceIndex]);
 | |
|           if (err) return (err);
 | |
| 
 | |
|           err = impd_concatenate_segments(
 | |
|               ia_drc_params_struct->drc_frame_size, 0, &interp_params_str,
 | |
|               &p_drc_gain_dec_structs->parametricdrc_params
 | |
|                    .str_parametric_drc_instance_params
 | |
|                        [parametricDrcInstanceIndex]
 | |
|                    .str_spline_nodes,
 | |
|               &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
 | |
|                     .buf_interpolation[gainElementIndex]));
 | |
|           if (err) return (err);
 | |
|         } else if (ia_drc_params_struct->sub_band_domain_mode ==
 | |
|                        SUBBAND_DOMAIN_MODE_OFF &&
 | |
|                    p_drc_gain_dec_structs->parametricdrc_params
 | |
|                            .str_parametric_drc_instance_params
 | |
|                                [parametricDrcInstanceIndex]
 | |
|                            .parametric_drc_type == PARAM_DRC_TYPE_LIM) {
 | |
|           FLOAT32* lpcm_gains = (drc_gain_buffers->pstr_gain_buf[sel_drc_index]
 | |
|                                      .buf_interpolation[gainElementIndex])
 | |
|                                     .lpcm_gains +
 | |
|                                 MAX_SIGNAL_DELAY;
 | |
|           impd_parametric_lim_type_drc_process(
 | |
|               p_drc_gain_dec_structs->audio_in_out_buf.audio_in_out_buf,
 | |
|               loudness_normalization_gain_db,
 | |
|               &p_drc_gain_dec_structs->parametricdrc_params
 | |
|                    .str_parametric_drc_instance_params
 | |
|                        [parametricDrcInstanceIndex]
 | |
|                    .str_parametric_drc_type_lim_params,
 | |
|               lpcm_gains);
 | |
| 
 | |
|         } else if (ia_drc_params_struct->sub_band_domain_mode !=
 | |
|                        SUBBAND_DOMAIN_MODE_OFF &&
 | |
|                    !(p_drc_gain_dec_structs->parametricdrc_params
 | |
|                          .str_parametric_drc_instance_params
 | |
|                              [parametricDrcInstanceIndex]
 | |
|                          .parametric_drc_type == PARAM_DRC_TYPE_LIM)) {
 | |
|           err = impd_parametric_drc_instance_process(
 | |
|               NULL, p_drc_gain_dec_structs->audio_in_out_buf.audio_real_buff,
 | |
|               p_drc_gain_dec_structs->audio_in_out_buf.audio_imag_buff,
 | |
|               &p_drc_gain_dec_structs->parametricdrc_params,
 | |
|               &p_drc_gain_dec_structs->parametricdrc_params
 | |
|                    .str_parametric_drc_instance_params
 | |
|                        [parametricDrcInstanceIndex]);
 | |
|           if (err) return (err);
 | |
| 
 | |
|           err = impd_concatenate_segments(
 | |
|               ia_drc_params_struct->drc_frame_size, 0, &interp_params_str,
 | |
|               &p_drc_gain_dec_structs->parametricdrc_params
 | |
|                    .str_parametric_drc_instance_params
 | |
|                        [parametricDrcInstanceIndex]
 | |
|                    .str_spline_nodes,
 | |
|               &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]
 | |
|                     .buf_interpolation[gainElementIndex]));
 | |
|           if (err) return (err);
 | |
| 
 | |
|         } else {
 | |
|           return (UNEXPECTED_ERROR);
 | |
|         }
 | |
|         gainElementIndex++;
 | |
|         parametricDrcInstanceIndex++;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return (0);
 | |
| }
 |