/****************************************************************************** * * * 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 #include "ixheaacd_sbr_common.h" #include "ixheaacd_type_def.h" #include "ixheaacd_constants.h" #include "ixheaacd_basic_ops32.h" #include "ixheaacd_basic_ops16.h" #include "ixheaacd_basic_ops40.h" #include "ixheaacd_basic_ops.h" #include "ixheaacd_intrinsics.h" #include "ixheaacd_common_rom.h" #include "ixheaacd_bitbuffer.h" #include "ixheaacd_sbrdecsettings.h" #include "ixheaacd_sbr_scale.h" #include "ixheaacd_lpp_tran.h" #include "ixheaacd_env_extr_part.h" #include "ixheaacd_sbr_rom.h" #include "ixheaacd_hybrid.h" #include "ixheaacd_ps_dec.h" #include "ixheaacd_env_extr.h" #include "ixheaacd_qmf_dec.h" #include "ixheaacd_basic_op.h" #include "ixheaacd_env_calc.h" #include "ixheaacd_interface.h" #include "ixheaacd_function_selector.h" #include "ixheaacd_audioobjtypes.h" #define DCT3_LEN (32) #define DCT2_LEN (64) #define LP_SHIFT_VAL 7 #define HQ_SHIFT_64 4 #define RADIXSHIFT 1 #define ROUNDING_SPECTRA 1 #define HQ_SHIFT_VAL 4 static PLATFORM_INLINE WORD32 ixheaacd_mult32x32in32_shift25(WORD32 a, WORD32 b) { WORD32 result; WORD64 temp_result; temp_result = (WORD64)a * (WORD64)b; result = (WORD32)(temp_result >> 25); return (result); } VOID ixheaacd_pretwdct2(WORD32 *inp, WORD32 *out_fwd) { WORD32 n; WORD32 *out_rev = out_fwd + DCT2_LEN - 1; for (n = 0; n < DCT2_LEN / 2; n++) { *out_fwd = *inp; inp++; *out_rev = *inp; out_fwd++; out_rev--; inp++; } return; } static PLATFORM_INLINE VOID ixheaacd_pretwdct2_32(WORD32 *inp, WORD32 *out_fwd, int dct2_len) { WORD32 n; WORD32 *out_rev = out_fwd + dct2_len - 1; for (n = dct2_len / 2 - 1; n >= 0; n--) { *out_fwd = *inp; inp++; *out_rev = *inp; out_fwd++; out_rev--; inp++; } return; } VOID ixheaacd_fftposttw(WORD32 *out, ia_qmf_dec_tables_struct *qmf_dec_tables_ptr) { int k; WORD32 *p_out_fwd, *ptr_out_rev; const WORD16 *twidle_fwd, *twidle_rev; WORD32 in1, in2, val1, val2; twidle_fwd = qmf_dec_tables_ptr->post_fft_tbl + 1; twidle_rev = qmf_dec_tables_ptr->post_fft_tbl + 15; p_out_fwd = out; ptr_out_rev = out + DCT2_LEN - 1; in1 = ((*p_out_fwd++) << 1); val1 = ((*p_out_fwd--) << 1); *p_out_fwd++ = in1; *p_out_fwd++ = val1; for (k = 1; k <= DCT2_LEN / 4; k++) { WORD32 temp[4]; WORD16 twid_re, twid_im; temp[0] = *p_out_fwd++; temp[1] = *p_out_fwd--; temp[3] = *ptr_out_rev--; temp[2] = *ptr_out_rev++; in2 = ixheaacd_sub32_sat(temp[3], temp[1]); in1 = ixheaacd_add32_sat(temp[3], temp[1]); temp[1] = ixheaacd_sub32_sat(temp[0], temp[2]); temp[3] = ixheaacd_add32_sat(temp[0], temp[2]); twid_re = *twidle_fwd++; twid_im = *twidle_rev--; val1 = ixheaacd_mult32x16in32(in1, twid_re) - ixheaacd_mult32x16in32(temp[1], twid_im); val2 = ixheaacd_mult32x16in32(temp[1], twid_re) + ixheaacd_mult32x16in32(in1, twid_im); val1 = val1 << 1; val2 = val2 << 1; *p_out_fwd++ = ixheaacd_add32_sat(temp[3], val1); *p_out_fwd++ = ixheaacd_add32_sat(in2, val2); *ptr_out_rev-- = ixheaacd_sub32_sat(val2, in2); *ptr_out_rev-- = ixheaacd_sub32_sat(temp[3], val1); } return; } VOID ixheaacd_posttwdct2(WORD32 *inp, WORD16 *out_fwd, ia_qmf_dec_tables_struct *qmf_dec_tables_ptr) { WORD32 k; WORD32 inp_re, inp_im, out_re, out_im, last_val, out_re1; WORD16 *out_fwd2, *out_rev2, *out_rev; WORD16 twid_re, twid_im; const WORD16 *twidle_fwd; WORD16 re1, im1, im2; out_rev = out_fwd + DCT2_LEN - 1; out_rev2 = out_fwd - 1; out_fwd2 = out_fwd + 65; out_re = *inp++; out_im = *inp++; out_re1 = ixheaacd_sat64_32(ixheaacd_add64((WORD64)out_re, (WORD64)out_im) >> 1); re1 = ixheaacd_round16(ixheaacd_shl32(out_re1, (5 - 1))); *out_fwd++ = re1; last_val = ixheaacd_sub32_sat(out_re, out_im); twidle_fwd = qmf_dec_tables_ptr->dct23_tw + 2; for (k = DCT2_LEN / 2 - 2; k >= 0; k--) { inp_re = *inp++; inp_im = *inp++; twid_re = *twidle_fwd++; twid_im = *twidle_fwd++; out_re = ixheaacd_sub32_sat(ixheaacd_mult32x16in32(inp_re, twid_re), ixheaacd_mult32x16in32(inp_im, twid_im)); out_im = ixheaacd_add32_sat(ixheaacd_mult32x16in32(inp_im, twid_re), ixheaacd_mult32x16in32(inp_re, twid_im)); re1 = ixheaacd_round16(ixheaacd_shl32(out_re, (5 - 1))); im1 = ixheaacd_round16(ixheaacd_shl32(out_im, (5 - 1))); im2 = ixheaacd_negate16(im1); *out_fwd++ = re1; *out_rev2-- = re1; *out_rev-- = im1; *out_fwd2++ = im2; } twid_re = *twidle_fwd++; out_re = ixheaacd_mult32x16in32(last_val, twid_re); re1 = ixheaacd_round16(ixheaacd_shl32(out_re, (5 - 1))); *out_fwd++ = re1; *out_rev2-- = re1; return; } static PLATFORM_INLINE VOID ixheaacd_fftposttw_32( WORD32 *out, int dct2_len, ia_qmf_dec_tables_struct *qmf_dec_tables_ptr) { int k; WORD32 *ptr_out_fwd, *ptr_out_rev; const WORD16 *twidle_fwd, *twidle_rev; WORD32 in1, in2, val1, val2; twidle_fwd = qmf_dec_tables_ptr->post_fft_tbl + 2; twidle_rev = qmf_dec_tables_ptr->post_fft_tbl + 14; ptr_out_fwd = out; ptr_out_rev = out + dct2_len - 1; in1 = ((*ptr_out_fwd++) << 1); val1 = ((*ptr_out_fwd--) << 1); *ptr_out_fwd++ = in1; *ptr_out_fwd++ = val1; for (k = dct2_len / 4 - 1; k >= 0; k--) { WORD32 temp0, temp1, temp2, temp3; WORD16 twid_re, twid_im; temp0 = *ptr_out_fwd++; temp1 = *ptr_out_fwd--; temp3 = *ptr_out_rev--; temp2 = *ptr_out_rev++; in1 = ixheaacd_add32_sat(temp1, temp3); in2 = ixheaacd_sub32_sat(temp3, temp1); temp1 = ixheaacd_sub32_sat(temp0, temp2); temp3 = ixheaacd_add32_sat(temp0, temp2); twid_re = *twidle_fwd; twidle_fwd += 2; twid_im = *twidle_rev; twidle_rev -= 2; val1 = ixheaacd_mult32x16in32(in1, twid_re) - ixheaacd_mult32x16in32(temp1, twid_im); val2 = ixheaacd_mult32x16in32(temp1, twid_re) + ixheaacd_mult32x16in32(in1, twid_im); val1 = val1 << 1; val2 = val2 << 1; *ptr_out_fwd++ = ixheaacd_add32_sat(temp3, val1); *ptr_out_fwd++ = ixheaacd_add32_sat(in2, val2); *ptr_out_rev-- = ixheaacd_sub32_sat(val2, in2); *ptr_out_rev-- = ixheaacd_sub32_sat(temp3, val1); } return; } static PLATFORM_INLINE VOID ixheaacd_posttwdct2_32(WORD32 *inp, WORD16 *out_fwd, ia_qmf_dec_tables_struct *qmf_dec_tables_ptr) { int k; WORD32 inp_re, out_re, out_im, last_val, out_re1; WORD16 *out_rev, *out_rev2, *out_fwd2; WORD16 twid_re, twid_im; const WORD16 *twidle_fwd; WORD16 re1, im1, im2; WORD32 rounding_fac = 0x8000; out_rev = out_fwd + 32 - 1; out_rev2 = out_fwd - 1; out_fwd2 = out_fwd + 32 + 1; out_fwd[32] = 0; out_re = *inp++; out_im = *inp++; out_re1 = ixheaacd_sat64_32(ixheaacd_add64((WORD64)out_re, (WORD64)out_im) >> 1); re1 = ixheaacd_round16(ixheaacd_shl32_sat(out_re1, (5 - 1))); *out_fwd++ = re1; last_val = ixheaacd_sub32_sat(out_re, out_im); twidle_fwd = qmf_dec_tables_ptr->dct23_tw + 4; for (k = 14; k >= 0; k--) { WORD32 temp1, temp2; inp_re = *inp++; twid_re = *twidle_fwd++; twid_im = *twidle_fwd; twidle_fwd += 3; temp1 = ixheaacd_mult32x16in32(inp_re, twid_re); temp2 = ixheaacd_mult32x16in32(inp_re, twid_im); inp_re = *inp++; out_re = ixheaacd_sub32_sat(temp1, ixheaacd_mult32x16in32(inp_re, twid_im)); out_im = ixheaacd_add32_sat(ixheaacd_mult32x16in32(inp_re, twid_re), temp2); out_re = ixheaacd_add32_sat(out_re, out_re); out_im = ixheaacd_add32_sat(out_im, out_im); out_re = ixheaacd_add32_sat(out_re, out_re); out_im = ixheaacd_add32_sat(out_im, out_im); out_re = ixheaacd_add32_sat(out_re, out_re); out_im = ixheaacd_add32_sat(out_im, out_im); out_re = ixheaacd_add32_sat(out_re, out_re); out_im = ixheaacd_add32_sat(out_im, out_im); out_re = ixheaacd_add32_sat(out_re, rounding_fac); out_im = ixheaacd_add32_sat(out_im, rounding_fac); re1 = (out_re >> 16); im1 = (out_im >> 16); im2 = ixheaacd_negate16(im1); *out_fwd++ = re1; *out_rev2-- = re1; *out_rev-- = im1; *out_fwd2++ = im2; } twid_re = *twidle_fwd++; out_re = ixheaacd_mult32x16in32(last_val, twid_re); re1 = ixheaacd_round16(ixheaacd_shl32_sat(out_re, (5 - 1))); *out_fwd++ = re1; *out_rev2-- = re1; return; } VOID ixheaacd_dct2_32(WORD32 *inp, WORD32 *out, ia_qmf_dec_tables_struct *qmf_dec_tables_ptr, WORD16 *filter_states) { WORD32 *output; output = out + 16; filter_states = filter_states + 16; ixheaacd_pretwdct2_32(inp, output, 32); ixheaacd_radix4bfly(qmf_dec_tables_ptr->w_16, output, 1, 4); ixheaacd_postradixcompute4(inp, output, qmf_dec_tables_ptr->dig_rev_table4_16, 16); ixheaacd_fftposttw_32(inp, 32, qmf_dec_tables_ptr); ixheaacd_posttwdct2_32(inp, filter_states, qmf_dec_tables_ptr); return; } VOID ixheaacd_sbr_qmfanal32_winadd_eld(WORD16 *inp1, WORD16 *inp2, WORD16 *p_qmf1, WORD16 *p_qmf2, WORD32 *p_out) { WORD32 n; for (n = 0; n < 32; n += 2) { WORD32 accu; accu = ixheaacd_mult16x16in32(inp1[n + 0], p_qmf1[(n + 0)]); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp1[n + 64], p_qmf1[(n + 64)])); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp1[n + 128], p_qmf1[(n + 128)])); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp1[n + 192], p_qmf1[(n + 192)])); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp1[n + 256], p_qmf1[(n + 256)])); p_out[n] = accu; accu = ixheaacd_mult16x16in32(inp1[n + 1 + 0], p_qmf1[(n + 1 + 0)]); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp1[n + 1 + 64], p_qmf1[(n + 1 + 64)])); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp1[n + 1 + 128], p_qmf1[(n + 1 + 128)])); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp1[n + 1 + 192], p_qmf1[(n + 1 + 192)])); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp1[n + 1 + 256], p_qmf1[(n + 1 + 256)])); p_out[n + 1] = accu; accu = ixheaacd_mult16x16in32(inp2[n + 0], p_qmf2[(n + 0)]); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp2[n + 64], p_qmf2[(n + 64)])); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp2[n + 128], p_qmf2[(n + 128)])); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp2[n + 192], p_qmf2[(n + 192)])); accu = ixheaacd_add32( accu, ixheaacd_mult16x16in32(inp2[n + 256], p_qmf2[(n + 256)])); p_out[n + 32] = accu; accu = ixheaacd_mult16x16in32(inp2[n + 1 + 0], p_qmf2[(n + 1 + 0)]); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp2[n + 1 + 64], p_qmf2[(n + 1 + 64)])); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp2[n + 1 + 128], p_qmf2[(n + 1 + 128)])); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp2[n + 1 + 192], p_qmf2[(n + 1 + 192)])); accu = ixheaacd_add32_sat( accu, ixheaacd_mult16x16in32(inp2[n + 1 + 256], p_qmf2[(n + 1 + 256)])); p_out[n + 1 + 32] = accu; } } VOID ixheaacd_esbr_qmfanal32_winadd(WORD32 *inp1, WORD32 *inp2, WORD32 *p_qmf1, WORD32 *p_qmf2, WORD32 *p_out, WORD32 num_band_anal_qmf) { WORD32 n; WORD64 accu; if (num_band_anal_qmf == 32) { for (n = 0; n < num_band_anal_qmf; n += 2) { accu = ixheaacd_mult64(inp1[n + 0], p_qmf1[2 * (n + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 2 * num_band_anal_qmf], p_qmf1[2 * (n + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 4 * num_band_anal_qmf], p_qmf1[2 * (n + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 6 * num_band_anal_qmf], p_qmf1[2 * (n + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 8 * num_band_anal_qmf], p_qmf1[2 * (n + 8 * num_band_anal_qmf)])); p_out[n] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp1[n + 1 + 0], p_qmf1[2 * (n + 1 + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 2 * num_band_anal_qmf], p_qmf1[2 * (n + 1 + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 4 * num_band_anal_qmf], p_qmf1[2 * (n + 1 + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 6 * num_band_anal_qmf], p_qmf1[2 * (n + 1 + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 8 * num_band_anal_qmf], p_qmf1[2 * (n + 1 + 8 * num_band_anal_qmf)])); p_out[n + 1] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp2[n + 0], p_qmf2[2 * (n + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 2 * num_band_anal_qmf], p_qmf2[2 * (n + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 4 * num_band_anal_qmf], p_qmf2[2 * (n + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 6 * num_band_anal_qmf], p_qmf2[2 * (n + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 8 * num_band_anal_qmf], p_qmf2[2 * (n + 8 * num_band_anal_qmf)])); p_out[n + num_band_anal_qmf] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp2[n + 1 + 0], p_qmf2[2 * (n + 1 + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 2 * num_band_anal_qmf], p_qmf2[2 * (n + 1 + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 4 * num_band_anal_qmf], p_qmf2[2 * (n + 1 + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 6 * num_band_anal_qmf], p_qmf2[2 * (n + 1 + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 8 * num_band_anal_qmf], p_qmf2[2 * (n + 1 + 8 * num_band_anal_qmf)])); p_out[n + 1 + num_band_anal_qmf] = (WORD32)(accu >> 31); } } else if (num_band_anal_qmf == 24) { for (n = 0; n < num_band_anal_qmf; n += 2) { accu = ixheaacd_mult64(inp1[n + 0], p_qmf1[(n + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 2 * num_band_anal_qmf], p_qmf1[(n + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 4 * num_band_anal_qmf], p_qmf1[(n + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 6 * num_band_anal_qmf], p_qmf1[(n + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 8 * num_band_anal_qmf], p_qmf1[(n + 8 * num_band_anal_qmf)])); p_out[n] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp1[n + 1 + 0], p_qmf1[(n + 1 + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 2 * num_band_anal_qmf], p_qmf1[(n + 1 + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 4 * num_band_anal_qmf], p_qmf1[(n + 1 + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 6 * num_band_anal_qmf], p_qmf1[(n + 1 + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 8 * num_band_anal_qmf], p_qmf1[(n + 1 + 8 * num_band_anal_qmf)])); p_out[n + 1] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp2[n + 0], p_qmf2[(n + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 2 * num_band_anal_qmf], p_qmf2[(n + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 4 * num_band_anal_qmf], p_qmf2[(n + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 6 * num_band_anal_qmf], p_qmf2[(n + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 8 * num_band_anal_qmf], p_qmf2[(n + 8 * num_band_anal_qmf)])); p_out[n + num_band_anal_qmf] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp2[n + 1 + 0], p_qmf2[(n + 1 + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 2 * num_band_anal_qmf], p_qmf2[(n + 1 + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 4 * num_band_anal_qmf], p_qmf2[(n + 1 + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 6 * num_band_anal_qmf], p_qmf2[(n + 1 + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 8 * num_band_anal_qmf], p_qmf2[(n + 1 + 8 * num_band_anal_qmf)])); p_out[n + 1 + num_band_anal_qmf] = (WORD32)(accu >> 31); } } else { for (n = 0; n < num_band_anal_qmf; n += 2) { accu = ixheaacd_mult64(inp1[n + 0], p_qmf1[4 * (n + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 2 * num_band_anal_qmf], p_qmf1[4 * (n + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 4 * num_band_anal_qmf], p_qmf1[4 * (n + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 6 * num_band_anal_qmf], p_qmf1[4 * (n + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 8 * num_band_anal_qmf], p_qmf1[4 * (n + 8 * num_band_anal_qmf)])); p_out[n] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp1[n + 1 + 0], p_qmf1[4 * (n + 1 + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 2 * num_band_anal_qmf], p_qmf1[4 * (n + 1 + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 4 * num_band_anal_qmf], p_qmf1[4 * (n + 1 + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 6 * num_band_anal_qmf], p_qmf1[4 * (n + 1 + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp1[n + 1 + 8 * num_band_anal_qmf], p_qmf1[4 * (n + 1 + 8 * num_band_anal_qmf)])); p_out[n + 1] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp2[n + 0], p_qmf2[4 * (n + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 2 * num_band_anal_qmf], p_qmf2[4 * (n + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 4 * num_band_anal_qmf], p_qmf2[4 * (n + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 6 * num_band_anal_qmf], p_qmf2[4 * (n + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 8 * num_band_anal_qmf], p_qmf2[4 * (n + 8 * num_band_anal_qmf)])); p_out[n + num_band_anal_qmf] = (WORD32)(accu >> 31); accu = ixheaacd_mult64(inp2[n + 1 + 0], p_qmf2[4 * (n + 1 + 0)]); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 2 * num_band_anal_qmf], p_qmf2[4 * (n + 1 + 2 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 4 * num_band_anal_qmf], p_qmf2[4 * (n + 1 + 4 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 6 * num_band_anal_qmf], p_qmf2[4 * (n + 1 + 6 * num_band_anal_qmf)])); accu = ixheaacd_add64( accu, ixheaacd_mult64(inp2[n + 1 + 8 * num_band_anal_qmf], p_qmf2[4 * (n + 1 + 8 * num_band_anal_qmf)])); p_out[n + 1 + num_band_anal_qmf] = (WORD32)(accu >> 31); } } } VOID ixheaacd_esbr_inv_modulation( WORD32 *qmf_real, ia_sbr_qmf_filter_bank_struct *syn_qmf, ia_qmf_dec_tables_struct *qmf_dec_tables_ptr) { ixheaacd_esbr_cos_sin_mod(qmf_real, syn_qmf, qmf_dec_tables_ptr->esbr_w_32, qmf_dec_tables_ptr->dig_rev_table2_32); } VOID ixheaacd_sbr_qmfsyn32_winadd(WORD16 *tmp1, WORD16 *tmp2, WORD16 *inp1, WORD16 *sample_buffer, FLAG shift, WORD32 ch_fac) { WORD32 k; WORD32 rounding_fac = 0x8000; rounding_fac = rounding_fac >> shift; for (k = 0; k < 32; k++) { WORD32 syn_out = rounding_fac; syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp1[0 + k], inp1[2 * (k + 0)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp1[128 + k], inp1[2 * (k + 64)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp1[256 + k], inp1[2 * (k + 128)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp1[384 + k], inp1[2 * (k + 192)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp1[512 + k], inp1[2 * (k + 256)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp2[64 + k], inp1[2 * (k + 32)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp2[192 + k], inp1[2 * (k + 96)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp2[320 + k], inp1[2 * (k + 160)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp2[448 + k], inp1[2 * (k + 224)])); syn_out = ixheaacd_add32( syn_out, ixheaacd_mult16x16in32(tmp2[576 + k], inp1[2 * (k + 288)])); syn_out = ixheaacd_add32_sat(syn_out, syn_out); if (shift == 2) { syn_out = ixheaacd_add32_sat(syn_out, syn_out); } sample_buffer[ch_fac * k] = (syn_out >> 16); } } void ixheaacd_sbr_pre_twiddle(WORD32 *p_xre, WORD32 *p_xim, WORD16 *p_twiddles) { int k; for (k = 62; k >= 0; k--) { WORD32 x_re = *p_xre; WORD32 x_im = *p_xim; WORD16 ixheaacd_cosine = *p_twiddles++; WORD16 ixheaacd_sine = *p_twiddles++; WORD32 re, im; re = ixheaacd_mac32x16in32_shl( ixheaacd_mult32x16in32_shl(x_re, ixheaacd_cosine), x_im, ixheaacd_sine); im = ixheaacd_sub32(ixheaacd_mult32x16in32_shl(x_im, ixheaacd_cosine), ixheaacd_mult32x16in32_shl(x_re, ixheaacd_sine)); *p_xre++ = re; *p_xim++ = im; } } VOID ixheaacd_cplx_synt_qmffilt( WORD32 **qmf_real, WORD32 **qmf_imag, WORD32 split, ia_sbr_scale_fact_struct *sbr_scale_factor, WORD16 *time_out, ia_sbr_qmf_filter_bank_struct *qmf_bank, ia_ps_dec_struct *ptr_ps_dec, FLAG active, FLAG low_pow_flag, ia_sbr_tables_struct *sbr_tables_ptr, ixheaacd_misc_tables *pstr_common_tables, WORD32 ch_fac, FLAG drc_on, WORD32 drc_sbr_factors[][64], WORD32 audio_object_type) { WORD32 i; WORD32 code_scale_factor; WORD32 scale_factor; WORD32 out_scale_factor; WORD32 low_band_scale_factor; WORD32 high_band_scale_factor; WORD16 *filter_states = qmf_bank->filter_states; WORD32 **ptr_qmf_imag_temp; WORD32 qmf_real2[2 * NO_SYNTHESIS_CHANNELS]; WORD32 no_synthesis_channels = qmf_bank->no_channels; WORD32 p1; WORD16 *fp1; WORD16 *fp2; WORD32 sixty4 = NO_SYNTHESIS_CHANNELS; WORD32 thirty2 = qmf_bank->no_channels; WORD16 *filter_coeff; WORD32 num_time_slots = qmf_bank->num_time_slots; WORD32 ixheaacd_drc_offset; WORD32 ov_lb_scale = sbr_scale_factor->ov_lb_scale; WORD32 lb_scale = sbr_scale_factor->lb_scale; WORD32 st_syn_scale = sbr_scale_factor->st_syn_scale; WORD32 ov_lb_shift, lb_shift, hb_shift; WORD32 *qmf_real_tmp = qmf_real2; WORD32 *qmf_imag_tmp = &qmf_real2[NO_SYNTHESIS_CHANNELS]; WORD32 env = 0; WORD32 common_shift; if (no_synthesis_channels == 32) { qmf_bank->cos_twiddle = (WORD16 *)sbr_tables_ptr->qmf_dec_tables_ptr->sbr_sin_cos_twiddle_l32; qmf_bank->alt_sin_twiddle = (WORD16 *)sbr_tables_ptr->qmf_dec_tables_ptr->sbr_alt_sin_twiddle_l32; qmf_bank->t_cos = (WORD16 *) sbr_tables_ptr->qmf_dec_tables_ptr->sbr_cos_sin_twiddle_ds_l32; } else { qmf_bank->cos_twiddle = (WORD16 *)sbr_tables_ptr->qmf_dec_tables_ptr->sbr_sin_cos_twiddle_l64; qmf_bank->alt_sin_twiddle = (WORD16 *)sbr_tables_ptr->qmf_dec_tables_ptr->sbr_alt_sin_twiddle_l64; } if (audio_object_type != AOT_ER_AAC_ELD && audio_object_type != AOT_ER_AAC_LD) { qmf_bank->filter_pos_syn += (sbr_tables_ptr->qmf_dec_tables_ptr->qmf_c - qmf_bank->p_filter); qmf_bank->p_filter = sbr_tables_ptr->qmf_dec_tables_ptr->qmf_c; } else { qmf_bank->filter_pos_syn += (sbr_tables_ptr->qmf_dec_tables_ptr->qmf_c_eld - qmf_bank->p_filter); qmf_bank->p_filter = sbr_tables_ptr->qmf_dec_tables_ptr->qmf_c_eld; } fp1 = &filter_states[0]; fp2 = fp1 + no_synthesis_channels; if (audio_object_type == AOT_ER_AAC_ELD || audio_object_type == AOT_ER_AAC_LD) { fp1 = qmf_bank->fp1_syn; fp2 = qmf_bank->fp2_syn; sixty4 = qmf_bank->sixty4; } filter_coeff = qmf_bank->filter_pos_syn; if (active) { code_scale_factor = scale_factor = sbr_scale_factor->ps_scale; } else { code_scale_factor = ixheaacd_min32(lb_scale, ov_lb_scale); scale_factor = sbr_scale_factor->hb_scale; } low_band_scale_factor = (st_syn_scale - code_scale_factor); high_band_scale_factor = (st_syn_scale - scale_factor); p1 = 0; if (low_pow_flag) { ov_lb_shift = (st_syn_scale - ov_lb_scale) - 4; lb_shift = (st_syn_scale - lb_scale) - 4; hb_shift = high_band_scale_factor - 4; out_scale_factor = -((sbr_scale_factor->st_syn_scale - 1)); ptr_qmf_imag_temp = 0; } else { out_scale_factor = -((sbr_scale_factor->st_syn_scale - 3)); if (active) { ov_lb_shift = (sbr_scale_factor->ps_scale - ov_lb_scale); lb_shift = (sbr_scale_factor->ps_scale - lb_scale); hb_shift = (sbr_scale_factor->ps_scale - sbr_scale_factor->hb_scale); common_shift = low_band_scale_factor - 8; } else { if (audio_object_type != AOT_ER_AAC_ELD && audio_object_type != AOT_ER_AAC_LD) { ov_lb_shift = (st_syn_scale - ov_lb_scale) - 8; lb_shift = (st_syn_scale - lb_scale) - 8; hb_shift = high_band_scale_factor - 8; } else { ov_lb_shift = (st_syn_scale - ov_lb_scale) - 7; lb_shift = (st_syn_scale - lb_scale) - 7; hb_shift = high_band_scale_factor - 7; } common_shift = 0; } ptr_qmf_imag_temp = qmf_imag; } { if (ov_lb_shift == lb_shift) { (*ixheaacd_adjust_scale)(qmf_real, ptr_qmf_imag_temp, 0, qmf_bank->lsb, 0, num_time_slots, ov_lb_shift, low_pow_flag); } else { (*ixheaacd_adjust_scale)(qmf_real, ptr_qmf_imag_temp, 0, qmf_bank->lsb, 0, split, ov_lb_shift, low_pow_flag); (*ixheaacd_adjust_scale)(qmf_real, ptr_qmf_imag_temp, 0, qmf_bank->lsb, split, num_time_slots, lb_shift, low_pow_flag); } (*ixheaacd_adjust_scale)(qmf_real, ptr_qmf_imag_temp, qmf_bank->lsb, qmf_bank->usb, 0, num_time_slots, hb_shift, low_pow_flag); } ixheaacd_drc_offset = qmf_bank->ixheaacd_drc_offset; if (1 == drc_on) { for (i = 0; i < num_time_slots; i++) { WORD32 loop_val; for (loop_val = 0; loop_val < 64; loop_val++) { qmf_real[i][loop_val] = ixheaacd_mult32x32in32_shift25( qmf_real[i][loop_val], drc_sbr_factors[6 + i][loop_val]); } } } if (low_pow_flag) { WORD16 *fptemp; VOID(*sbr_qmf_syn_winadd) (WORD16 *, WORD16 *, WORD16 *, WORD16 *, FLAG, WORD32); ia_qmf_dec_tables_struct *qmf_tab_ptr = sbr_tables_ptr->qmf_dec_tables_ptr; if (no_synthesis_channels == NO_SYNTHESIS_CHANNELS_DOWN_SAMPLED) sbr_qmf_syn_winadd = ixheaacd_sbr_qmfsyn32_winadd; else sbr_qmf_syn_winadd = ixheaacd_sbr_qmfsyn64_winadd; for (i = 0; i < num_time_slots; i++) { ixheaacd_inv_modulation_lp(qmf_real[i], &filter_states[ixheaacd_drc_offset], qmf_bank, qmf_tab_ptr); sbr_qmf_syn_winadd(fp1, fp2, filter_coeff, &time_out[ch_fac * p1], 2, ch_fac); ixheaacd_drc_offset -= no_synthesis_channels << 1; if (ixheaacd_drc_offset < 0) ixheaacd_drc_offset += ((no_synthesis_channels << 1) * 10); fptemp = fp1; fp1 = fp2; fp2 = fptemp; filter_coeff += 64; if (filter_coeff == qmf_bank->p_filter + 640) filter_coeff = (WORD16 *)qmf_bank->p_filter; p1 += no_synthesis_channels; } } else { for (i = 0; i < num_time_slots; i++) { WORD32 *t_qmf_imag; t_qmf_imag = qmf_imag[i]; if (active) { if (i == ptr_ps_dec->border_position[env]) { ixheaacd_init_rot_env(ptr_ps_dec, (WORD16)env, qmf_bank->usb, sbr_tables_ptr, pstr_common_tables->trig_data); env++; } ixheaacd_apply_ps(ptr_ps_dec, &qmf_real[i], &qmf_imag[i], qmf_real_tmp, qmf_imag_tmp, sbr_scale_factor, (WORD16)i, sbr_tables_ptr); } if (1 == drc_on) { WORD32 loop_val; for (loop_val = 0; loop_val < 64; loop_val++) { qmf_real[i][loop_val] = ixheaacd_mult32x32in32_shift25( qmf_real[i][loop_val], drc_sbr_factors[6 + i][loop_val]); } } if (active) { if (common_shift) ixheaacd_shiftrountine(qmf_real[i], t_qmf_imag, no_synthesis_channels, common_shift); } if (audio_object_type == AOT_ER_AAC_ELD || audio_object_type == AOT_ER_AAC_LD) ixheaacd_sbr_pre_twiddle( qmf_real[i], t_qmf_imag, sbr_tables_ptr->qmf_dec_tables_ptr->ixheaacd_sbr_synth_cos_sin_l32); ixheaacd_inv_emodulation(qmf_real[i], qmf_bank, sbr_tables_ptr->qmf_dec_tables_ptr); { WORD32 temp_out_scale_fac = out_scale_factor + 1; if (audio_object_type == AOT_ER_AAC_LD || audio_object_type == AOT_ER_AAC_ELD) { temp_out_scale_fac = temp_out_scale_fac - 1; ixheaacd_shiftrountine_with_rnd_eld( qmf_real[i], t_qmf_imag, &filter_states[ixheaacd_drc_offset], no_synthesis_channels, temp_out_scale_fac); } else { ixheaacd_shiftrountine_with_rnd( qmf_real[i], t_qmf_imag, &filter_states[ixheaacd_drc_offset], no_synthesis_channels, temp_out_scale_fac); } } if (no_synthesis_channels == NO_SYNTHESIS_CHANNELS_DOWN_SAMPLED) { WORD32 temp = 1; if (audio_object_type == AOT_ER_AAC_LD || audio_object_type == AOT_ER_AAC_ELD) { temp = 2; } ixheaacd_sbr_qmfsyn32_winadd(fp1, fp2, filter_coeff, &time_out[ch_fac * p1], temp, ch_fac); fp1 += thirty2; fp2 -= thirty2; thirty2 = -thirty2; ixheaacd_drc_offset -= 64; if (ixheaacd_drc_offset < 0) ixheaacd_drc_offset += 640; } else { WORD32 temp = 1; if (audio_object_type == AOT_ER_AAC_LD || audio_object_type == AOT_ER_AAC_ELD) { temp = 2; } ixheaacd_sbr_qmfsyn64_winadd(fp1, fp2, filter_coeff, &time_out[ch_fac * p1], temp, ch_fac); fp1 += sixty4; fp2 -= sixty4; sixty4 = -sixty4; ixheaacd_drc_offset -= 128; if (ixheaacd_drc_offset < 0) ixheaacd_drc_offset += 1280; } filter_coeff += 64; if (filter_coeff == qmf_bank->p_filter + 640) filter_coeff = (WORD16 *)qmf_bank->p_filter; p1 += no_synthesis_channels; if (active) memcpy(qmf_real[i], qmf_real_tmp, 2 * no_synthesis_channels * sizeof(WORD32)); } } if (audio_object_type == AOT_ER_AAC_LD || audio_object_type == AOT_ER_AAC_ELD) { qmf_bank->fp1_syn = fp1; qmf_bank->fp2_syn = fp2; qmf_bank->sixty4 = sixty4; } qmf_bank->filter_pos_syn = filter_coeff; qmf_bank->ixheaacd_drc_offset = ixheaacd_drc_offset; }