Bug: 80133175 Test: CTS android.metia.cts.DecoderTestXheAac Change-Id: Ic1962238eabe4ad98e4fa0ea85acc5494e762d30
757 lines
32 KiB
C
757 lines
32 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 ia_cicp_sigmoid_characteristic_param_struct pstr_cicp_sigmoid_characteristic_param[];
|
|
|
|
WORD32 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 (0);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
WORD32
|
|
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 (0);
|
|
}
|
|
|
|
|
|
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:
|
|
err = impd_compressor_io_nodes_inverse(split_drc_characteristic_source, gain_in_db, &inLevel);
|
|
if (err) return (err);
|
|
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);
|
|
}
|
|
|
|
if (interp_params_str->gain_interpolation_type == GAIN_INTERPOLATION_TYPE_SPLINE) {
|
|
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);
|
|
|
|
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{
|
|
|
|
err = impd_conv_to_linear_domain(interp_params_str, drc_band, gain1, slope1, &gain_t2, &slope_t2);
|
|
if (err)
|
|
return (err);
|
|
|
|
a = 0;
|
|
b = gain_t2;
|
|
|
|
result[0] = gain_t2;
|
|
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;
|
|
}
|
|
|
|
WORD32
|
|
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(0);
|
|
}
|
|
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;
|
|
}
|
|
|
|
err = impd_advance_buf(ia_drc_params_struct->drc_frame_size, &(drc_gain_buffers->pstr_gain_buf[sel_drc_index]));
|
|
if (err) return (err);
|
|
|
|
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;
|
|
err = 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);
|
|
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)) {
|
|
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);
|
|
}
|
|
|