1062 lines
37 KiB
C
1062 lines
37 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 <math.h>
|
|
#include <string.h>
|
|
#include "ixheaacd_type_def.h"
|
|
#include "ixheaacd_bitbuffer.h"
|
|
#include "ixheaacd_common_rom.h"
|
|
#include "ixheaacd_sbrdecsettings.h"
|
|
#include "ixheaacd_sbr_scale.h"
|
|
#include "ixheaacd_env_extr_part.h"
|
|
#include "ixheaacd_sbr_rom.h"
|
|
#include "ixheaacd_hybrid.h"
|
|
#include "ixheaacd_ps_dec.h"
|
|
#include "ixheaacd_config.h"
|
|
#include "ixheaacd_qmf_dec.h"
|
|
#include "ixheaacd_audioobjtypes.h"
|
|
#include "ixheaacd_mps_polyphase.h"
|
|
#include "ixheaacd_mps_struct_def.h"
|
|
#include "ixheaacd_mps_res_rom.h"
|
|
#include "ixheaacd_mps_aac_struct.h"
|
|
#include "ixheaacd_constants.h"
|
|
#include "ixheaacd_mps_dec.h"
|
|
#include "ixheaacd_mps_decor.h"
|
|
#include "ixheaacd_mps_hybfilter.h"
|
|
#include "ixheaacd_error_standards.h"
|
|
#include "ixheaacd_basic_ops32.h"
|
|
#include "ixheaacd_basic_ops40.h"
|
|
#include "ixheaacd_mps_macro_def.h"
|
|
#include "ixheaacd_mps_basic_op.h"
|
|
|
|
static const WORD32 ixheaacd_decorr_delay[] = {11, 10, 5, 2};
|
|
static const WORD32 ixheaacd_decorr_delay_ldmps[] = {8, 7, 2, 1};
|
|
|
|
static const WORD32 ixheaacd_qmf_split_freq_0[] = {3, 15, 24, 65};
|
|
static const WORD32 ixheaacd_qmf_split_freq_1[] = {3, 50, 65, 65};
|
|
static const WORD32 ixheaacd_qmf_split_freq_2[] = {0, 15, 65, 65};
|
|
|
|
|
|
static const WORD32 ixheaacd_qmf_split_freq_0_ldmps[] = {0, 15, 24, 65};
|
|
static const WORD32 ixheaacd_qmf_split_freq_1_ldmps[] = {0, 50, 65, 65};
|
|
static const WORD32 ixheaacd_qmf_split_freq_2_ldmps[] = {0, 15, 65, 65};
|
|
|
|
extern const WORD32 ixheaacd_mps_gain_set_indx[29];
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_0_filt_den_coeff[DECORR_FILT_0_ORD + 1] = {
|
|
1.000000f, -0.314818f, -0.256828f, -0.173641f, -0.115077f, 0.000599f,
|
|
0.033343f, 0.122672f, -0.356362f, 0.128058f, 0.089800f};
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_0_filt_num_coeff[DECORR_FILT_0_ORD + 1] = {
|
|
0.089800f, 0.128058f, -0.356362f, 0.122672f, 0.033343f, 0.000599f,
|
|
-0.115077f, -0.173641f, -0.256828f, -0.314818f, 1.000000f};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_1_filt_den_coeff[DECORR_FILT_1_ORD + 1] = {
|
|
1.000000f, -0.287137f, -0.088940f, 0.123204f, -0.126111f,
|
|
0.064218f, 0.045768f, -0.016264f, -0.122100f};
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_1_filt_num_coeff[DECORR_FILT_1_ORD + 1] = {
|
|
-0.122100f, -0.016264f, 0.045768f, 0.064218f, -0.126111f,
|
|
0.123204f, -0.088940f, -0.287137f, 1.000000f};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_2_filt_den_coeff[DECORR_FILT_2_ORD + 1] = {
|
|
1.000000f, 0.129403f, -0.032633f, 0.035700f};
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_2_filt_num_coeff[DECORR_FILT_2_ORD + 1] = {
|
|
0.035700f, -0.032633f, 0.129403f, 1.000000f};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_3_filt_den_coeff[DECORR_FILT_3_ORD + 1] = {
|
|
1.000000f, 0.034742f, -0.013000f};
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_3_filt_num_coeff[DECORR_FILT_3_ORD + 1] = {
|
|
-0.013000f, 0.034742f, 1.000000f};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_1_filt_num_ldmps[DECORR_FILTER_ORDER_BAND_1 + 1] = {
|
|
(0.3355999887f), (0.0024894588f), (-0.1572290659f), (0.2807503343f),
|
|
(-0.1942857355f), (0.3840600252f), (-0.4084388912f), (-0.1750483066f),
|
|
(0.5559588671f), (-0.4935829639f), (0.0567415841f), (-0.0658148378f),
|
|
(0.3378961682f), (0.2284426540f), (-0.7025330663f), (1.0000000000f)};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_1_filt_den_ldmps[DECORR_FILTER_ORDER_BAND_1 + 1] = {
|
|
(1.0000000000f), (-0.7025330663f), (0.2284426540f), (0.3378961682f),
|
|
(-0.0658148378f), (0.0567415841f), (-0.4935829639f), (0.5559588671f),
|
|
(-0.1750483066f), (-0.4084388912f), (0.3840600252f), (-0.1942857355f),
|
|
(0.2807503343f), (-0.1572290659f), (0.0024894588f), (0.3355999887f)};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_2_filt_num_ldmps[DECORR_FILTER_ORDER_BAND_2 + 1] = {
|
|
(-0.4623999894f), (0.2341193259f), (0.5163637400f), (-0.0253488291f),
|
|
(-0.2871030867f), (0.0153170601f), (1.0000000000f)};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_2_filt_den_ldmps[DECORR_FILTER_ORDER_BAND_2 + 1] = {
|
|
(1.0000000000f), (0.0153170601f), (-0.2871030867f), (-0.0253488291f),
|
|
(0.5163637400f), (0.2341193259f), (-0.4623999894f)
|
|
|
|
};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_3_filt_num_ldmps[DECORR_FILTER_ORDER_BAND_3 + 1] = {
|
|
(0.2468000054f), (0.0207958221f), (-0.3898491263f), (1.0000000000f)};
|
|
|
|
static const FLOAT32
|
|
ixheaacd_lattice_coeff_3_filt_den_ldmps[DECORR_FILTER_ORDER_BAND_3 + 1] = {
|
|
(1.0000000000f), (-0.3898491263f), (0.0207958221f), (0.2468000054f)};
|
|
|
|
extern WORD32
|
|
ixheaacd_hybrid_band_71_to_processing_band_28_map[MAX_HYBRID_BANDS_MPS];
|
|
extern WORD32
|
|
ixheaacd_hybrid_band_64_to_processing_band_23_map[MAX_HYBRID_BANDS_MPS];
|
|
|
|
static const WORD32 ixheaacd_hybrid_to_qmf_map[MAX_HYBRID_BANDS_MPS] = {
|
|
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
|
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
|
|
47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
|
|
|
|
static const WORD32 ixheaacd_hybrid_to_qmf_map_ldmps[MAX_HYBRID_BANDS_MPS] = {
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
|
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
|
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70};
|
|
|
|
static VOID ixheaacd_mps_decor_filt_init(ia_mps_decor_filt_struct *self,
|
|
WORD32 reverb_band,
|
|
WORD32 object_type) {
|
|
if (object_type == AOT_ER_AAC_ELD || object_type == AOT_ER_AAC_LD) {
|
|
switch (reverb_band) {
|
|
case 0:
|
|
self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_0 + 1;
|
|
self->num = NULL;
|
|
self->den = NULL;
|
|
|
|
break;
|
|
case 1:
|
|
self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_1 + 1;
|
|
self->num = ixheaacd_lattice_coeff_1_filt_num_ldmps;
|
|
self->den = ixheaacd_lattice_coeff_1_filt_den_ldmps;
|
|
|
|
break;
|
|
case 2:
|
|
self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_2 + 1;
|
|
self->num = ixheaacd_lattice_coeff_2_filt_num_ldmps;
|
|
self->den = ixheaacd_lattice_coeff_2_filt_den_ldmps;
|
|
break;
|
|
case 3:
|
|
self->num_len = self->den_len = DECORR_FILTER_ORDER_BAND_3 + 1;
|
|
self->num = ixheaacd_lattice_coeff_3_filt_num_ldmps;
|
|
self->den = ixheaacd_lattice_coeff_3_filt_den_ldmps;
|
|
break;
|
|
}
|
|
} else {
|
|
switch (reverb_band) {
|
|
case 0:
|
|
self->num_len = self->den_len = DECORR_FILT_0_ORD + 1;
|
|
self->num = ixheaacd_lattice_coeff_0_filt_num_coeff;
|
|
self->den = ixheaacd_lattice_coeff_0_filt_den_coeff;
|
|
|
|
break;
|
|
case 1:
|
|
self->num_len = self->den_len = DECORR_FILT_1_ORD + 1;
|
|
self->num = ixheaacd_lattice_coeff_1_filt_num_coeff;
|
|
self->den = ixheaacd_lattice_coeff_1_filt_den_coeff;
|
|
|
|
break;
|
|
case 2:
|
|
self->num_len = self->den_len = DECORR_FILT_2_ORD + 1;
|
|
self->num = ixheaacd_lattice_coeff_2_filt_num_coeff;
|
|
self->den = ixheaacd_lattice_coeff_2_filt_den_coeff;
|
|
break;
|
|
case 3:
|
|
self->num_len = self->den_len = DECORR_FILT_3_ORD + 1;
|
|
self->num = ixheaacd_lattice_coeff_3_filt_num_coeff;
|
|
self->den = ixheaacd_lattice_coeff_3_filt_den_coeff;
|
|
break;
|
|
}
|
|
}
|
|
|
|
self->state_len = self->num_len;
|
|
memset(self->state, 0,
|
|
sizeof(ia_cmplx_flt_struct) * (MAX_DECORR_FILTER_ORDER + 1));
|
|
|
|
return;
|
|
}
|
|
|
|
static VOID ixheaacd_mps_allpass_apply(ia_mps_decor_filt_struct *self,
|
|
ia_cmplx_flt_struct *input, WORD32 len,
|
|
ia_cmplx_flt_struct *output) {
|
|
WORD32 i, j;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
output[i].re = self->state[0].re + input[i].re * self->num[0];
|
|
output[i].im = self->state[0].im + input[i].im * self->num[0];
|
|
|
|
for (j = 1; j < self->num_len; j++) {
|
|
self->state[j - 1].re = self->state[j].re + self->num[j] * input[i].re -
|
|
self->den[j] * output[i].re;
|
|
self->state[j - 1].im = self->state[j].im + self->num[j] * input[i].im -
|
|
self->den[j] * output[i].im;
|
|
}
|
|
}
|
|
}
|
|
|
|
static VOID ixheaacd_mps_decor_energy_adjustment(
|
|
ixheaacd_mps_decor_energy_adjust_filt_struct *handle,
|
|
ia_cmplx_flt_struct in[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS],
|
|
ia_cmplx_flt_struct out[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS],
|
|
WORD32 time_slots, WORD32 res_bands, WORD32 ldmps_present) {
|
|
ixheaacd_mps_decor_energy_adjust_filt_struct *self =
|
|
(ixheaacd_mps_decor_energy_adjust_filt_struct *)handle;
|
|
FLOAT32 in_energy[MAX_PARAMETER_BANDS] = {0};
|
|
FLOAT32 out_energy[MAX_PARAMETER_BANDS] = {0};
|
|
FLOAT32 gain[MAX_PARAMETER_BANDS];
|
|
WORD32 i, j, k, loop_counter;
|
|
WORD32 *ptr_hybrid_band;
|
|
|
|
if (ldmps_present == 1)
|
|
ptr_hybrid_band = ixheaacd_hybrid_band_64_to_processing_band_23_map;
|
|
else
|
|
ptr_hybrid_band = ixheaacd_hybrid_band_71_to_processing_band_28_map;
|
|
|
|
WORD32 start_param_band = 0, start_bin = 0;
|
|
|
|
if (res_bands != NO_RES_BANDS) {
|
|
start_bin = ixheaacd_mps_gain_set_indx[res_bands];
|
|
start_param_band = res_bands;
|
|
}
|
|
|
|
for (i = 0; i < time_slots; i++) {
|
|
memset(in_energy, 0, sizeof(FLOAT32) * MAX_PARAMETER_BANDS);
|
|
memset(out_energy, 0, sizeof(FLOAT32) * MAX_PARAMETER_BANDS);
|
|
|
|
for (j = start_bin; j < self->num_bins; j++) {
|
|
k = ptr_hybrid_band[j];
|
|
|
|
in_energy[k] += in[i][j].re * in[i][j].re + in[i][j].im * in[i][j].im;
|
|
out_energy[k] +=
|
|
out[i][j].re * out[i][j].re + out[i][j].im * out[i][j].im;
|
|
}
|
|
|
|
loop_counter = MAX_PARAMETER_BANDS;
|
|
|
|
for (k = start_param_band; k < loop_counter; k++) {
|
|
self->smooth_in_energy[k] = self->smooth_in_energy[k] * DECOR_ALPHA +
|
|
in_energy[k] * ONE_MINUS_DECOR_ALPHA;
|
|
self->smooth_out_energy[k] = self->smooth_out_energy[k] * DECOR_ALPHA +
|
|
out_energy[k] * ONE_MINUS_DECOR_ALPHA;
|
|
|
|
gain[k] = 1.0f;
|
|
|
|
if (self->smooth_out_energy[k] >
|
|
self->smooth_in_energy[k] * DECOR_GAMMA) {
|
|
gain[k] = (FLOAT32)sqrt(self->smooth_in_energy[k] * DECOR_GAMMA /
|
|
(self->smooth_out_energy[k] + ABS_THR));
|
|
}
|
|
|
|
if (self->smooth_in_energy[k] >
|
|
self->smooth_out_energy[k] * DECOR_GAMMA) {
|
|
gain[k] =
|
|
min(2.0f, (FLOAT32)sqrt(self->smooth_in_energy[k] /
|
|
(DECOR_GAMMA * self->smooth_out_energy[k] +
|
|
ABS_THR)));
|
|
}
|
|
}
|
|
|
|
for (j = start_bin; j < self->num_bins; j++) {
|
|
k = ptr_hybrid_band[j];
|
|
|
|
out[i][j].re *= gain[k];
|
|
out[i][j].im *= gain[k];
|
|
}
|
|
}
|
|
}
|
|
|
|
IA_ERRORCODE ixheaacd_mps_decor_init(ia_mps_decor_struct *self,
|
|
WORD32 subbands, WORD32 decor_config,
|
|
WORD32 object_type) {
|
|
WORD32 i, reverb_band;
|
|
const WORD32 *splitfreq;
|
|
const WORD32 *ptr_ixheaacd_hybrid_to_qmf_map;
|
|
const WORD32 *ptr_decorr_delay;
|
|
if (object_type == AOT_ER_AAC_ELD || object_type == AOT_ER_AAC_LD) {
|
|
ptr_ixheaacd_hybrid_to_qmf_map = ixheaacd_hybrid_to_qmf_map_ldmps;
|
|
ptr_decorr_delay = ixheaacd_decorr_delay_ldmps;
|
|
switch (decor_config) {
|
|
case 0:
|
|
splitfreq = ixheaacd_qmf_split_freq_0_ldmps;
|
|
break;
|
|
case 1:
|
|
splitfreq = ixheaacd_qmf_split_freq_1_ldmps;
|
|
break;
|
|
case 2:
|
|
splitfreq = ixheaacd_qmf_split_freq_2_ldmps;
|
|
break;
|
|
default:
|
|
return IA_FATAL_ERROR;
|
|
}
|
|
} else {
|
|
ptr_ixheaacd_hybrid_to_qmf_map = ixheaacd_hybrid_to_qmf_map;
|
|
ptr_decorr_delay = ixheaacd_decorr_delay;
|
|
switch (decor_config) {
|
|
case 0:
|
|
splitfreq = ixheaacd_qmf_split_freq_0;
|
|
break;
|
|
case 1:
|
|
splitfreq = ixheaacd_qmf_split_freq_1;
|
|
break;
|
|
case 2:
|
|
splitfreq = ixheaacd_qmf_split_freq_2;
|
|
break;
|
|
default:
|
|
return IA_FATAL_ERROR;
|
|
}
|
|
}
|
|
|
|
self->num_bins = subbands;
|
|
if (self->num_bins > MAX_HYBRID_BANDS_MPS) return IA_FATAL_ERROR;
|
|
|
|
for (i = 0; i < self->num_bins; i++) {
|
|
reverb_band = 0;
|
|
while ((reverb_band < 3) &&
|
|
(ptr_ixheaacd_hybrid_to_qmf_map[i] >= (splitfreq[reverb_band] - 1)))
|
|
reverb_band++;
|
|
|
|
self->delay_sample_count[i] = ptr_decorr_delay[reverb_band];
|
|
ixheaacd_mps_decor_filt_init(&self->filter[i], reverb_band, object_type);
|
|
}
|
|
|
|
self->decor_nrg_smooth.num_bins = self->num_bins;
|
|
|
|
return IA_NO_ERROR;
|
|
}
|
|
|
|
VOID ixheaacd_mps_decor_apply(
|
|
ia_mps_decor_struct *self,
|
|
ia_cmplx_flt_struct in[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS],
|
|
ia_cmplx_flt_struct out[MAX_TIME_SLOTS][MAX_HYBRID_BANDS_MPS],
|
|
WORD32 length, WORD32 res_bands, WORD32 ldmps_present) {
|
|
WORD32 idx, sb_sample, index = 0;
|
|
|
|
ia_cmplx_flt_struct scratch[MAX_TIME_SLOTS];
|
|
|
|
if (res_bands != NO_RES_BANDS) index = ixheaacd_mps_gain_set_indx[res_bands];
|
|
|
|
for (idx = index; idx < self->num_bins; idx++) {
|
|
for (sb_sample = 0; sb_sample < length; sb_sample++) {
|
|
self->decor_delay_buffer[idx][self->delay_sample_count[idx] + sb_sample]
|
|
.re = in[sb_sample][idx].re;
|
|
self->decor_delay_buffer[idx][self->delay_sample_count[idx] + sb_sample]
|
|
.im = in[sb_sample][idx].im;
|
|
}
|
|
ixheaacd_mps_allpass_apply(&self->filter[idx],
|
|
self->decor_delay_buffer[idx], length, scratch);
|
|
|
|
for (sb_sample = 0; sb_sample < length; sb_sample++) {
|
|
out[sb_sample][idx].re = scratch[sb_sample].re;
|
|
out[sb_sample][idx].im = scratch[sb_sample].im;
|
|
}
|
|
|
|
for (sb_sample = 0; sb_sample < self->delay_sample_count[idx];
|
|
sb_sample++) {
|
|
self->decor_delay_buffer[idx][sb_sample].re =
|
|
self->decor_delay_buffer[idx][length + sb_sample].re;
|
|
self->decor_delay_buffer[idx][sb_sample].im =
|
|
self->decor_delay_buffer[idx][length + sb_sample].im;
|
|
}
|
|
}
|
|
|
|
ixheaacd_mps_decor_energy_adjustment(&self->decor_nrg_smooth, in, out, length,
|
|
res_bands,
|
|
ldmps_present);
|
|
}
|
|
|
|
static VOID ixheaacd_convert_lattice_coefs_complex(WORD32 const order,
|
|
WORD32 const *const rfc_real,
|
|
WORD32 const *const rfc_imag,
|
|
WORD32 *const apar_real,
|
|
WORD32 *const apar_imag) {
|
|
WORD32 i, j;
|
|
WORD32 tmp_real[MAX_DECORR_FILTER_ORDER + 1];
|
|
WORD32 tmp_imag[MAX_DECORR_FILTER_ORDER + 1];
|
|
WORD64 temp;
|
|
|
|
apar_real[0] = 32768;
|
|
apar_imag[0] = 0;
|
|
|
|
for (i = 0; i < order; i++) {
|
|
apar_real[i + 1] = rfc_real[i];
|
|
apar_imag[i + 1] = rfc_imag[i];
|
|
for (j = 0; j < i; j++) {
|
|
temp = (WORD64)((WORD64)rfc_real[i] * (WORD64)tmp_real[i - j - 1] +
|
|
(WORD64)rfc_imag[i] * (WORD64)tmp_imag[i - j - 1]);
|
|
temp >>= 15;
|
|
apar_real[j + 1] = ixheaacd_add32(tmp_real[j], (WORD32)temp);
|
|
|
|
temp = (WORD64)((WORD64)rfc_real[i] * (WORD64)tmp_imag[i - j - 1] +
|
|
(WORD64)rfc_imag[i] * (WORD64)tmp_real[i - j - 1]);
|
|
temp >>= 15;
|
|
apar_imag[j + 1] = ixheaacd_sub32(tmp_imag[j], (WORD32)temp);
|
|
}
|
|
for (j = 0; j <= i; j++) {
|
|
tmp_real[j] = apar_real[j + 1];
|
|
tmp_imag[j] = apar_imag[j + 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
static IA_ERRORCODE ixheaacd_decorr_filt_create(
|
|
ia_mps_dec_decorr_filter_instance_struct *self, WORD32 const decorr_seed,
|
|
WORD32 const qmf_band, WORD32 const reverb_band, WORD32 const dec_type,
|
|
ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table) {
|
|
IA_ERRORCODE error_code = IA_NO_ERROR;
|
|
WORD32 i;
|
|
const WORD32 *lattice_coeff = NULL;
|
|
WORD32 lattice_coeff_real[MAX_DECORR_FILTER_ORDER];
|
|
WORD32 lattice_coeff_imag[MAX_DECORR_FILTER_ORDER];
|
|
WORD32 temp_1;
|
|
|
|
if (self == NULL) {
|
|
error_code = IA_FATAL_ERROR;
|
|
}
|
|
|
|
if (error_code == IA_NO_ERROR) {
|
|
switch (reverb_band) {
|
|
case REVERB_BAND_0:
|
|
self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_0 + 1;
|
|
lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->lattice_coeff_0[decorr_seed][0]);
|
|
break;
|
|
case REVERB_BAND_1:
|
|
self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_1 + 1;
|
|
lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->lattice_coeff_1[decorr_seed][0]);
|
|
break;
|
|
case REVERB_BAND_2:
|
|
self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_2 + 1;
|
|
lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->lattice_coeff_2[decorr_seed][0]);
|
|
break;
|
|
case REVERB_BAND_3:
|
|
self->num_length = self->den_length = DECORR_FILTER_ORDER_BAND_3 + 1;
|
|
lattice_coeff = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->lattice_coeff_3[decorr_seed][0]);
|
|
break;
|
|
default:
|
|
return IA_FATAL_ERROR;
|
|
}
|
|
self->state_length = (self->num_length > self->den_length)
|
|
? self->num_length
|
|
: self->den_length;
|
|
}
|
|
|
|
if (error_code == IA_NO_ERROR) {
|
|
const WORD32 *cos_tab =
|
|
ia_mps_dec_mps_table->hybrid_table_ptr->cosine_array;
|
|
const WORD32 *sin_tab = ia_mps_dec_mps_table->hybrid_table_ptr->sine_array;
|
|
|
|
if (dec_type == 1) {
|
|
for (i = 0; i < self->num_length - 1; i++) {
|
|
temp_1 = (qmf_band * ia_mps_dec_mps_table->decor_table_ptr
|
|
->lattice_delta_phi[decorr_seed][i]) >>
|
|
1;
|
|
lattice_coeff_real[i] = ixheaacd_mps_mult32_shr_15(
|
|
ixheaacd_mps_cos(temp_1, cos_tab), lattice_coeff[i]);
|
|
lattice_coeff_imag[i] = ixheaacd_mps_mult32_shr_15(
|
|
ixheaacd_mps_sin(temp_1, sin_tab), lattice_coeff[i]);
|
|
}
|
|
|
|
ixheaacd_convert_lattice_coefs_complex(
|
|
self->num_length - 1, lattice_coeff_real, lattice_coeff_imag,
|
|
self->denominator_real, self->denominator_imag);
|
|
for (i = 0; i < self->num_length; i++) {
|
|
self->numerator_real[i] =
|
|
self->denominator_real[self->num_length - 1 - i];
|
|
self->numerator_imag[i] =
|
|
-self->denominator_imag[self->num_length - 1 - i];
|
|
}
|
|
|
|
self->complex = 1;
|
|
} else {
|
|
switch (reverb_band) {
|
|
case REVERB_BAND_0:
|
|
self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->den_coef_0[decorr_seed][0]);
|
|
break;
|
|
case REVERB_BAND_1:
|
|
self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->den_coef_1[decorr_seed][0]);
|
|
break;
|
|
case REVERB_BAND_2:
|
|
self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->den_coef_2[decorr_seed][0]);
|
|
break;
|
|
case REVERB_BAND_3:
|
|
self->denominator_real = &(ia_mps_dec_mps_table->decor_table_ptr
|
|
->den_coef_3[decorr_seed][0]);
|
|
break;
|
|
default:
|
|
return IA_FATAL_ERROR;
|
|
}
|
|
|
|
for (i = 0; i < self->num_length; i++) {
|
|
self->numerator_real[i] =
|
|
self->denominator_real[self->num_length - 1 - i];
|
|
}
|
|
self->complex = 0;
|
|
}
|
|
}
|
|
return error_code;
|
|
}
|
|
|
|
static VOID ixheaacd_decorr_filt_apply(
|
|
ia_mps_dec_decorr_filter_instance_struct *const self, WORD32 const length,
|
|
WORD32 const *const input_real, WORD32 const *const input_imag,
|
|
WORD32 *const p_output_real, WORD32 *const p_output_imag) {
|
|
WORD32 temp_1, temp_2, temp3, temp4;
|
|
WORD32 temp5, temp6, temp7, temp8;
|
|
WORD32 *state_real, *state_imag;
|
|
WORD32 *numerator_real, *denominator_real;
|
|
WORD32 *output_real = p_output_real;
|
|
WORD32 *output_imag = p_output_imag;
|
|
|
|
WORD32 common_part;
|
|
WORD32 i;
|
|
WORD32 j;
|
|
|
|
common_part = self->num_length;
|
|
state_real = self->state_real;
|
|
state_imag = self->state_imag;
|
|
numerator_real = self->numerator_real;
|
|
denominator_real = self->denominator_real;
|
|
|
|
{
|
|
for (i = 0; i < length; i++) {
|
|
{
|
|
temp5 = input_real[i];
|
|
temp6 = input_imag[i];
|
|
|
|
temp_1 = ixheaacd_mps_mult32_shr_14(temp5, numerator_real[0]);
|
|
temp_2 = ixheaacd_mps_mult32_shr_14(temp6, numerator_real[0]);
|
|
|
|
*output_real = temp_1 + state_real[0];
|
|
*output_imag = temp_2 + state_imag[0];
|
|
|
|
temp7 = *output_real;
|
|
temp8 = *output_imag;
|
|
|
|
output_real += MAX_HYBRID_BANDS;
|
|
output_imag += MAX_HYBRID_BANDS;
|
|
for (j = 1; j < common_part; j++) {
|
|
temp_1 = ixheaacd_mps_mult32x16_shr_16(temp5, numerator_real[j]);
|
|
temp3 = ixheaacd_mps_mult32x16_shr_16(temp6, numerator_real[j]);
|
|
temp_2 = ixheaacd_mps_mult32x16_shr_16(temp7, denominator_real[j]);
|
|
temp4 = ixheaacd_mps_mult32x16_shr_16(temp8, denominator_real[j]);
|
|
temp_1 -= temp_2;
|
|
|
|
state_real[j - 1] = state_real[j] + (temp_1 << 2);
|
|
temp3 -= temp4;
|
|
|
|
state_imag[j - 1] = state_imag[j] + (temp3 << 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static VOID ixheaacd_ducker_apply_71(
|
|
ia_mps_dec_ducker_interface *const face, WORD32 const time_slots,
|
|
WORD32 const *input_real, WORD32 const *input_imag, WORD32 *output_real,
|
|
WORD32 *output_imag, ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table_ptr,
|
|
VOID *scratch) {
|
|
ia_mps_dec_duck_instance_struct *self =
|
|
(ia_mps_dec_duck_instance_struct *)&face[1];
|
|
WORD32 *duck_gain;
|
|
WORD32 gain;
|
|
WORD16 qgain;
|
|
WORD64 direct_nrg[28];
|
|
WORD64 reverb_nrg[28];
|
|
WORD16 *q_duck_gain;
|
|
WORD32 ts;
|
|
WORD32 qs;
|
|
WORD32 pb;
|
|
WORD16 qtemp1, qtemp2, qtemp3;
|
|
WORD32 temp_1, temp_2, temp3;
|
|
const WORD32 *p_input_real;
|
|
const WORD32 *p_input_imag;
|
|
const WORD32 *hybrid_2_param_28 =
|
|
ia_mps_dec_mps_table_ptr->m1_m2_table_ptr->hybrid_2_param_28;
|
|
const WORD32 *sqrt_tab = ia_mps_dec_mps_table_ptr->common_table_ptr->sqrt_tab;
|
|
WORD32 *smooth_direct_nrg = self->smooth_direct_nrg;
|
|
WORD16 *q_smooth_direct_nrg = self->q_smooth_direct_nrg;
|
|
|
|
WORD32 *smooth_reverb_nrg = self->smooth_reverb_nrg;
|
|
WORD16 *q_smooth_reverb_nrg = self->q_smooth_reverb_nrg;
|
|
|
|
WORD32 parameter_bands = self->parameter_bands;
|
|
|
|
WORD32 *p_output_real, *p_output_imag;
|
|
|
|
WORD32 num_bands_2 = self->hybrid_bands;
|
|
WORD32 v1, v2, v3, v4;
|
|
WORD16 one_by_5 = ONE_BY_FIVE_Q16;
|
|
|
|
duck_gain = scratch;
|
|
q_duck_gain = (WORD16 *)scratch + PARAMETER_BANDSX2;
|
|
|
|
p_input_real = input_real;
|
|
p_input_imag = input_imag;
|
|
|
|
p_output_real = output_real;
|
|
p_output_imag = output_imag;
|
|
|
|
for (ts = 0; ts < time_slots; ts++) {
|
|
memset(direct_nrg, 0, sizeof(direct_nrg));
|
|
memset(reverb_nrg, 0, sizeof(reverb_nrg));
|
|
|
|
for (qs = 0; qs < 55; qs++) {
|
|
v1 = p_input_real[qs];
|
|
v2 = p_input_imag[qs];
|
|
v3 = p_output_real[qs];
|
|
v4 = p_output_imag[qs];
|
|
|
|
pb = hybrid_2_param_28[qs];
|
|
direct_nrg[pb] +=
|
|
(WORD64)((WORD64)v1 * (WORD64)v1) + (WORD64)((WORD64)v2 * (WORD64)v2);
|
|
reverb_nrg[pb] +=
|
|
(WORD64)((WORD64)v3 * (WORD64)v3) + (WORD64)((WORD64)v4 * (WORD64)v4);
|
|
}
|
|
|
|
for (; qs < num_bands_2; qs++) {
|
|
v1 = p_input_real[qs];
|
|
v2 = p_input_imag[qs];
|
|
v3 = p_output_real[qs];
|
|
v4 = p_output_imag[qs];
|
|
|
|
direct_nrg[27] +=
|
|
(WORD64)((WORD64)v1 * (WORD64)v1) + (WORD64)((WORD64)v2 * (WORD64)v2);
|
|
reverb_nrg[27] +=
|
|
(WORD64)((WORD64)v3 * (WORD64)v3) + (WORD64)((WORD64)v4 * (WORD64)v4);
|
|
}
|
|
|
|
for (pb = 0; pb < parameter_bands; pb++) {
|
|
WORD16 qtemp, qtemp_1;
|
|
temp_1 = ixheaacd_mps_narrow(direct_nrg[pb], &qtemp);
|
|
|
|
temp_2 = smooth_direct_nrg[pb] << 2;
|
|
temp3 =
|
|
ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_direct_nrg[pb]), qtemp);
|
|
smooth_direct_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5);
|
|
|
|
temp_1 = ixheaacd_mps_narrow(reverb_nrg[pb], &qtemp);
|
|
temp_2 = smooth_reverb_nrg[pb] << 2;
|
|
|
|
temp3 =
|
|
ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_reverb_nrg[pb]), qtemp);
|
|
smooth_reverb_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5);
|
|
|
|
qtemp1 = q_smooth_reverb_nrg[pb] - 1;
|
|
temp_1 = (smooth_reverb_nrg[pb] >> 2) * 3;
|
|
qtemp = q_smooth_direct_nrg[pb];
|
|
temp3 = smooth_direct_nrg[pb];
|
|
|
|
if (ixheaacd_mps_comp(temp3, temp_1, &qtemp, qtemp1)) {
|
|
temp_2 = ixheaacd_mps_div_32(temp3, temp_1, &qtemp2);
|
|
qtemp2 = qtemp2 + qtemp - qtemp1;
|
|
temp3 = (qtemp2) > 28 ? MAX_32 : 4 << qtemp2;
|
|
|
|
if (temp_2 > temp3) {
|
|
*duck_gain = (ONE_IN_Q15 - 1);
|
|
*q_duck_gain++ = 14;
|
|
} else {
|
|
*duck_gain = ixheaacd_mps_sqrt(temp_2, &qtemp2, sqrt_tab);
|
|
*q_duck_gain++ = qtemp2;
|
|
}
|
|
duck_gain++;
|
|
continue;
|
|
}
|
|
|
|
*duck_gain = ONE_IN_Q14 - 1;
|
|
|
|
qtemp = q_smooth_direct_nrg[pb] - 1;
|
|
temp_1 = (smooth_direct_nrg[pb] >> 2) * 3;
|
|
|
|
qtemp_1 = q_smooth_reverb_nrg[pb];
|
|
temp_2 = smooth_reverb_nrg[pb];
|
|
if (ixheaacd_mps_comp(temp_2, temp_1, &(qtemp_1), qtemp)) {
|
|
temp3 = ixheaacd_mps_div_32(temp_1, temp_2, &qtemp3);
|
|
qtemp3 = qtemp3 + qtemp - qtemp_1;
|
|
|
|
*duck_gain = ixheaacd_mps_sqrt(temp3, &qtemp3, sqrt_tab);
|
|
*q_duck_gain = qtemp3;
|
|
}
|
|
|
|
duck_gain++;
|
|
q_duck_gain++;
|
|
}
|
|
duck_gain -= parameter_bands;
|
|
q_duck_gain -= parameter_bands;
|
|
|
|
for (qs = 0; qs < 55; qs++) {
|
|
pb = hybrid_2_param_28[qs];
|
|
gain = duck_gain[pb];
|
|
if (gain == 16383) {
|
|
continue;
|
|
}
|
|
qgain = q_duck_gain[pb];
|
|
p_output_real[qs] =
|
|
ixheaacd_mps_mult32_shr_n(p_output_real[qs], gain, qgain);
|
|
p_output_imag[qs] =
|
|
ixheaacd_mps_mult32_shr_n(p_output_imag[qs], gain, qgain);
|
|
}
|
|
|
|
gain = duck_gain[27];
|
|
|
|
if (gain != 16383) {
|
|
qgain = q_duck_gain[27];
|
|
for (; qs < num_bands_2; qs++) {
|
|
p_output_real[qs] =
|
|
ixheaacd_mps_mult32_shr_n(p_output_real[qs], gain, qgain);
|
|
p_output_imag[qs] =
|
|
ixheaacd_mps_mult32_shr_n(p_output_imag[qs], gain, qgain);
|
|
}
|
|
}
|
|
|
|
p_input_real += MAX_HYBRID_BANDS;
|
|
p_input_imag += MAX_HYBRID_BANDS;
|
|
|
|
p_output_real += MAX_HYBRID_BANDS;
|
|
p_output_imag += MAX_HYBRID_BANDS;
|
|
}
|
|
}
|
|
|
|
static VOID ixheaacd_ducker_apply(
|
|
ia_mps_dec_ducker_interface *const face, WORD32 const time_slots,
|
|
WORD32 const *input_real, WORD32 const *input_imag, WORD32 *output_real,
|
|
WORD32 *output_imag, ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table_ptr,
|
|
VOID *scratch) {
|
|
ia_mps_dec_duck_instance_struct *self =
|
|
(ia_mps_dec_duck_instance_struct *)&face[1];
|
|
WORD32 *duck_gain;
|
|
WORD32 gain;
|
|
WORD16 qgain;
|
|
WORD64 direct_nrg[28];
|
|
WORD64 reverb_nrg[28];
|
|
WORD16 *q_duck_gain;
|
|
WORD32 ts;
|
|
WORD32 qs;
|
|
WORD32 pb;
|
|
WORD16 qtemp1, qtemp2, qtemp3;
|
|
WORD32 temp_1, temp_2, temp3;
|
|
const WORD32 *p_input_real;
|
|
const WORD32 *p_input_imag;
|
|
const WORD32 *hybrid_2_param_28 =
|
|
ia_mps_dec_mps_table_ptr->m1_m2_table_ptr->hybrid_2_param_28;
|
|
const WORD32 *sqrt_tab = ia_mps_dec_mps_table_ptr->common_table_ptr->sqrt_tab;
|
|
WORD32 *smooth_direct_nrg = self->smooth_direct_nrg;
|
|
WORD16 *q_smooth_direct_nrg = self->q_smooth_direct_nrg;
|
|
|
|
WORD32 *smooth_reverb_nrg = self->smooth_reverb_nrg;
|
|
WORD16 *q_smooth_reverb_nrg = self->q_smooth_reverb_nrg;
|
|
|
|
WORD32 parameter_bands = self->parameter_bands;
|
|
|
|
WORD32 *p_output_real, *p_output_imag;
|
|
|
|
WORD32 num_bands_2 = self->hybrid_bands;
|
|
WORD32 v1, v2, v3, v4;
|
|
WORD16 one_by_5 = ONE_BY_FIVE_Q16;
|
|
|
|
duck_gain = scratch;
|
|
q_duck_gain = (WORD16 *)scratch + PARAMETER_BANDSX2;
|
|
|
|
p_input_real = input_real;
|
|
p_input_imag = input_imag;
|
|
|
|
p_output_real = output_real;
|
|
p_output_imag = output_imag;
|
|
|
|
for (ts = 0; ts < time_slots; ts++) {
|
|
memset(direct_nrg, 0, sizeof(direct_nrg));
|
|
memset(reverb_nrg, 0, sizeof(reverb_nrg));
|
|
|
|
for (qs = 0; qs < num_bands_2; qs++) {
|
|
v1 = p_input_real[qs];
|
|
v2 = p_input_imag[qs];
|
|
v3 = p_output_real[qs];
|
|
v4 = p_output_imag[qs];
|
|
|
|
pb = hybrid_2_param_28[qs];
|
|
direct_nrg[pb] +=
|
|
(WORD64)((WORD64)v1 * (WORD64)v1) + (WORD64)((WORD64)v2 * (WORD64)v2);
|
|
reverb_nrg[pb] +=
|
|
(WORD64)((WORD64)v3 * (WORD64)v3) + (WORD64)((WORD64)v4 * (WORD64)v4);
|
|
}
|
|
|
|
for (pb = 0; pb < parameter_bands; pb++) {
|
|
WORD16 qtemp, qtemp_1;
|
|
temp_1 = ixheaacd_mps_narrow(direct_nrg[pb], &qtemp);
|
|
temp_2 = smooth_direct_nrg[pb] << 2;
|
|
temp3 =
|
|
ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_direct_nrg[pb]), qtemp);
|
|
smooth_direct_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5);
|
|
|
|
temp_1 = ixheaacd_mps_narrow(reverb_nrg[pb], &qtemp);
|
|
temp_2 = smooth_reverb_nrg[pb] << 2;
|
|
|
|
temp3 =
|
|
ixheaacd_mps_add32(temp_2, temp_1, &(q_smooth_reverb_nrg[pb]), qtemp);
|
|
smooth_reverb_nrg[pb] = ixheaacd_mps_mult32x16_shr_16(temp3, one_by_5);
|
|
|
|
qtemp1 = q_smooth_reverb_nrg[pb] - 1;
|
|
temp_1 = (smooth_reverb_nrg[pb] >> 2) * 3;
|
|
qtemp = q_smooth_direct_nrg[pb];
|
|
temp3 = smooth_direct_nrg[pb];
|
|
|
|
if (ixheaacd_mps_comp(temp3, temp_1, &qtemp, qtemp1)) {
|
|
temp_2 = ixheaacd_mps_div_32(temp3, temp_1, &qtemp2);
|
|
qtemp2 = qtemp2 + qtemp - qtemp1;
|
|
temp3 = qtemp2 > 28 ? MAX_32 : 4 << qtemp2;
|
|
|
|
if (temp_2 > temp3) {
|
|
*duck_gain = 32767;
|
|
*q_duck_gain++ = 14;
|
|
} else {
|
|
*duck_gain = ixheaacd_mps_sqrt(temp_2, &qtemp2, sqrt_tab);
|
|
*q_duck_gain++ = qtemp2;
|
|
}
|
|
duck_gain++;
|
|
continue;
|
|
}
|
|
|
|
*duck_gain = 16383;
|
|
|
|
qtemp = q_smooth_direct_nrg[pb] - 1;
|
|
temp_1 = (smooth_direct_nrg[pb] >> 2) * 3;
|
|
|
|
qtemp_1 = q_smooth_reverb_nrg[pb];
|
|
temp_2 = smooth_reverb_nrg[pb];
|
|
if (ixheaacd_mps_comp(temp_2, temp_1, &(qtemp_1), qtemp)) {
|
|
temp3 = ixheaacd_mps_div_32(temp_1, temp_2, &qtemp3);
|
|
qtemp3 = qtemp3 + qtemp - qtemp_1;
|
|
|
|
*duck_gain = ixheaacd_mps_sqrt(temp3, &qtemp3, sqrt_tab);
|
|
*q_duck_gain = qtemp3;
|
|
}
|
|
|
|
duck_gain++;
|
|
q_duck_gain++;
|
|
}
|
|
|
|
duck_gain -= parameter_bands;
|
|
q_duck_gain -= parameter_bands;
|
|
|
|
for (qs = 0; qs < num_bands_2; qs++) {
|
|
pb = hybrid_2_param_28[qs];
|
|
gain = duck_gain[pb];
|
|
if (gain == 16383) {
|
|
continue;
|
|
}
|
|
qgain = q_duck_gain[pb];
|
|
p_output_real[qs] =
|
|
ixheaacd_mps_mult32_shr_n(p_output_real[qs], gain, qgain);
|
|
p_output_imag[qs] =
|
|
ixheaacd_mps_mult32_shr_n(p_output_imag[qs], gain, qgain);
|
|
}
|
|
|
|
p_input_real += MAX_HYBRID_BANDS;
|
|
p_input_imag += MAX_HYBRID_BANDS;
|
|
|
|
p_output_real += MAX_HYBRID_BANDS;
|
|
p_output_imag += MAX_HYBRID_BANDS;
|
|
}
|
|
}
|
|
|
|
static IA_ERRORCODE ixheaacd_ducker_create(
|
|
ia_mps_dec_ducker_interface *const face, WORD32 const hybrid_bands) {
|
|
ia_mps_dec_duck_instance_struct *self = NULL;
|
|
IA_ERRORCODE error_code = IA_NO_ERROR;
|
|
WORD32 i;
|
|
|
|
if (face == NULL) {
|
|
error_code = IA_FATAL_ERROR;
|
|
}
|
|
|
|
if (error_code == IA_NO_ERROR) {
|
|
self = (ia_mps_dec_duck_instance_struct *)&face[1];
|
|
|
|
self->hybrid_bands = hybrid_bands;
|
|
self->parameter_bands = MAX_PARAMETER_BANDS;
|
|
|
|
self->alpha = DUCK_ALPHA;
|
|
self->one_minus_alpha = DUCK_ONEMINUSALPHA;
|
|
self->gamma = DUCK_GAMMA;
|
|
self->abs_thr = ABS_THR_FIX;
|
|
self->hybrid_bands = hybrid_bands;
|
|
self->parameter_bands = MAX_PARAMETER_BANDS;
|
|
|
|
self->qalpha = 15;
|
|
self->qgamma = 14;
|
|
|
|
if (hybrid_bands == 71)
|
|
face->apply = ixheaacd_ducker_apply_71;
|
|
else
|
|
face->apply = ixheaacd_ducker_apply;
|
|
|
|
for (i = 0; i < MAX_PARAMETER_BANDS; i++) {
|
|
self->q_smooth_direct_nrg[i] = 31;
|
|
self->q_smooth_reverb_nrg[i] = 31;
|
|
}
|
|
}
|
|
|
|
return error_code;
|
|
}
|
|
|
|
IA_ERRORCODE ixheaacd_decorr_create(
|
|
ia_mps_dec_decorr_dec_handle self, WORD32 subbands, WORD32 seed,
|
|
WORD32 dec_type, WORD32 decorr_config,
|
|
ia_mps_dec_mps_tables_struct *ia_mps_dec_mps_table_ptr) {
|
|
IA_ERRORCODE error_code = IA_NO_ERROR;
|
|
WORD32 i, reverb_band;
|
|
|
|
const WORD32 *rev_split_freq;
|
|
|
|
switch (decorr_config) {
|
|
case DECOR_CONFIG_0:
|
|
rev_split_freq =
|
|
ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table.rev_split_freq_0;
|
|
break;
|
|
case DECOR_CONFIG_1:
|
|
rev_split_freq =
|
|
ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table.rev_split_freq_1;
|
|
break;
|
|
case DECOR_CONFIG_2:
|
|
rev_split_freq =
|
|
ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table.rev_split_freq_2;
|
|
break;
|
|
default:
|
|
return IA_FATAL_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (error_code == IA_NO_ERROR) {
|
|
self->decorr_seed = seed;
|
|
self->numbins = subbands;
|
|
|
|
for (i = 0; i < self->numbins; i++) {
|
|
reverb_band = 0;
|
|
while ((reverb_band < 3) &&
|
|
(ixheaacd_get_qmf_sb(
|
|
i, ia_mps_dec_mps_table_ptr->mdct2qmf_table_ptr) >=
|
|
(rev_split_freq[reverb_band] - 1)))
|
|
reverb_band++;
|
|
|
|
{
|
|
self->no_sample_delay[i] =
|
|
ia_mps_dec_mps_table_ptr->decor_table_ptr->rev_table
|
|
.rev_delay[reverb_band][self->decorr_seed];
|
|
|
|
error_code = ixheaacd_decorr_filt_create(
|
|
self->filter[i], self->decorr_seed,
|
|
ixheaacd_get_qmf_sb(i,
|
|
ia_mps_dec_mps_table_ptr->mdct2qmf_table_ptr),
|
|
reverb_band, dec_type, ia_mps_dec_mps_table_ptr);
|
|
}
|
|
}
|
|
|
|
if (error_code == IA_NO_ERROR) {
|
|
error_code = ixheaacd_ducker_create(self->ducker, self->numbins);
|
|
}
|
|
}
|
|
return (error_code);
|
|
}
|
|
|
|
VOID ixheaacd_decorr_apply(ia_heaac_mps_state_struct *pstr_mps_state, WORD32 length,
|
|
WORD32 *input_real, WORD32 *input_imag,
|
|
WORD32 *output_real, WORD32 *output_imag,
|
|
WORD32 index) {
|
|
WORD32 l = index - pstr_mps_state->num_direct_signals;
|
|
ia_mps_dec_decorr_dec_handle decorr_ptr = pstr_mps_state->ap_decor[l];
|
|
WORD32 idx, sb_sample;
|
|
|
|
WORD32 *p_input_real, *p_input_re, *p_input_imag, *p_input_im;
|
|
WORD32 *p_output_real, *p_output_imag, *p_output_re, *p_output_im;
|
|
WORD32 *delay_buffer_real, *delay_buffer_imag;
|
|
WORD32 length1;
|
|
VOID *free_scratch;
|
|
|
|
free_scratch = (WORD32 *)pstr_mps_state->mps_scratch_mem_v + MAX_TIMESLOTSX2;
|
|
|
|
if (decorr_ptr != NULL) {
|
|
p_input_real = input_real;
|
|
p_input_imag = input_imag;
|
|
|
|
p_output_real = output_real;
|
|
p_output_imag = output_imag;
|
|
for (idx = 0; idx < decorr_ptr->numbins; idx++) {
|
|
p_input_re = p_input_real;
|
|
p_input_im = p_input_imag;
|
|
|
|
p_output_re = p_output_real;
|
|
p_output_im = p_output_imag;
|
|
|
|
length1 = length - decorr_ptr->no_sample_delay[idx];
|
|
delay_buffer_real =
|
|
&decorr_ptr->delay_buffer_real[idx][decorr_ptr->no_sample_delay[idx]];
|
|
delay_buffer_imag =
|
|
&decorr_ptr->delay_buffer_imag[idx][decorr_ptr->no_sample_delay[idx]];
|
|
for (sb_sample = 0; sb_sample < length1; sb_sample++) {
|
|
delay_buffer_real[sb_sample] = *p_input_re;
|
|
*delay_buffer_imag++ = *p_input_im;
|
|
p_input_re += MAX_HYBRID_BANDS;
|
|
p_input_im += MAX_HYBRID_BANDS;
|
|
}
|
|
{
|
|
ixheaacd_decorr_filt_apply(
|
|
decorr_ptr->filter[idx], length, decorr_ptr->delay_buffer_real[idx],
|
|
decorr_ptr->delay_buffer_imag[idx], p_output_re++, p_output_im++);
|
|
}
|
|
|
|
length1 = decorr_ptr->no_sample_delay[idx];
|
|
delay_buffer_real = &decorr_ptr->delay_buffer_real[idx][0];
|
|
delay_buffer_imag = &decorr_ptr->delay_buffer_imag[idx][0];
|
|
for (sb_sample = 0; sb_sample < length1; sb_sample++) {
|
|
delay_buffer_real[sb_sample] = *p_input_re;
|
|
p_input_re += MAX_HYBRID_BANDS;
|
|
*delay_buffer_imag++ = *p_input_im;
|
|
p_input_im += MAX_HYBRID_BANDS;
|
|
}
|
|
|
|
p_input_real++;
|
|
p_input_imag++;
|
|
|
|
p_output_real++;
|
|
p_output_imag++;
|
|
}
|
|
decorr_ptr->ducker->apply(decorr_ptr->ducker, length, input_real,
|
|
input_imag, output_real, output_imag,
|
|
&(pstr_mps_state->ia_mps_dec_mps_table), free_scratch);
|
|
}
|
|
}
|