/******************************************************************************
|
*
|
* 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_filter_bank.h"
|
#include "impd_drc_multi_band.h"
|
#include "impd_drc_gain_dec.h"
|
#include "impd_drc_process_audio.h"
|
|
WORD32 impd_apply_gains_and_add(
|
ia_drc_instructions_struct* pstr_drc_instruction_arr,
|
const WORD32 drc_instructions_index,
|
ia_drc_params_struct* ia_drc_params_struct,
|
ia_gain_buffer_struct* pstr_gain_buf,
|
shape_filter_block shape_filter_block[], FLOAT32* deinterleaved_audio[],
|
|
FLOAT32* channel_audio[], WORD32 impd_apply_gains) {
|
WORD32 c, b, g, i;
|
WORD32 offset = 0, signalIndex = 0;
|
WORD32 gainIndexForGroup[CHANNEL_GROUP_COUNT_MAX];
|
WORD32 signalIndexForChannel[MAX_CHANNEL_COUNT];
|
FLOAT32* lpcm_gains;
|
FLOAT32 sum;
|
FLOAT32 drc_gain_last, gainThr;
|
WORD32 iEnd, iStart;
|
ia_drc_instructions_struct* str_drc_instruction_str =
|
&(pstr_drc_instruction_arr[drc_instructions_index]);
|
|
if (drc_instructions_index >= 0) {
|
str_drc_instruction_str =
|
&(pstr_drc_instruction_arr[drc_instructions_index]);
|
{
|
if (str_drc_instruction_str->drc_set_id > 0) {
|
if (ia_drc_params_struct->delay_mode == DELAY_MODE_LOW_DELAY) {
|
offset = ia_drc_params_struct->drc_frame_size;
|
}
|
gainIndexForGroup[0] = 0;
|
for (g = 0; g < str_drc_instruction_str->num_drc_ch_groups - 1; g++) {
|
gainIndexForGroup[g + 1] =
|
gainIndexForGroup[g] +
|
str_drc_instruction_str->band_count_of_ch_group[g];
|
}
|
signalIndexForChannel[0] = 0;
|
for (c = 0; c < str_drc_instruction_str->audio_num_chan - 1; c++) {
|
if (str_drc_instruction_str->channel_group_of_ch[c] >= 0) {
|
signalIndexForChannel[c + 1] =
|
signalIndexForChannel[c] +
|
str_drc_instruction_str->band_count_of_ch_group
|
[str_drc_instruction_str->channel_group_of_ch[c]];
|
} else {
|
signalIndexForChannel[c + 1] = signalIndexForChannel[c] + 1;
|
}
|
}
|
|
for (g = 0; g < str_drc_instruction_str->num_drc_ch_groups; g++) {
|
for (b = 0; b < str_drc_instruction_str->band_count_of_ch_group[g];
|
b++) {
|
if (str_drc_instruction_str->ch_group_parametric_drc_flag[g] == 0) {
|
lpcm_gains =
|
pstr_gain_buf->buf_interpolation[gainIndexForGroup[g] + b]
|
.lpcm_gains +
|
MAX_SIGNAL_DELAY - ia_drc_params_struct->gain_delay_samples -
|
ia_drc_params_struct->audio_delay_samples + offset;
|
} else {
|
lpcm_gains =
|
pstr_gain_buf->buf_interpolation[gainIndexForGroup[g] + b]
|
.lpcm_gains +
|
MAX_SIGNAL_DELAY +
|
str_drc_instruction_str
|
->parametric_drc_look_ahead_samples[g] -
|
ia_drc_params_struct->audio_delay_samples;
|
}
|
iEnd = 0;
|
iStart = 0;
|
while (iEnd < ia_drc_params_struct->drc_frame_size) {
|
if (shape_filter_block[g].shape_flter_block_flag) {
|
drc_gain_last = shape_filter_block[g].drc_gain_last;
|
gainThr = 0.0001f * drc_gain_last;
|
while ((iEnd < ia_drc_params_struct->drc_frame_size) &&
|
(fabs(lpcm_gains[iEnd] - drc_gain_last) <= gainThr))
|
iEnd++;
|
} else {
|
iEnd = ia_drc_params_struct->drc_frame_size;
|
}
|
|
for (c = 0; c < str_drc_instruction_str->audio_num_chan; c++)
|
|
{
|
if (g == str_drc_instruction_str->channel_group_of_ch[c]) {
|
signalIndex = signalIndexForChannel[c] + b;
|
|
if (impd_apply_gains == 1) {
|
impd_shape_filt_block_time_process(
|
&shape_filter_block[g], &lpcm_gains[0], signalIndex,
|
&deinterleaved_audio[signalIndex][0], iStart, iEnd);
|
|
} else {
|
for (i = iStart; i < iEnd; i++) {
|
deinterleaved_audio[signalIndex][i] = lpcm_gains[i];
|
}
|
}
|
}
|
}
|
if ((iEnd < ia_drc_params_struct->drc_frame_size) &&
|
(shape_filter_block[g].shape_flter_block_flag)) {
|
impd_shape_filt_block_adapt(lpcm_gains[iEnd],
|
&shape_filter_block[g]);
|
}
|
iStart = iEnd;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
signalIndex = 0;
|
|
if (str_drc_instruction_str->drc_set_id > 0) {
|
for (c = 0; c < str_drc_instruction_str->audio_num_chan; c++)
|
|
{
|
g = str_drc_instruction_str->channel_group_of_ch[c];
|
if (g >= 0) {
|
for (i = 0; i < ia_drc_params_struct->drc_frame_size; i++) {
|
sum = 0.0f;
|
for (b = 0; b < str_drc_instruction_str->band_count_of_ch_group[g];
|
b++) {
|
sum += deinterleaved_audio[signalIndex + b][i];
|
}
|
|
channel_audio[c][i] = sum;
|
}
|
signalIndex += str_drc_instruction_str->band_count_of_ch_group[g];
|
} else {
|
for (i = 0; i < ia_drc_params_struct->drc_frame_size; i++) {
|
channel_audio[c][i] = deinterleaved_audio[signalIndex][i];
|
}
|
signalIndex++;
|
}
|
}
|
} else {
|
for (c = 0; c < str_drc_instruction_str->audio_num_chan; c++)
|
|
{
|
for (i = 0; i < ia_drc_params_struct->drc_frame_size; i++) {
|
channel_audio[c][i] = deinterleaved_audio[c][i];
|
}
|
}
|
}
|
|
return (0);
|
}
|
|
/* subband-domain DRC: in-place application of DRC gains to audio frame */
|
WORD32
|
impd_apply_gains_subband(ia_drc_instructions_struct* pstr_drc_instruction_arr,
|
const WORD32 drc_instructions_index,
|
ia_drc_params_struct* ia_drc_params_struct,
|
ia_gain_buffer_struct* pstr_gain_buf,
|
ia_overlap_params_struct* pstr_overlap_params,
|
FLOAT32* deinterleaved_audio_delayed_re[],
|
FLOAT32* deinterleaved_audio_delayed_im[],
|
FLOAT32* deinterleaved_audio_re[],
|
FLOAT32* deinterleaved_audio_im[]) {
|
WORD32 c, b, g, m, s;
|
WORD32 gainIndexForGroup[CHANNEL_GROUP_COUNT_MAX];
|
FLOAT32* lpcm_gains;
|
FLOAT32 gainSb, gainLr;
|
ia_drc_instructions_struct* str_drc_instruction_str;
|
WORD32 offset = 0, signalIndex = 0;
|
WORD32 drc_frame_sizeSb = 0;
|
WORD32 nDecoderSubbands = 0;
|
WORD32 L = 0; /* L: downsampling factor */
|
WORD32 analysisDelay = 0;
|
switch (ia_drc_params_struct->sub_band_domain_mode) {
|
case SUBBAND_DOMAIN_MODE_QMF64:
|
nDecoderSubbands = AUDIO_CODEC_SUBBAND_COUNT_QMF64;
|
L = AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR_QMF64;
|
analysisDelay = AUDIO_CODEC_SUBBAND_ANALYSE_DELAY_QMF64;
|
break;
|
case SUBBAND_DOMAIN_MODE_QMF71:
|
nDecoderSubbands = AUDIO_CODEC_SUBBAND_COUNT_QMF71;
|
L = AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR_QMF71;
|
analysisDelay = AUDIO_CODEC_SUBBAND_ANALYSE_DELAY_QMF71;
|
break;
|
case SUBBAND_DOMAIN_MODE_STFT256:
|
nDecoderSubbands = AUDIO_CODEC_SUBBAND_COUNT_STFT256;
|
L = AUDIO_CODEC_SUBBAND_DOWNSAMPLING_FACTOR_STFT256;
|
analysisDelay = AUDIO_CODEC_SUBBAND_ANALYSE_DELAY_STFT256;
|
break;
|
default:
|
return -1;
|
break;
|
}
|
drc_frame_sizeSb = ia_drc_params_struct->drc_frame_size / L;
|
|
if (drc_instructions_index >= 0) {
|
str_drc_instruction_str =
|
&(pstr_drc_instruction_arr[drc_instructions_index]);
|
{
|
if (str_drc_instruction_str->drc_set_id > 0) {
|
if (ia_drc_params_struct->delay_mode == DELAY_MODE_LOW_DELAY) {
|
offset = ia_drc_params_struct->drc_frame_size;
|
}
|
gainIndexForGroup[0] = 0;
|
for (g = 0; g < str_drc_instruction_str->num_drc_ch_groups - 1; g++) {
|
gainIndexForGroup[g + 1] =
|
gainIndexForGroup[g] +
|
str_drc_instruction_str
|
->band_count_of_ch_group[g]; /* index of first gain sequence
|
in channel group */
|
}
|
|
for (c = 0; c < str_drc_instruction_str->audio_num_chan; c++)
|
|
{
|
g = str_drc_instruction_str->channel_group_of_ch[c];
|
if (g >= 0) {
|
for (m = 0; m < drc_frame_sizeSb; m++) {
|
if (str_drc_instruction_str->band_count_of_ch_group[g] >
|
1) { /* multiband DRC */
|
for (s = 0; s < nDecoderSubbands; s++) {
|
gainSb = 0.0f;
|
for (b = 0;
|
b < str_drc_instruction_str->band_count_of_ch_group[g];
|
b++) {
|
if (str_drc_instruction_str
|
->ch_group_parametric_drc_flag[g] == 0) {
|
lpcm_gains =
|
pstr_gain_buf
|
->buf_interpolation[gainIndexForGroup[g] + b]
|
.lpcm_gains +
|
MAX_SIGNAL_DELAY -
|
ia_drc_params_struct->gain_delay_samples -
|
ia_drc_params_struct->audio_delay_samples + offset;
|
} else {
|
lpcm_gains =
|
pstr_gain_buf
|
->buf_interpolation[gainIndexForGroup[g] + b]
|
.lpcm_gains +
|
MAX_SIGNAL_DELAY +
|
str_drc_instruction_str
|
->parametric_drc_look_ahead_samples[g] -
|
ia_drc_params_struct->audio_delay_samples +
|
analysisDelay;
|
}
|
/* get gain for this timeslot by downsampling */
|
gainLr = lpcm_gains[(m * L + (L - 1) / 2)];
|
gainSb += pstr_overlap_params->str_group_overlap_params[g]
|
.str_band_overlap_params[b]
|
.overlap_weight[s] *
|
gainLr;
|
}
|
deinterleaved_audio_re[signalIndex][m * nDecoderSubbands +
|
s] =
|
gainSb *
|
deinterleaved_audio_delayed_re[signalIndex]
|
[m * nDecoderSubbands + s];
|
if (ia_drc_params_struct->sub_band_domain_mode ==
|
SUBBAND_DOMAIN_MODE_STFT256) { /* For STFT filterbank, the
|
real value of the
|
nyquist band is stored
|
at the imag value of the
|
first band */
|
if (s != 0)
|
deinterleaved_audio_im[signalIndex][m * nDecoderSubbands +
|
s] =
|
gainSb *
|
deinterleaved_audio_delayed_im[signalIndex]
|
[m * nDecoderSubbands +
|
s];
|
if (s == (nDecoderSubbands - 1))
|
deinterleaved_audio_im[signalIndex][m * nDecoderSubbands +
|
0] =
|
gainSb *
|
deinterleaved_audio_delayed_im[signalIndex]
|
[m * nDecoderSubbands +
|
0];
|
} else {
|
deinterleaved_audio_im[signalIndex][m * nDecoderSubbands +
|
s] =
|
gainSb *
|
deinterleaved_audio_delayed_im[signalIndex]
|
[m * nDecoderSubbands +
|
s];
|
}
|
}
|
} else { /* single-band DRC */
|
if (str_drc_instruction_str->ch_group_parametric_drc_flag[g] ==
|
0) {
|
lpcm_gains =
|
pstr_gain_buf->buf_interpolation[gainIndexForGroup[g]]
|
.lpcm_gains +
|
MAX_SIGNAL_DELAY -
|
ia_drc_params_struct->gain_delay_samples -
|
ia_drc_params_struct->audio_delay_samples + offset;
|
} else {
|
lpcm_gains =
|
pstr_gain_buf->buf_interpolation[gainIndexForGroup[g]]
|
.lpcm_gains +
|
MAX_SIGNAL_DELAY +
|
str_drc_instruction_str
|
->parametric_drc_look_ahead_samples[g] -
|
ia_drc_params_struct->audio_delay_samples + analysisDelay;
|
}
|
/* get gain for this timeslot by downsampling */
|
gainSb = lpcm_gains[(m * L + (L - 1) / 2)];
|
for (s = 0; s < nDecoderSubbands; s++) {
|
deinterleaved_audio_re[signalIndex][m * nDecoderSubbands +
|
s] =
|
gainSb *
|
deinterleaved_audio_delayed_re[signalIndex]
|
[m * nDecoderSubbands + s];
|
deinterleaved_audio_im[signalIndex][m * nDecoderSubbands +
|
s] =
|
gainSb *
|
deinterleaved_audio_delayed_im[signalIndex]
|
[m * nDecoderSubbands + s];
|
}
|
}
|
}
|
}
|
signalIndex++;
|
}
|
}
|
}
|
}
|
return (0);
|
}
|
|
WORD32
|
impd_filter_banks_process(ia_drc_instructions_struct* pstr_drc_instruction_arr,
|
const WORD32 drc_instructions_index,
|
ia_drc_params_struct* ia_drc_params_struct,
|
FLOAT32* audio_io_buf[],
|
ia_audio_band_buffer_struct* audio_band_buffer,
|
ia_filter_banks_struct* ia_filter_banks_struct,
|
const WORD32 passThru) {
|
WORD32 c, g, e, i, num_bands;
|
// WORD32 err = 0;
|
FLOAT32* audio_in;
|
FLOAT32** audio_out;
|
ia_drc_filter_bank_struct* str_drc_filter_bank;
|
ia_drc_instructions_struct* str_drc_instruction_str;
|
WORD32 drc_frame_size = ia_drc_params_struct->drc_frame_size;
|
|
if (drc_instructions_index >= 0) {
|
str_drc_instruction_str =
|
&(pstr_drc_instruction_arr[drc_instructions_index]);
|
} else {
|
return -1;
|
}
|
|
e = 0;
|
|
for (c = 0; c < str_drc_instruction_str->audio_num_chan; c++)
|
|
{
|
str_drc_filter_bank = NULL;
|
|
audio_in = audio_io_buf[c];
|
|
audio_out = &(audio_band_buffer->non_interleaved_audio[e]);
|
if ((passThru == 0) && (drc_instructions_index >= 0)) {
|
if (str_drc_instruction_str->drc_set_id < 0) {
|
num_bands = 1;
|
} else {
|
g = str_drc_instruction_str->channel_group_of_ch[c];
|
if (g == -1) {
|
num_bands = 1;
|
// if (ia_filter_banks_struct->str_drc_filter_bank != NULL)
|
//{
|
str_drc_filter_bank =
|
&(ia_filter_banks_struct->str_drc_filter_bank
|
[str_drc_instruction_str->num_drc_ch_groups]);
|
//}
|
} else {
|
num_bands = str_drc_instruction_str->band_count_of_ch_group[g];
|
// if (ia_filter_banks_struct->str_drc_filter_bank != NULL)
|
//{
|
str_drc_filter_bank =
|
&(ia_filter_banks_struct->str_drc_filter_bank[g]);
|
//}
|
}
|
// if (ia_filter_banks_struct->str_drc_filter_bank != NULL)
|
//{
|
// if (&str_drc_filter_bank->str_all_pass_cascade != NULL)
|
//{
|
impd_all_pass_cascade_process(
|
&str_drc_filter_bank->str_all_pass_cascade, c, drc_frame_size,
|
audio_in);
|
//}
|
//}
|
}
|
} else {
|
num_bands = 1;
|
}
|
switch (num_bands) {
|
case 1:
|
for (i = 0; i < drc_frame_size; i++) {
|
audio_out[0][i] = audio_in[i];
|
}
|
e++;
|
break;
|
case 2:
|
impd_two_band_filter_process(&str_drc_filter_bank->str_two_band_bank, c,
|
drc_frame_size, audio_in, audio_out);
|
e += 2;
|
break;
|
case 3:
|
impd_three_band_filter_process(
|
&str_drc_filter_bank->str_three_band_bank, c, drc_frame_size,
|
audio_in, audio_out);
|
e += 3;
|
break;
|
case 4:
|
impd_four_band_filter_process(&str_drc_filter_bank->str_four_band_bank,
|
c, drc_frame_size, audio_in, audio_out);
|
e += 4;
|
break;
|
default:
|
return (PARAM_ERROR);
|
break;
|
}
|
}
|
|
return (0);
|
}
|
|
WORD32
|
impd_store_audio_io_buffer_time(FLOAT32* audio_in_out_buf[],
|
ia_audio_in_out_buf* audio_io_buf_internal) {
|
WORD32 i, j;
|
|
if (audio_io_buf_internal->audio_delay_samples) {
|
for (i = 0; i < audio_io_buf_internal->audio_num_chan; i++) {
|
for (j = 0; j < audio_io_buf_internal->frame_size; j++) {
|
audio_io_buf_internal->audio_io_buffer_delayed
|
[i][audio_io_buf_internal->audio_delay_samples + j] =
|
audio_in_out_buf[i][j];
|
}
|
}
|
} else {
|
audio_io_buf_internal->audio_io_buffer_delayed = audio_in_out_buf;
|
audio_io_buf_internal->audio_in_out_buf = audio_in_out_buf;
|
}
|
|
return 0;
|
}
|
|
WORD32
|
impd_store_audio_io_buffer_freq(FLOAT32* audio_real_buff[],
|
FLOAT32* audio_imag_buff[],
|
ia_audio_in_out_buf* audio_io_buf_internal) {
|
WORD32 i, j;
|
|
if (audio_io_buf_internal->audio_delay_sub_band_samples) {
|
for (i = 0; i < audio_io_buf_internal->audio_num_chan; i++) {
|
for (j = 0; j < audio_io_buf_internal->audio_sub_band_frame_size *
|
audio_io_buf_internal->audio_sub_band_count;
|
j++) {
|
audio_io_buf_internal->audio_buffer_delayed_real
|
[i][audio_io_buf_internal->audio_delay_sub_band_samples *
|
audio_io_buf_internal->audio_sub_band_count +
|
j] = audio_real_buff[i][j];
|
audio_io_buf_internal->audio_buffer_delayed_imag
|
[i][audio_io_buf_internal->audio_delay_sub_band_samples *
|
audio_io_buf_internal->audio_sub_band_count +
|
j] = audio_imag_buff[i][j];
|
}
|
}
|
} else {
|
audio_io_buf_internal->audio_buffer_delayed_real = audio_real_buff;
|
audio_io_buf_internal->audio_buffer_delayed_imag = audio_imag_buff;
|
audio_io_buf_internal->audio_real_buff = audio_real_buff;
|
audio_io_buf_internal->audio_imag_buff = audio_imag_buff;
|
}
|
|
return 0;
|
}
|
|
WORD32
|
impd_retrieve_audio_io_buffer_time(FLOAT32* audio_in_out_buf[],
|
ia_audio_in_out_buf* audio_io_buf_internal) {
|
WORD32 i, j;
|
|
if (audio_io_buf_internal->audio_delay_samples) {
|
for (i = 0; i < audio_io_buf_internal->audio_num_chan; i++) {
|
for (j = 0; j < audio_io_buf_internal->frame_size; j++) {
|
audio_in_out_buf[i][j] =
|
audio_io_buf_internal->audio_io_buffer_delayed[i][j];
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
WORD32
|
impd_retrieve_audio_buffer_freq(FLOAT32* audio_real_buff[],
|
FLOAT32* audio_imag_buff[],
|
ia_audio_in_out_buf* audio_io_buf_internal) {
|
WORD32 i, j;
|
|
if (audio_io_buf_internal->audio_delay_sub_band_samples) {
|
for (i = 0; i < audio_io_buf_internal->audio_num_chan; i++) {
|
for (j = 0; j < audio_io_buf_internal->audio_sub_band_frame_size *
|
audio_io_buf_internal->audio_sub_band_count;
|
j++) {
|
audio_real_buff[i][j] =
|
audio_io_buf_internal->audio_buffer_delayed_real
|
[i][audio_io_buf_internal->audio_sub_band_count + j];
|
audio_imag_buff[i][j] =
|
audio_io_buf_internal->audio_buffer_delayed_imag
|
[i][audio_io_buf_internal->audio_sub_band_count + j];
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
WORD32
|
impd_advance_audio_io_buffer_time(ia_audio_in_out_buf* audio_io_buf_internal) {
|
WORD32 i;
|
if (audio_io_buf_internal->audio_delay_samples) {
|
for (i = 0; i < audio_io_buf_internal->audio_num_chan; i++) {
|
memmove(
|
audio_io_buf_internal->audio_io_buffer_delayed[i],
|
&audio_io_buf_internal
|
->audio_io_buffer_delayed[i][audio_io_buf_internal->frame_size],
|
sizeof(FLOAT32) * audio_io_buf_internal->audio_delay_samples);
|
}
|
}
|
|
return 0;
|
}
|
|
WORD32
|
impd_advance_audio_buff_freq(ia_audio_in_out_buf* audio_io_buf_internal) {
|
WORD32 i;
|
if (audio_io_buf_internal->audio_delay_sub_band_samples) {
|
for (i = 0; i < audio_io_buf_internal->audio_num_chan; i++) {
|
memmove(audio_io_buf_internal->audio_buffer_delayed_real[i],
|
&audio_io_buf_internal->audio_buffer_delayed_real
|
[i][audio_io_buf_internal->audio_sub_band_frame_size *
|
audio_io_buf_internal->audio_sub_band_count],
|
sizeof(FLOAT32) *
|
audio_io_buf_internal->audio_delay_sub_band_samples *
|
audio_io_buf_internal->audio_sub_band_count);
|
memmove(audio_io_buf_internal->audio_buffer_delayed_imag[i],
|
&audio_io_buf_internal->audio_buffer_delayed_imag
|
[i][audio_io_buf_internal->audio_sub_band_frame_size *
|
audio_io_buf_internal->audio_sub_band_count],
|
sizeof(FLOAT32) *
|
audio_io_buf_internal->audio_delay_sub_band_samples *
|
audio_io_buf_internal->audio_sub_band_count);
|
}
|
}
|
return 0;
|
}
|