| /****************************************************************************** |
| * * |
| * 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 <stdio.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_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_function_selector.h" |
| #include <ixheaacd_constants.h> |
| #include <ixheaacd_basic_ops32.h> |
| #include <ixheaacd_basic_ops40.h> |
| |
| #define sfb_offset(x) (((x) > 0) ? sfb_top[(x)-1] : 0) |
| |
| static VOID ixheaacd_tns_dec_coef_usac(ia_usac_data_struct *usac_data, |
| ia_tns_filter_struct *filter, |
| WORD32 coef_res, WORD32 *par_coeff) { |
| WORD32 resolution; |
| WORD32 *ptr_par_coeff = par_coeff; |
| const WORD32 *tns_coeff_ptr; |
| WORD32 ixheaacd_drc_offset = 4; |
| WORD16 *ptr_coeff = filter->coef; |
| WORD32 order; |
| |
| resolution = coef_res - 3; |
| tns_coeff_ptr = usac_data->tns_coeff3_32; |
| if (resolution) { |
| tns_coeff_ptr = usac_data->tns_coeff4_32; |
| ixheaacd_drc_offset = ixheaacd_drc_offset << 1; |
| } |
| order = filter->order; |
| |
| do { |
| WORD16 temp = *ptr_coeff++; |
| *ptr_par_coeff++ = tns_coeff_ptr[temp + ixheaacd_drc_offset]; |
| order--; |
| } while (order != 0); |
| } |
| |
| static VOID ixheaacd_tns_parcor_lpc_convert_usac(WORD32 *parcor, |
| WORD32 *lpc_coeff, |
| WORD32 *scale, WORD order) |
| |
| { |
| WORD i, j, status; |
| WORD32 accu; |
| WORD32 temp_buf1[TNS_MAX_ORDER + 1]; |
| WORD32 temp_buf2[TNS_MAX_ORDER + 1]; |
| WORD32 accu1, accu2; |
| |
| status = 1; |
| *scale = 1; |
| |
| while (status) { |
| status = 0; |
| |
| for (i = TNS_MAX_ORDER; i >= 0; i--) { |
| temp_buf1[i] = 0; |
| temp_buf2[i] = 0; |
| } |
| |
| accu1 = (0x40000000 >> (*scale - 1)); |
| |
| for (i = 0; i <= order; i++) { |
| accu = accu1; |
| |
| for (j = 0; j < order; j++) { |
| temp_buf2[j] = (accu1); |
| |
| accu1 = ixheaacd_add32_sat( |
| accu1, ixheaacd_mult32_shl_sat(parcor[j], temp_buf1[j])); |
| if (ixheaacd_abs32_sat(accu1) == 0x7fffffff) status = 1; |
| } |
| |
| for (j = (order - 1); j >= 0; j--) { |
| accu2 = (temp_buf1[j]); |
| accu2 = ixheaacd_add32_sat( |
| accu2, ixheaacd_mult32_shl_sat(parcor[j], temp_buf2[j])); |
| temp_buf1[j + 1] = (accu2); |
| |
| if (ixheaacd_abs32_sat(accu2) == 0x7fffffff) status = 1; |
| } |
| |
| temp_buf1[0] = (accu); |
| lpc_coeff[i] = (accu1); |
| accu1 = 0; |
| } |
| |
| accu1 = (status - 1); |
| |
| if (accu1 == 0) { |
| *scale = *scale + 1; |
| } |
| } |
| } |
| |
| static VOID ixheaacd_tns_ar_filter_usac(WORD32 *spectrum, WORD32 size, |
| WORD32 inc, WORD32 *lpc_coeff, |
| WORD32 order, WORD32 shift_value, |
| WORD32 *ptr_filter_state) { |
| WORD32 i, j; |
| WORD32 y; |
| WORD64 acc; |
| |
| if ((order & 3) != 0) { |
| for (i = order + 1; i < ((WORD32)(order & 0xfffffffc) + 4); i++) { |
| lpc_coeff[i] = 0; |
| } |
| lpc_coeff[i] = 0; |
| order = ((order & 0xfffffffc) + 4); |
| } |
| |
| for (i = 0; i < order; i++) { |
| y = *spectrum; |
| acc = 0; |
| |
| for (j = i; j > 0; j--) { |
| acc = ixheaacd_add64_sat( |
| acc, ixheaacd_mult64(ptr_filter_state[j - 1], lpc_coeff[j])); |
| ptr_filter_state[j] = ptr_filter_state[j - 1]; |
| } |
| |
| y = ixheaacd_sub32_sat(y, (WORD32)(acc >> 31)); |
| ptr_filter_state[0] = ixheaacd_shl32(y, shift_value); |
| *spectrum = y; |
| spectrum += inc; |
| } |
| |
| for (i = order; i < size; i++) { |
| y = *spectrum; |
| acc = 0; |
| for (j = order; j > 0; j--) { |
| acc = ixheaacd_add64_sat( |
| acc, ixheaacd_mult64(ptr_filter_state[j - 1], lpc_coeff[j])); |
| ; |
| ptr_filter_state[j] = ptr_filter_state[j - 1]; |
| } |
| y = ixheaacd_sub32_sat(y, (WORD32)(acc >> 31)); |
| ptr_filter_state[0] = ixheaacd_shl32(y, shift_value); |
| *spectrum = y; |
| spectrum += inc; |
| } |
| } |
| |
| VOID ixheaacd_tns_apply(ia_usac_data_struct *usac_data, WORD32 *spec, |
| WORD32 nbands, ia_sfb_info_struct *pstr_sfb_info, |
| ia_tns_frame_info_struct *pstr_tns) { |
| WORD32 f, max_order, start, stop, size, inc; |
| WORD32 n_filt, coef_res, order, direction; |
| WORD32 *ptr_spec; |
| WORD32 scale_spec; |
| WORD32 scale_lpc; |
| WORD32 guard_band; |
| WORD32 shift; |
| WORD32 lpc_coeff[TNS_MAX_ORDER + 1]; |
| WORD32 par_coeff[TNS_MAX_ORDER + 1]; |
| ia_tns_filter_struct *filt; |
| |
| const WORD16 *sfb_top; |
| |
| WORD32 nbins = (pstr_sfb_info->islong) ? 1024 : 128; |
| WORD32 i, j, idx; |
| |
| max_order = (pstr_sfb_info->islong) ? 15 : 7; |
| idx = (pstr_sfb_info->islong) ? 0 : 1; |
| |
| ptr_spec = &usac_data->scratch_buffer[0]; |
| |
| for (j = 0; j < pstr_tns->n_subblocks; j++) { |
| sfb_top = pstr_sfb_info->ptr_sfb_tbl; |
| |
| for (i = 0; i < nbins; i++) { |
| ptr_spec[i] = spec[i]; |
| } |
| |
| if (pstr_tns->str_tns_info[j].n_filt) { |
| n_filt = pstr_tns->str_tns_info[j].n_filt; |
| |
| for (f = 0; f < n_filt; f++) { |
| WORD32 tmp; |
| |
| coef_res = pstr_tns->str_tns_info[j].coef_res; |
| filt = &pstr_tns->str_tns_info[j].str_filter[f]; |
| order = filt->order; |
| direction = filt->direction; |
| start = filt->start_band; |
| stop = filt->stop_band; |
| |
| if (order > max_order) { |
| fprintf(stderr, "Error in tns max order: %d %d\n", order, max_order); |
| } |
| |
| if (!order) continue; |
| |
| ixheaacd_tns_dec_coef_usac(usac_data, filt, coef_res, |
| (WORD32 *)par_coeff); |
| |
| ixheaacd_tns_parcor_lpc_convert_usac(par_coeff, lpc_coeff, &scale_lpc, |
| filt->order); |
| |
| tmp = (*usac_data->tns_max_bands_tbl_usac)[usac_data->sampling_rate_idx] |
| [idx]; |
| |
| start = ixheaacd_min32(start, tmp); |
| |
| start = ixheaacd_min32(start, nbands); |
| start = sfb_offset(start); |
| |
| stop = ixheaacd_min32(stop, tmp); |
| stop = ixheaacd_min32(stop, nbands); |
| stop = sfb_offset(stop); |
| |
| guard_band = 31 - ixheaacd_norm32(filt->order); |
| |
| if ((size = stop - start) <= 0) continue; |
| |
| if (direction) { |
| inc = -1; |
| shift = stop - 1; |
| } |
| |
| else { |
| inc = 1; |
| shift = start; |
| } |
| |
| { |
| WORD32 *ptr_temp = ptr_spec + start; |
| scale_spec = (*ixheaacd_calc_max_spectral_line)(ptr_temp, size); |
| } |
| |
| scale_spec = ((scale_spec - guard_band) - scale_lpc); |
| |
| if (scale_spec > 0) { |
| ixheaacd_tns_ar_filter_usac(&ptr_spec[shift], size, inc, lpc_coeff, |
| filt->order, scale_lpc, |
| usac_data->x_ac_dec); |
| } |
| |
| else { |
| WORD32 *ptr_temp = ptr_spec + start; |
| |
| scale_spec = -scale_spec; |
| scale_spec = ixheaacd_min32(scale_spec, 31); |
| |
| for (i = size; i != 0; i--) { |
| *ptr_temp = *ptr_temp >> scale_spec; |
| ptr_temp++; |
| } |
| |
| { |
| ixheaacd_tns_ar_filter_usac(&ptr_spec[shift], size, inc, lpc_coeff, |
| filt->order, scale_lpc, |
| usac_data->x_ac_dec); |
| } |
| |
| { |
| ptr_temp = ptr_spec + start; |
| i = size; |
| |
| do { |
| *ptr_temp = *ptr_temp << scale_spec; |
| ptr_temp++; |
| i--; |
| } while (i != 0); |
| } |
| } |
| |
| for (i = start; i <= stop - 1; i++) { |
| spec[i] = ptr_spec[i]; |
| } |
| } |
| } |
| |
| spec += pstr_sfb_info->bins_per_sbk; |
| } |
| } |