/****************************************************************************** * * * 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 #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_func_def.h" #include "ixheaacd_constants.h" #include "ixheaacd_basic_ops32.h" #include "ixheaacd_basic_ops40.h" extern const WORD32 ixheaacd_pre_post_twid_cos_sin_512[4][512]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_384[4][384]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_256[4][256]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_192[4][192]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_128[4][128]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_96[4][96]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_64[4][64]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_48[4][48]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_32[4][32]; extern const WORD32 ixheaacd_pre_post_twid_cos_sin_24[4][24]; static PLATFORM_INLINE WORD32 ixheaacd_mul_sub64_sat_32(WORD32 a, WORD32 b, WORD32 c, WORD32 d) { WORD64 diff; WORD64 temp_result1; WORD64 temp_result2; temp_result1 = (WORD64)a * (WORD64)c; temp_result2 = (WORD64)b * (WORD64)d; diff = (temp_result1 - temp_result2) >> 32; if (diff >= 2147483647) diff = 2147483647; else if (diff <= -2147483647 - 1) diff = -2147483647 - 1; return ((WORD32)diff); } static PLATFORM_INLINE WORD32 ixheaacd_mul_add64_sat_32(WORD32 a, WORD32 b, WORD32 c, WORD32 d) { WORD64 sum; WORD64 temp_result1; WORD64 temp_result2; temp_result1 = (WORD64)a * (WORD64)c; temp_result2 = (WORD64)b * (WORD64)d; sum = (temp_result1 + temp_result2) >> 32; if (sum >= 2147483647) sum = 2147483647; else if (sum <= -2147483647 - 1) sum = -2147483647 - 1; return ((WORD32)sum); } static void ixheaacd_pre_twid(WORD32 *in, WORD32 *r_ptr, WORD32 *i_ptr, WORD32 nlength, const WORD32 *ptr_pre_cos_sin) { WORD32 i; const WORD32 *cos_ptr = &ptr_pre_cos_sin[0]; const WORD32 *sin_ptr = &ptr_pre_cos_sin[nlength]; for (i = 0; i < nlength; i += 4) { *r_ptr++ = ixheaacd_mul_sub64_sat_32(in[i], in[nlength + i], cos_ptr[i], sin_ptr[i]); *i_ptr++ = ixheaacd_mul_add64_sat_32(in[i], in[nlength + i], sin_ptr[i], cos_ptr[i]); *r_ptr++ = ixheaacd_mul_sub64_sat_32(in[i + 1], in[nlength + i + 1], cos_ptr[i + 1], sin_ptr[i + 1]); *i_ptr++ = ixheaacd_mul_add64_sat_32(in[i + 1], in[nlength + i + 1], sin_ptr[i + 1], cos_ptr[i + 1]); *r_ptr++ = ixheaacd_mul_sub64_sat_32(in[i + 2], in[nlength + i + 2], cos_ptr[i + 2], sin_ptr[i + 2]); *i_ptr++ = ixheaacd_mul_add64_sat_32(in[i + 2], in[nlength + i + 2], sin_ptr[i + 2], cos_ptr[i + 2]); *r_ptr++ = ixheaacd_mul_sub64_sat_32(in[i + 3], in[nlength + i + 3], cos_ptr[i + 3], sin_ptr[i + 3]); *i_ptr++ = ixheaacd_mul_add64_sat_32(in[i + 3], in[nlength + i + 3], sin_ptr[i + 3], cos_ptr[i + 3]); } } static void ixheaacd_post_twid(WORD32 *data_re, WORD32 *data_im, WORD32 *out, WORD32 nlength, const WORD32 *ptr_post_cos_sin) { WORD32 i; const WORD32 *cos_ptr = &ptr_post_cos_sin[nlength * 2]; const WORD32 *sin_ptr = &ptr_post_cos_sin[nlength * 3]; WORD32 *out_ptr = &out[2 * nlength - 1]; for (i = 0; i < nlength; i += 4) { out[0] = ixheaacd_mul_sub64_sat_32(data_re[i], data_im[i], cos_ptr[i], sin_ptr[i]); out_ptr[0] = -ixheaacd_mul_add64_sat_32(data_re[i], data_im[i], sin_ptr[i], cos_ptr[i]); out[2] = ixheaacd_mul_sub64_sat_32(data_re[i + 1], data_im[i + 1], cos_ptr[i + 1], sin_ptr[i + 1]); out_ptr[-2] = -ixheaacd_mul_add64_sat_32(data_re[i + 1], data_im[i + 1], sin_ptr[i + 1], cos_ptr[i + 1]); out[4] = ixheaacd_mul_sub64_sat_32(data_re[i + 2], data_im[i + 2], cos_ptr[i + 2], sin_ptr[i + 2]); out_ptr[-4] = -ixheaacd_mul_add64_sat_32(data_re[i + 2], data_im[i + 2], sin_ptr[i + 2], cos_ptr[i + 2]); out[6] = ixheaacd_mul_sub64_sat_32(data_re[i + 3], data_im[i + 3], cos_ptr[i + 3], sin_ptr[i + 3]); out_ptr[-6] = -ixheaacd_mul_add64_sat_32(data_re[i + 3], data_im[i + 3], sin_ptr[i + 3], cos_ptr[i + 3]); out += 8; out_ptr -= 8; } } WORD32 ixheaacd_acelp_mdct(WORD32 *ptr_in, WORD32 *ptr_out, WORD32 *preshift, WORD32 length, WORD32 *ptr_scratch) { WORD32 *ptr_data_r = ptr_scratch; WORD32 *ptr_data_i = ptr_scratch + 512; const WORD32 *ptr_pre_post_twid; WORD32 err = 0; switch (length) { case 1024: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_512[0][0]; break; case 768: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_384[0][0]; break; case 512: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_256[0][0]; break; case 384: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_192[0][0]; break; case 256: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_128[0][0]; break; case 192: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_96[0][0]; break; case 128: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_64[0][0]; break; case 96: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_48[0][0]; break; case 64: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_32[0][0]; break; case 48: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_24[0][0]; break; default: ptr_pre_post_twid = &ixheaacd_pre_post_twid_cos_sin_24[0][0]; break; } ixheaacd_pre_twid(ptr_in, ptr_data_r, ptr_data_i, length / 2, ptr_pre_post_twid); ixheaacd_complex_fft(ptr_data_r, ptr_data_i, length / 2, -1, preshift); *preshift += 1; ixheaacd_post_twid(ptr_data_r, ptr_data_i, ptr_out, length / 2, ptr_pre_post_twid); *preshift += 1; return err; } WORD32 ixheaacd_acelp_mdct_main(ia_usac_data_struct *usac_data, WORD32 *in, WORD32 *out, WORD32 l, WORD32 m, WORD32 *preshift) { WORD32 i; WORD32 *ptr_scratch = &usac_data->scratch_buffer[0]; WORD32 *output_buffer = &usac_data->x_ac_dec[0]; WORD32 err = 0; err = ixheaacd_acelp_mdct(in, output_buffer, preshift, l + m, ptr_scratch); if (err == -1) return err; for (i = 0; i < m / 2; i++) { out[l + m / 2 - 1 - i] = -output_buffer[m / 2 + l / 2 + i]; } for (i = 0; i < l / 2; i++) { out[i] = output_buffer[m + l / 2 + i]; out[l - 1 - i] = -output_buffer[m + l / 2 + i]; } for (i = 0; i < m / 2; i++) { out[l + m / 2 + i] = -output_buffer[m / 2 + l / 2 - 1 - i]; } for (i = 0; i < l / 2; i++) { out[l + m + i] = -output_buffer[l / 2 - 1 - i]; out[2 * l + m - 1 - i] = -output_buffer[l / 2 - 1 - i]; } return err; }