| /****************************************************************************** |
| * * |
| * 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 <stdlib.h> |
| #include <string.h> |
| #include <math.h> |
| |
| #include "ixheaacd_type_def.h" |
| #include "ixheaacd_bitbuffer.h" |
| #include "ixheaacd_interface.h" |
| #include "ixheaacd_tns_usac.h" |
| #include "ixheaacd_cnst.h" |
| #include "ixheaacd_acelp_info.h" |
| #include "ixheaacd_td_mdct.h" |
| #include "ixheaacd_sbrdecsettings.h" |
| #include "ixheaacd_info.h" |
| #include "ixheaacd_sbr_common.h" |
| #include "ixheaacd_drc_data_struct.h" |
| #include "ixheaacd_drc_dec.h" |
| #include "ixheaacd_sbrdecoder.h" |
| #include "ixheaacd_mps_polyphase.h" |
| #include "ixheaacd_sbr_const.h" |
| #include "ixheaacd_main.h" |
| #include "ixheaacd_arith_dec.h" |
| #include "ixheaacd_windows.h" |
| #include "ixheaacd_constants.h" |
| #include "ixheaacd_basic_ops32.h" |
| #include "ixheaacd_basic_ops40.h" |
| #include "ixheaacd_func_def.h" |
| #include "ixheaacd_acelp_com.h" |
| |
| static PLATFORM_INLINE WORD32 ixheaacd_mult32_m(WORD32 a, WORD32 b) { |
| WORD32 result; |
| WORD64 temp_result; |
| |
| temp_result = (WORD64)a * (WORD64)b; |
| result = (WORD32)(temp_result >> 31); |
| |
| return (result); |
| } |
| |
| static VOID ixheaacd_weighted_synthesis_filter(WORD32 *a, WORD32 *ap) { |
| WORD32 f; |
| WORD32 i; |
| ap[0] = a[0]; |
| f = IGAMMA1; |
| for (i = 1; i <= ORDER; i++) { |
| ap[i] = ixheaacd_mult32_m(f, a[i]); |
| f = ixheaacd_mult32_m(f, IGAMMA1); |
| } |
| return; |
| } |
| |
| static VOID ixheaacd_synthesis_tool(WORD32 a[], WORD32 x[], WORD32 l, |
| WORD32 qshift, WORD32 *preshift) { |
| WORD32 s; |
| WORD32 i, j; |
| |
| for (i = 0; i < l; i++) { |
| s = x[i]; |
| for (j = 1; j <= ORDER; j += 4) { |
| s = ixheaacd_sub32_sat( |
| s, ixheaacd_mul32_sh(a[j], x[i - j], (WORD8)(qshift))); |
| s = ixheaacd_sub32_sat( |
| s, ixheaacd_mul32_sh(a[j + 1], x[i - (j + 1)], (WORD8)(qshift))); |
| s = ixheaacd_sub32_sat( |
| s, ixheaacd_mul32_sh(a[j + 2], x[i - (j + 2)], (WORD8)(qshift))); |
| s = ixheaacd_sub32_sat( |
| s, ixheaacd_mul32_sh(a[j + 3], x[i - (j + 3)], (WORD8)(qshift))); |
| } |
| x[i] = s; |
| } |
| |
| (*preshift)++; |
| return; |
| } |
| |
| WORD32 ixheaacd_fwd_alias_cancel_tool( |
| ia_usac_data_struct *usac_data, ia_td_frame_data_struct *pstr_td_frame_data, |
| WORD32 fac_length, FLOAT32 *lp_filt_coeff, WORD32 gain) { |
| WORD32 i; |
| FLOAT32 lp_filt_coeff_a[ORDER + 1]; |
| WORD32 qshift = 0; |
| WORD32 err = 0; |
| |
| WORD32 *x_in = pstr_td_frame_data->fac_data; |
| WORD32 *ptr_scratch = &usac_data->scratch_buffer[0]; |
| WORD32 *fac_signal = &usac_data->x_ac_dec[16]; |
| FLOAT32 fac_signal_flt[128 + 16]; |
| FLOAT32 *ptr_fac_signal_flt = &fac_signal_flt[16]; |
| WORD32 *ptr_overlap_buf = |
| &(usac_data->overlap_data_ptr[usac_data->present_chan] |
| [(usac_data->ccfl / 2) - fac_length]); |
| |
| memset(fac_signal - 16, 0, ORDER * sizeof(WORD32)); |
| |
| err = ixheaacd_acelp_mdct(x_in, fac_signal, &qshift, fac_length, ptr_scratch); |
| if (err == -1) return err; |
| |
| ixheaacd_lpc_coeff_wt_apply(lp_filt_coeff, lp_filt_coeff_a); |
| |
| for (i = 0; i < fac_length; i++) |
| ptr_fac_signal_flt[i] = |
| (FLOAT32)((FLOAT32)fac_signal[i] / (1 << (16 - qshift))); |
| |
| memset(ptr_fac_signal_flt - 16, 0, 16 * sizeof(FLOAT32)); |
| |
| ixheaacd_synthesis_tool_float1(lp_filt_coeff_a, ptr_fac_signal_flt, |
| fac_length); |
| |
| for (i = 0; i < fac_length; i++) |
| fac_signal[i] = (WORD32)(ptr_fac_signal_flt[i] * (1 << (16 - qshift))); |
| |
| for (i = 0; i < fac_length; i++) |
| ptr_overlap_buf[i] = ixheaacd_add32_sat( |
| ptr_overlap_buf[i], |
| (WORD32)ixheaacd_mul32_sh(fac_signal[i], gain, (WORD8)(16 - qshift))); |
| |
| return err; |
| } |
| |
| WORD32 ixheaacd_fr_alias_cnx_fix(WORD32 *x_in, WORD32 len, WORD32 fac_length, |
| WORD32 *lp_filt_coeff, WORD32 *izir, |
| WORD32 *fac_data_out, WORD8 *qshift1, |
| WORD8 qshift2, WORD8 qshift3, WORD32 *preshift, |
| WORD32 *ptr_scratch) { |
| WORD32 i; |
| const WORD32 *sine_window; |
| WORD32 fac_window[2 * FAC_LENGTH]; |
| WORD32 lp_filt_coeff_a[ORDER + 1]; |
| WORD32 err = 0; |
| |
| if (fac_length == 48) { |
| sine_window = ixheaacd_sine_win_96; |
| } else if (fac_length == 64) { |
| sine_window = ixheaacd_sine_win_128; |
| } else if (fac_length == 96) { |
| sine_window = ixheaacd_sine_win_192; |
| } else { |
| sine_window = ixheaacd_sine_win_256; |
| } |
| if (FAC_LENGTH < fac_length) { |
| return -1; |
| } |
| |
| if (FAC_LENGTH < fac_length) { |
| return -1; |
| } |
| if ((1 + (len / 2)) < (fac_length + 1)) { |
| return -1; |
| } |
| if ((len / 2 + 1) > (2 * LEN_FRAME - fac_length - 1)) { |
| return -1; |
| } |
| |
| if (lp_filt_coeff != NULL && fac_data_out != NULL) { |
| memset(fac_data_out - 16, 0, ORDER * sizeof(WORD32)); |
| err = ixheaacd_acelp_mdct(x_in, fac_data_out, preshift, fac_length, |
| ptr_scratch); |
| if (err == -1) return err; |
| |
| ixheaacd_weighted_synthesis_filter(lp_filt_coeff, lp_filt_coeff_a); |
| |
| memset(fac_data_out + fac_length, 0, fac_length * sizeof(WORD32)); |
| |
| ixheaacd_synthesis_tool(lp_filt_coeff_a, fac_data_out, 2 * fac_length, |
| qshift2, preshift); |
| |
| if (izir != NULL) { |
| for (i = 0; i < fac_length; i++) { |
| fac_window[i] = ixheaacd_mult32_m( |
| sine_window[i], sine_window[(2 * fac_length) - 1 - i]); |
| fac_window[fac_length + i] = |
| 2147483647 - ixheaacd_mult32_m(sine_window[fac_length + i], |
| sine_window[fac_length + i]); |
| } |
| for (i = 0; i < fac_length; i++) { |
| WORD32 temp1; |
| WORD32 temp2; |
| |
| temp1 = ixheaacd_mul32_sh( |
| izir[1 + (len / 2) + i], fac_window[fac_length + i], |
| (char)((qshift3 - *qshift1 + 31 + (WORD8)(*preshift)))); |
| |
| temp2 = ixheaacd_mul32_sh( |
| izir[1 + (len / 2) - 1 - i], fac_window[fac_length - 1 - i], |
| (char)((qshift3 - *qshift1 + 31 + (WORD8)(*preshift)))); |
| |
| fac_data_out[i] = |
| ixheaacd_add32_sat3((fac_data_out[i] / 2), temp1, temp2); |
| |
| fac_data_out[fac_length + i] = (fac_data_out[fac_length + i] / 2); |
| } |
| } |
| } |
| |
| return err; |
| } |