| /****************************************************************************** |
| * |
| * 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_parametric_drc_dec.h" |
| #include "impd_drc_filter_bank.h" |
| #include "impd_drc_multi_band.h" |
| #include "impd_drc_gain_dec.h" |
| #include "impd_drc_process_audio.h" |
| #include "impd_drc_interface.h" |
| #include "impd_drc_gain_dec.h" |
| #include "impd_drc_eq.h" |
| #include "impd_drc_gain_decoder.h" |
| #include "impd_drc_rom.h" |
| |
| WORD32 impd_shape_filt_block_adapt(const FLOAT32 drc_gain, |
| shape_filter_block* shape_filter_block) { |
| // WORD32 err = 0; |
| WORD32 i; |
| FLOAT32 warpedGain, x1, y1; |
| shape_filter_block->drc_gain_last = drc_gain; |
| for (i = 0; i < 4; i++) { |
| if (shape_filter_block->shape_filter[i].type == SHAPE_FILTER_TYPE_OFF) |
| continue; |
| else if (shape_filter_block->shape_filter[i].type == |
| SHAPE_FILTER_TYPE_LF_CUT || |
| shape_filter_block->shape_filter[i].type == |
| SHAPE_FILTER_TYPE_HF_CUT) { |
| if (drc_gain < 1.0f) |
| warpedGain = -1.0f; |
| else |
| warpedGain = |
| (drc_gain - 1.0f) / |
| (drc_gain - 1.0f + shape_filter_block->shape_filter[i].gain_offset); |
| x1 = shape_filter_block->shape_filter[i].a1; |
| } else if (shape_filter_block->shape_filter[i].type == |
| SHAPE_FILTER_TYPE_LF_BOOST || |
| shape_filter_block->shape_filter[i].type == |
| SHAPE_FILTER_TYPE_HF_BOOST) { |
| if (drc_gain >= 1.0f) |
| warpedGain = -1.0f; |
| else |
| warpedGain = |
| (1.0f - drc_gain) / |
| (1.0f + |
| drc_gain * |
| (shape_filter_block->shape_filter[i].gain_offset - 1.0f)); |
| x1 = shape_filter_block->shape_filter[i].b1; |
| } |
| |
| if (warpedGain <= 0.0f) { |
| y1 = x1; |
| } else if (warpedGain < |
| shape_filter_block->shape_filter[i].warped_gain_max) { |
| y1 = x1 + shape_filter_block->shape_filter[i].factor * warpedGain; |
| } else { |
| y1 = shape_filter_block->shape_filter[i].y1_bound; |
| } |
| if (shape_filter_block->shape_filter[i].type == SHAPE_FILTER_TYPE_LF_CUT) { |
| shape_filter_block->shape_filter[i].b1 = y1; |
| } else if (shape_filter_block->shape_filter[i].type == |
| SHAPE_FILTER_TYPE_HF_CUT) { |
| shape_filter_block->shape_filter[i].g_norm = |
| shape_filter_block->shape_filter[i].coeff_sum / |
| (shape_filter_block->shape_filter[i].partial_coeff_sum + y1); |
| shape_filter_block->shape_filter[i].b1 = y1; |
| } else if (shape_filter_block->shape_filter[i].type == |
| SHAPE_FILTER_TYPE_HF_BOOST) { |
| shape_filter_block->shape_filter[i].g_norm = |
| (shape_filter_block->shape_filter[i].partial_coeff_sum + y1) / |
| shape_filter_block->shape_filter[i].coeff_sum; |
| shape_filter_block->shape_filter[i].a1 = y1; |
| } else if (shape_filter_block->shape_filter[i].type == |
| SHAPE_FILTER_TYPE_LF_BOOST) { |
| shape_filter_block->shape_filter[i].a1 = y1; |
| } |
| } |
| return (0); |
| } |
| |
| WORD32 resetshape_flter_block(shape_filter_block* shape_filter_block) { |
| WORD32 i, c; |
| shape_filter_block->drc_gain_last = -1.0f; |
| impd_shape_filt_block_adapt(1.0f, shape_filter_block); |
| for (i = 0; i < 4; i++) { |
| for (c = 0; c < MAX_CHANNEL_COUNT; c++) { |
| shape_filter_block->shape_filter[i].audio_in_state_1[c] = 0.0f; |
| shape_filter_block->shape_filter[i].audio_in_state_2[c] = 0.0f; |
| shape_filter_block->shape_filter[i].audio_out_state_1[c] = 0.0f; |
| shape_filter_block->shape_filter[i].audio_out_state_2[c] = 0.0f; |
| } |
| } |
| return (0); |
| } |
| |
| WORD32 impd_shape_filt_block_init( |
| ia_shape_filter_block_params_struct* shape_flter_block_params, |
| shape_filter_block* shape_filter_block) { |
| // WORD32 err = 0; |
| FLOAT32 x1; |
| FLOAT32 x2 = 0.0f; |
| FLOAT32 radius; |
| if (shape_flter_block_params->lf_cut_filter_present) { |
| ia_shape_filter_params_struct* params = |
| &shape_flter_block_params->str_lf_cut_params; |
| shape_filter_block->shape_filter[0].type = SHAPE_FILTER_TYPE_LF_CUT; |
| shape_filter_block->shape_filter[0].gain_offset = |
| shape_filt_lf_gain_offset_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| shape_filter_block->shape_filter[0].y1_bound = |
| shape_filt_lf_y1_bound_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| x1 = -shape_filt_lf_radius_tbl[params->corner_freq_index]; |
| shape_filter_block->shape_filter[0].warped_gain_max = |
| SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE / |
| (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE + |
| shape_filter_block->shape_filter[0].gain_offset); |
| shape_filter_block->shape_filter[0].factor = |
| (shape_filter_block->shape_filter[0].y1_bound - x1) / |
| shape_filter_block->shape_filter[0].warped_gain_max; |
| shape_filter_block->shape_filter[0].a1 = x1; |
| |
| } else { |
| shape_filter_block->shape_filter[0].type = SHAPE_FILTER_TYPE_OFF; |
| } |
| if (shape_flter_block_params->lf_boost_filter_present) { |
| ia_shape_filter_params_struct* params = |
| &shape_flter_block_params->str_lf_boost_params; |
| shape_filter_block->shape_filter[1].type = SHAPE_FILTER_TYPE_LF_BOOST; |
| shape_filter_block->shape_filter[1].gain_offset = |
| shape_filt_lf_gain_offset_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| shape_filter_block->shape_filter[1].y1_bound = |
| shape_filt_lf_y1_bound_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| x1 = -shape_filt_lf_radius_tbl[params->corner_freq_index]; |
| shape_filter_block->shape_filter[1].warped_gain_max = |
| SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE / |
| (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE + |
| shape_filter_block->shape_filter[1].gain_offset); |
| shape_filter_block->shape_filter[1].factor = |
| (shape_filter_block->shape_filter[1].y1_bound - x1) / |
| shape_filter_block->shape_filter[1].warped_gain_max; |
| shape_filter_block->shape_filter[1].b1 = x1; |
| |
| } else { |
| shape_filter_block->shape_filter[1].type = SHAPE_FILTER_TYPE_OFF; |
| } |
| if (shape_flter_block_params->hf_cut_filter_present) { |
| ia_shape_filter_params_struct* params = |
| &shape_flter_block_params->str_hfCutParams; |
| shape_filter_block->shape_filter[2].type = SHAPE_FILTER_TYPE_HF_CUT; |
| shape_filter_block->shape_filter[2].gain_offset = |
| shape_filt_hf_gain_offset_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| shape_filter_block->shape_filter[2].y1_bound = |
| shape_filt_hf_y1_bound_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| radius = shape_filt_hf_radius_tbl[params->corner_freq_index]; |
| x1 = (FLOAT32)( |
| -2.0f * radius * |
| cos(2.0f * M_PI * |
| shape_filt_cutoff_freq_norm_hf_tbl[params->corner_freq_index])); |
| x2 = radius * radius; |
| shape_filter_block->shape_filter[2].warped_gain_max = |
| SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE / |
| (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE + |
| shape_filter_block->shape_filter[2].gain_offset); |
| shape_filter_block->shape_filter[2].factor = |
| (shape_filter_block->shape_filter[2].y1_bound - x1) / |
| shape_filter_block->shape_filter[2].warped_gain_max; |
| shape_filter_block->shape_filter[2].coeff_sum = 1.0f + x1 + x2; |
| shape_filter_block->shape_filter[2].partial_coeff_sum = 1.0f + x2; |
| shape_filter_block->shape_filter[2].a1 = x1; |
| shape_filter_block->shape_filter[2].a2 = x2; |
| shape_filter_block->shape_filter[2].b2 = x2; |
| } else { |
| shape_filter_block->shape_filter[2].type = SHAPE_FILTER_TYPE_OFF; |
| } |
| if (shape_flter_block_params->hf_boost_filter_present) { |
| ia_shape_filter_params_struct* params = |
| &shape_flter_block_params->str_hf_boost_params; |
| shape_filter_block->shape_filter[3].type = SHAPE_FILTER_TYPE_HF_BOOST; |
| shape_filter_block->shape_filter[3].gain_offset = |
| shape_filt_hf_gain_offset_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| shape_filter_block->shape_filter[3].y1_bound = |
| shape_filt_hf_y1_bound_tbl[params->corner_freq_index] |
| [params->filter_strength_index]; |
| radius = shape_filt_hf_radius_tbl[params->corner_freq_index]; |
| x1 = (FLOAT32)( |
| -2.0f * radius * |
| cos(2.0f * M_PI * |
| shape_filt_cutoff_freq_norm_hf_tbl[params->corner_freq_index])); |
| x2 = radius * radius; |
| shape_filter_block->shape_filter[3].warped_gain_max = |
| SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE / |
| (SHAPE_FILTER_DRC_GAIN_MAX_MINUS_ONE + |
| shape_filter_block->shape_filter[3].gain_offset); |
| shape_filter_block->shape_filter[3].factor = |
| (shape_filter_block->shape_filter[3].y1_bound - x1) / |
| shape_filter_block->shape_filter[3].warped_gain_max; |
| shape_filter_block->shape_filter[3].coeff_sum = 1.0f + x1 + x2; |
| shape_filter_block->shape_filter[3].partial_coeff_sum = 1.0f + x2; |
| shape_filter_block->shape_filter[3].b1 = x1; |
| shape_filter_block->shape_filter[3].b2 = x2; |
| shape_filter_block->shape_filter[3].a2 = x2; |
| |
| } else { |
| shape_filter_block->shape_filter[3].type = SHAPE_FILTER_TYPE_OFF; |
| } |
| resetshape_flter_block(shape_filter_block); |
| shape_filter_block->shape_flter_block_flag = 1; |
| return (0); |
| } |
| |
| WORD32 impd_shape_filt_block_time_process( |
| shape_filter_block* shape_filter_block, FLOAT32* drc_gain, |
| const WORD32 channel, FLOAT32* audio_in, WORD32 start, WORD32 end) { |
| WORD32 i, j, err = 0; |
| FLOAT32 audio_out; |
| |
| if (shape_filter_block->shape_flter_block_flag) { |
| for (i = start; i < end; i++) { |
| FLOAT32 tmp = audio_in[i]; |
| for (j = 0; j < 4; j++) { |
| if (shape_filter_block->shape_filter[j].type == |
| SHAPE_FILTER_TYPE_LF_CUT || |
| shape_filter_block->shape_filter[j].type == |
| SHAPE_FILTER_TYPE_LF_BOOST) { |
| audio_out = tmp + |
| shape_filter_block->shape_filter[j].b1 * |
| shape_filter_block->shape_filter[j] |
| .audio_in_state_1[channel] - |
| shape_filter_block->shape_filter[j].a1 * |
| shape_filter_block->shape_filter[j] |
| .audio_out_state_1[channel]; |
| shape_filter_block->shape_filter[j].audio_in_state_1[channel] = tmp; |
| shape_filter_block->shape_filter[j].audio_out_state_1[channel] = |
| audio_out; |
| |
| } else if (shape_filter_block->shape_filter[j].type == |
| SHAPE_FILTER_TYPE_HF_CUT || |
| shape_filter_block->shape_filter[j].type == |
| SHAPE_FILTER_TYPE_HF_BOOST) { |
| audio_out = shape_filter_block->shape_filter[j].g_norm * tmp + |
| shape_filter_block->shape_filter[j].b1 * |
| shape_filter_block->shape_filter[j] |
| .audio_in_state_1[channel] + |
| shape_filter_block->shape_filter[j].b2 * |
| shape_filter_block->shape_filter[j] |
| .audio_in_state_2[channel] - |
| shape_filter_block->shape_filter[j].a1 * |
| shape_filter_block->shape_filter[j] |
| .audio_out_state_1[channel] - |
| shape_filter_block->shape_filter[j].a2 * |
| shape_filter_block->shape_filter[j] |
| .audio_out_state_2[channel]; |
| shape_filter_block->shape_filter[j].audio_in_state_2[channel] = |
| shape_filter_block->shape_filter[j].audio_in_state_1[channel]; |
| shape_filter_block->shape_filter[j].audio_in_state_1[channel] = |
| shape_filter_block->shape_filter[j].g_norm * tmp; |
| shape_filter_block->shape_filter[j].audio_out_state_2[channel] = |
| shape_filter_block->shape_filter[j].audio_out_state_1[channel]; |
| shape_filter_block->shape_filter[j].audio_out_state_1[channel] = |
| audio_out; |
| } else { |
| audio_out = tmp; |
| } |
| tmp = audio_out; |
| } |
| |
| audio_in[i] = audio_out * drc_gain[i]; |
| } |
| |
| } else { |
| for (i = start; i < end; i++) { |
| audio_in[i] = audio_in[i] * drc_gain[i]; |
| } |
| } |
| |
| return err; |
| } |