1/******************************************************************************
2 *                                                                            *
3 * Copyright (C) 2018 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19*/
20#include <math.h>
21#include <stdio.h>
22
23#include <ixheaacd_type_def.h>
24#include "ixheaacd_bitbuffer.h"
25
26#include "ixheaacd_interface.h"
27
28#include "ixheaacd_tns_usac.h"
29#include "ixheaacd_cnst.h"
30
31#include "ixheaacd_acelp_info.h"
32
33#include "ixheaacd_sbrdecsettings.h"
34#include "ixheaacd_info.h"
35#include "ixheaacd_sbr_common.h"
36#include "ixheaacd_drc_data_struct.h"
37#include "ixheaacd_drc_dec.h"
38#include "ixheaacd_sbrdecoder.h"
39#include "ixheaacd_mps_polyphase.h"
40#include "ixheaacd_sbr_const.h"
41
42#include "ixheaacd_main.h"
43#include "ixheaacd_arith_dec.h"
44#include "ixheaacd_function_selector.h"
45#include <ixheaacd_constants.h>
46#include <ixheaacd_basic_ops32.h>
47#include <ixheaacd_basic_ops40.h>
48
49#define sfb_offset(x) (((x) > 0) ? sfb_top[(x)-1] : 0)
50
51static VOID ixheaacd_tns_dec_coef_usac(ia_usac_data_struct *usac_data,
52                                       ia_tns_filter_struct *filter,
53                                       WORD32 coef_res, WORD32 *par_coeff) {
54  WORD32 resolution;
55  WORD32 *ptr_par_coeff = par_coeff;
56  const WORD32 *tns_coeff_ptr;
57  WORD32 ixheaacd_drc_offset = 4;
58  WORD16 *ptr_coeff = filter->coef;
59  WORD32 order;
60
61  resolution = coef_res - 3;
62  tns_coeff_ptr = usac_data->tns_coeff3_32;
63  if (resolution) {
64    tns_coeff_ptr = usac_data->tns_coeff4_32;
65    ixheaacd_drc_offset = ixheaacd_drc_offset << 1;
66  }
67  order = filter->order;
68
69  do {
70    WORD16 temp = *ptr_coeff++;
71    *ptr_par_coeff++ = tns_coeff_ptr[temp + ixheaacd_drc_offset];
72    order--;
73  } while (order != 0);
74}
75
76static VOID ixheaacd_tns_parcor_lpc_convert_usac(WORD32 *parcor,
77                                                 WORD32 *lpc_coeff,
78                                                 WORD32 *scale, WORD order)
79
80{
81  WORD i, j, status;
82  WORD32 accu;
83  WORD32 temp_buf1[TNS_MAX_ORDER + 1];
84  WORD32 temp_buf2[TNS_MAX_ORDER + 1];
85  WORD32 accu1, accu2;
86
87  status = 1;
88  *scale = 1;
89
90  while (status) {
91    status = 0;
92
93    for (i = TNS_MAX_ORDER; i >= 0; i--) {
94      temp_buf1[i] = 0;
95      temp_buf2[i] = 0;
96    }
97
98    accu1 = (0x40000000 >> (*scale - 1));
99
100    for (i = 0; i <= order; i++) {
101      accu = accu1;
102
103      for (j = 0; j < order; j++) {
104        temp_buf2[j] = (accu1);
105
106        accu1 = ixheaacd_add32_sat(
107            accu1, ixheaacd_mult32_shl_sat(parcor[j], temp_buf1[j]));
108        if (ixheaacd_abs32_sat(accu1) == 0x7fffffff) status = 1;
109      }
110
111      for (j = (order - 1); j >= 0; j--) {
112        accu2 = (temp_buf1[j]);
113        accu2 = ixheaacd_add32_sat(
114            accu2, ixheaacd_mult32_shl_sat(parcor[j], temp_buf2[j]));
115        temp_buf1[j + 1] = (accu2);
116
117        if (ixheaacd_abs32_sat(accu2) == 0x7fffffff) status = 1;
118      }
119
120      temp_buf1[0] = (accu);
121      lpc_coeff[i] = (accu1);
122      accu1 = 0;
123    }
124
125    accu1 = (status - 1);
126
127    if (accu1 == 0) {
128      *scale = *scale + 1;
129    }
130  }
131}
132
133static VOID ixheaacd_tns_ar_filter_usac(WORD32 *spectrum, WORD32 size,
134                                        WORD32 inc, WORD32 *lpc_coeff,
135                                        WORD32 order, WORD32 shift_value,
136                                        WORD32 *ptr_filter_state) {
137  WORD32 i, j;
138  WORD32 y;
139  WORD64 acc;
140
141  if ((order & 3) != 0) {
142    for (i = order + 1; i < ((WORD32)(order & 0xfffffffc) + 4); i++) {
143      lpc_coeff[i] = 0;
144    }
145    lpc_coeff[i] = 0;
146    order = ((order & 0xfffffffc) + 4);
147  }
148
149  for (i = 0; i < order; i++) {
150    y = *spectrum;
151    acc = 0;
152
153    for (j = i; j > 0; j--) {
154      acc = ixheaacd_add64_sat(
155          acc, ixheaacd_mult64(ptr_filter_state[j - 1], lpc_coeff[j]));
156      ptr_filter_state[j] = ptr_filter_state[j - 1];
157    }
158
159    y = ixheaacd_sub32_sat(y, (WORD32)(acc >> 31));
160    ptr_filter_state[0] = ixheaacd_shl32(y, shift_value);
161    *spectrum = y;
162    spectrum += inc;
163  }
164
165  for (i = order; i < size; i++) {
166    y = *spectrum;
167    acc = 0;
168    for (j = order; j > 0; j--) {
169      acc = ixheaacd_add64_sat(
170          acc, ixheaacd_mult64(ptr_filter_state[j - 1], lpc_coeff[j]));
171      ;
172      ptr_filter_state[j] = ptr_filter_state[j - 1];
173    }
174    y = ixheaacd_sub32_sat(y, (WORD32)(acc >> 31));
175    ptr_filter_state[0] = ixheaacd_shl32(y, shift_value);
176    *spectrum = y;
177    spectrum += inc;
178  }
179}
180
181VOID ixheaacd_tns_apply(ia_usac_data_struct *usac_data, WORD32 *spec,
182                        WORD32 nbands, ia_sfb_info_struct *pstr_sfb_info,
183                        ia_tns_frame_info_struct *pstr_tns) {
184  WORD32 f, max_order, start, stop, size, inc;
185  WORD32 n_filt, coef_res, order, direction;
186  WORD32 *ptr_spec;
187  WORD32 scale_spec;
188  WORD32 scale_lpc;
189  WORD32 guard_band;
190  WORD32 shift;
191  WORD32 lpc_coeff[TNS_MAX_ORDER + 1];
192  WORD32 par_coeff[TNS_MAX_ORDER + 1];
193  ia_tns_filter_struct *filt;
194
195  const WORD16 *sfb_top;
196
197  WORD32 nbins = (pstr_sfb_info->islong) ? 1024 : 128;
198  WORD32 i, j, idx;
199
200  max_order = (pstr_sfb_info->islong) ? 15 : 7;
201  idx = (pstr_sfb_info->islong) ? 0 : 1;
202
203  ptr_spec = &usac_data->scratch_buffer[0];
204
205  for (j = 0; j < pstr_tns->n_subblocks; j++) {
206    sfb_top = pstr_sfb_info->ptr_sfb_tbl;
207
208    for (i = 0; i < nbins; i++) {
209      ptr_spec[i] = spec[i];
210    }
211
212    if (pstr_tns->str_tns_info[j].n_filt) {
213      n_filt = pstr_tns->str_tns_info[j].n_filt;
214
215      for (f = 0; f < n_filt; f++) {
216        WORD32 tmp;
217
218        coef_res = pstr_tns->str_tns_info[j].coef_res;
219        filt = &pstr_tns->str_tns_info[j].str_filter[f];
220        order = filt->order;
221        direction = filt->direction;
222        start = filt->start_band;
223        stop = filt->stop_band;
224
225        if (order > max_order) {
226          fprintf(stderr, "Error in tns max order: %d %d\n", order, max_order);
227        }
228
229        if (!order) continue;
230
231        ixheaacd_tns_dec_coef_usac(usac_data, filt, coef_res,
232                                   (WORD32 *)par_coeff);
233
234        ixheaacd_tns_parcor_lpc_convert_usac(par_coeff, lpc_coeff, &scale_lpc,
235                                             filt->order);
236
237        tmp = (*usac_data->tns_max_bands_tbl_usac)[usac_data->sampling_rate_idx]
238                                                  [idx];
239
240        start = ixheaacd_min32(start, tmp);
241
242        start = ixheaacd_min32(start, nbands);
243        start = sfb_offset(start);
244
245        stop = ixheaacd_min32(stop, tmp);
246        stop = ixheaacd_min32(stop, nbands);
247        stop = sfb_offset(stop);
248
249        guard_band = 31 - ixheaacd_norm32(filt->order);
250
251        if ((size = stop - start) <= 0) continue;
252
253        if (direction) {
254          inc = -1;
255          shift = stop - 1;
256        }
257
258        else {
259          inc = 1;
260          shift = start;
261        }
262
263        {
264          WORD32 *ptr_temp = ptr_spec + start;
265          scale_spec = (*ixheaacd_calc_max_spectral_line)(ptr_temp, size);
266        }
267
268        scale_spec = ((scale_spec - guard_band) - scale_lpc);
269
270        if (scale_spec > 0) {
271          ixheaacd_tns_ar_filter_usac(&ptr_spec[shift], size, inc, lpc_coeff,
272                                      filt->order, scale_lpc,
273                                      usac_data->x_ac_dec);
274        }
275
276        else {
277          WORD32 *ptr_temp = ptr_spec + start;
278
279          scale_spec = -scale_spec;
280          scale_spec = ixheaacd_min32(scale_spec, 31);
281
282          for (i = size; i != 0; i--) {
283            *ptr_temp = *ptr_temp >> scale_spec;
284            ptr_temp++;
285          }
286
287          {
288            ixheaacd_tns_ar_filter_usac(&ptr_spec[shift], size, inc, lpc_coeff,
289                                        filt->order, scale_lpc,
290                                        usac_data->x_ac_dec);
291          }
292
293          {
294            ptr_temp = ptr_spec + start;
295            i = size;
296
297            do {
298              *ptr_temp = *ptr_temp << scale_spec;
299              ptr_temp++;
300              i--;
301            } while (i != 0);
302          }
303        }
304
305        for (i = start; i <= stop - 1; i++) {
306          spec[i] = ptr_spec[i];
307        }
308      }
309    }
310
311    spec += pstr_sfb_info->bins_per_sbk;
312  }
313}
314