1 /******************************************************************************
2 * *
3 * Copyright (C) 2023 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
21 #include <stdlib.h>
22 #include <math.h>
23 #include <string.h>
24 #include "ixheaac_type_def.h"
25 #include "ixheaac_constants.h"
26 #include "ixheaace_aac_constants.h"
27
28 #include "ixheaac_basic_ops32.h"
29 #include "ixheaac_basic_ops16.h"
30 #include "ixheaac_basic_ops40.h"
31 #include "ixheaac_basic_ops.h"
32 #include "ixheaac_error_standards.h"
33
34 #include "ixheaace_common_rom.h"
35 #include "ixheaace_psy_const.h"
36 #include "ixheaace_tns.h"
37 #include "ixheaace_tns_params.h"
38 #include "ixheaace_rom.h"
39 #include "ixheaace_bitbuffer.h"
40 #include "ixheaace_psy_configuration.h"
41 #include "ixheaace_tns_func.h"
42 #include "ixheaace_error_codes.h"
43 #include "ixheaace_common_utils.h"
44
ia_enhaacplus_enc_auto_to_parcor(const FLOAT32 * ptr_input,FLOAT32 * ptr_refl_coeff,WORD32 num_coeff,FLOAT32 * ptr_work_buffer,FLOAT32 * prediction_gain)45 static VOID ia_enhaacplus_enc_auto_to_parcor(const FLOAT32 *ptr_input, FLOAT32 *ptr_refl_coeff,
46 WORD32 num_coeff, FLOAT32 *ptr_work_buffer,
47 FLOAT32 *prediction_gain) {
48 WORD32 i, j;
49 FLOAT32 *ptr_work_buf_tmp, tmp_var;
50
51 memset(ptr_refl_coeff, 0, num_coeff * sizeof(*ptr_refl_coeff));
52
53 if (ptr_input[0] == 0) {
54 return;
55 }
56
57 ptr_work_buffer[0] = ptr_input[0];
58 for (i = 1; i < num_coeff; i++) {
59 tmp_var = ptr_input[i];
60 ptr_work_buffer[i] = tmp_var;
61 ptr_work_buffer[i + num_coeff - 1] = tmp_var;
62 }
63 ptr_work_buffer[i + num_coeff - 1] = ptr_input[i];
64
65 for (i = 0; i < num_coeff; i++) {
66 FLOAT32 refc, tmp;
67
68 tmp = ptr_work_buffer[num_coeff + i];
69
70 if (tmp < 0.f) {
71 tmp = -tmp;
72 }
73
74 if ((ptr_work_buffer[0]) < tmp) {
75 break;
76 }
77
78 if (ptr_work_buffer[0] == 0.f) {
79 refc = 0;
80 } else {
81 refc = (tmp / ptr_work_buffer[0]);
82 }
83
84 if (ptr_work_buffer[num_coeff + i] > 0.f) {
85 refc = -refc;
86 }
87
88 ptr_refl_coeff[i] = refc;
89
90 ptr_work_buf_tmp = &(ptr_work_buffer[num_coeff]);
91
92 for (j = i; j < num_coeff; j++) {
93 FLOAT32 accu1, accu2;
94
95 accu1 = (refc * ptr_work_buffer[j - i]);
96 accu1 = (accu1) + ptr_work_buf_tmp[j];
97
98 accu2 = (refc * ptr_work_buf_tmp[j]);
99 accu2 = accu2 + ptr_work_buffer[j - i];
100
101 ptr_work_buf_tmp[j] = accu1;
102 ptr_work_buffer[j - i] = accu2;
103 }
104 }
105
106 *prediction_gain = (ptr_input[0] / ptr_work_buffer[0]);
107 }
108
ia_enhaacplus_enc_calc_tns_filter(const FLOAT32 * ptr_signal,const FLOAT32 * ptr_window,WORD32 num_lines,WORD32 tns_order,FLOAT32 * ptr_parcor,FLOAT32 * prediction_gain)109 static IA_ERRORCODE ia_enhaacplus_enc_calc_tns_filter(const FLOAT32 *ptr_signal,
110 const FLOAT32 *ptr_window, WORD32 num_lines,
111 WORD32 tns_order, FLOAT32 *ptr_parcor,
112 FLOAT32 *prediction_gain) {
113 FLOAT32 auto_corr_buf[TEMPORAL_NOISE_SHAPING_MAX_ORDER + 1];
114 FLOAT32 par_cor_buf[2 * TEMPORAL_NOISE_SHAPING_MAX_ORDER];
115 WORD32 i;
116
117 if (tns_order > TEMPORAL_NOISE_SHAPING_MAX_ORDER) {
118 return IA_EXHEAACE_EXE_FATAL_INVALID_TNS_FILT_ORDER;
119 }
120
121 memset(&auto_corr_buf[0], 0, (tns_order + 1) * sizeof(auto_corr_buf[0]));
122
123 ia_enhaacplus_enc_auto_correlation(ptr_signal, auto_corr_buf, num_lines, tns_order + 1);
124
125 if (ptr_window) {
126 for (i = 0; i < tns_order + 1; i++) {
127 auto_corr_buf[i] = (auto_corr_buf[i] * ptr_window[i]);
128 }
129 }
130
131 ia_enhaacplus_enc_auto_to_parcor(auto_corr_buf, ptr_parcor, tns_order, par_cor_buf,
132 prediction_gain);
133
134 return IA_NO_ERROR;
135 }
136
ia_enhaacplus_enc_tns_detect(ixheaace_temporal_noise_shaping_data * pstr_tns_data,ixheaace_temporal_noise_shaping_config tns_config,FLOAT32 * ptr_scratch_tns,const WORD32 * ptr_sfb_offset,FLOAT32 * ptr_spectrum,WORD32 sub_blk_num,WORD32 block_type,WORD32 aot,FLOAT32 * ptr_sfb_energy,FLOAT32 * ptr_shared_buffer1,WORD32 long_frame_len)137 IA_ERRORCODE ia_enhaacplus_enc_tns_detect(ixheaace_temporal_noise_shaping_data *pstr_tns_data,
138 ixheaace_temporal_noise_shaping_config tns_config,
139 FLOAT32 *ptr_scratch_tns, const WORD32 *ptr_sfb_offset,
140 FLOAT32 *ptr_spectrum, WORD32 sub_blk_num,
141 WORD32 block_type, WORD32 aot, FLOAT32 *ptr_sfb_energy,
142 FLOAT32 *ptr_shared_buffer1, WORD32 long_frame_len)
143
144 {
145 FLOAT32 prediction_gain = 0;
146 FLOAT32 *ptr_weighted_spec = ptr_scratch_tns + sub_blk_num * long_frame_len;
147 WORD i;
148 FLOAT32 *ptr_weighted_spec_new = ptr_weighted_spec;
149 IA_ERRORCODE error_code = IA_NO_ERROR;
150
151 if (tns_config.tns_active) {
152 ia_enhaacplus_enc_calc_weighted_spectrum(ptr_spectrum, ptr_weighted_spec, ptr_sfb_energy,
153 ptr_sfb_offset, tns_config.lpc_start_line,
154 tns_config.lpc_stop_line, tns_config.lpc_start_band,
155 tns_config.lpc_stop_band, ptr_shared_buffer1, aot);
156
157 for (i = tns_config.lpc_stop_line; i < (tns_config.lpc_stop_line + 12); i++) {
158 ptr_weighted_spec_new[i] = 0;
159 }
160
161 if (block_type != SHORT_WINDOW) {
162 error_code = ia_enhaacplus_enc_calc_tns_filter(
163 &ptr_weighted_spec_new[tns_config.lpc_start_line], tns_config.acf_window_float,
164 tns_config.lpc_stop_line - tns_config.lpc_start_line, tns_config.max_order,
165 pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor, &prediction_gain);
166
167 if (error_code != IA_NO_ERROR) {
168 return error_code;
169 }
170 pstr_tns_data->data_raw.tns_data_long.sub_block_info.tns_active =
171 ((prediction_gain) > tns_config.threshold) ? 1 : 0;
172
173 pstr_tns_data->data_raw.tns_data_long.sub_block_info.prediction_gain = prediction_gain;
174 } else {
175 error_code = ia_enhaacplus_enc_calc_tns_filter(
176 &ptr_weighted_spec_new[tns_config.lpc_start_line], tns_config.acf_window_float,
177 tns_config.lpc_stop_line - tns_config.lpc_start_line, tns_config.max_order,
178 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor,
179 &prediction_gain);
180
181 if (error_code != IA_NO_ERROR) {
182 return error_code;
183 }
184
185 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].tns_active =
186 ((prediction_gain) > tns_config.threshold) ? 1 : 0;
187
188 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].prediction_gain =
189 prediction_gain;
190 }
191 } else {
192 if (block_type != SHORT_WINDOW) {
193 pstr_tns_data->data_raw.tns_data_long.sub_block_info.tns_active = 0;
194 pstr_tns_data->data_raw.tns_data_long.sub_block_info.prediction_gain = 0.f;
195 } else {
196 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].tns_active = 0;
197 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].prediction_gain = 0.f;
198 }
199 }
200 return error_code;
201 }
202
ia_enhaacplus_enc_tns_sync(ixheaace_temporal_noise_shaping_data * pstr_tns_data_dst,const ixheaace_temporal_noise_shaping_data * pstr_tns_data_src,const ixheaace_temporal_noise_shaping_config tns_config,const WORD32 sub_blk_num,const WORD32 block_type)203 VOID ia_enhaacplus_enc_tns_sync(ixheaace_temporal_noise_shaping_data *pstr_tns_data_dst,
204 const ixheaace_temporal_noise_shaping_data *pstr_tns_data_src,
205 const ixheaace_temporal_noise_shaping_config tns_config,
206 const WORD32 sub_blk_num, const WORD32 block_type) {
207 if (block_type != SHORT_WINDOW) {
208 ixheaace_temporal_noise_shaping_subblock_info_long *pstr_sfb_info_dst;
209 const ixheaace_temporal_noise_shaping_subblock_info_long *pstr_sfb_info_src;
210
211 pstr_sfb_info_dst = &pstr_tns_data_dst->data_raw.tns_data_long.sub_block_info;
212 pstr_sfb_info_src = &pstr_tns_data_src->data_raw.tns_data_long.sub_block_info;
213 FLOAT32 tmp_var = pstr_sfb_info_dst->prediction_gain;
214 if (fabs(tmp_var - pstr_sfb_info_src->prediction_gain) < (tmp_var * 0.03f)) {
215 pstr_sfb_info_dst->tns_active = pstr_sfb_info_src->tns_active;
216
217 memcpy(pstr_sfb_info_dst->parcor, pstr_sfb_info_src->parcor,
218 tns_config.max_order * sizeof(pstr_sfb_info_dst->parcor[0]));
219 }
220 } else {
221 ixheaace_temporal_noise_shaping_subblock_info_short *pstr_sfb_info_dst;
222 const ixheaace_temporal_noise_shaping_subblock_info_short *pstr_sfb_info_src;
223 pstr_sfb_info_dst = &pstr_tns_data_dst->data_raw.tns_data_short.sub_block_info[sub_blk_num];
224 pstr_sfb_info_src = &pstr_tns_data_src->data_raw.tns_data_short.sub_block_info[sub_blk_num];
225
226 FLOAT32 tmp_var = pstr_sfb_info_dst->prediction_gain;
227 if (fabs(tmp_var - pstr_sfb_info_src->prediction_gain) < (tmp_var * 0.03f)) {
228 pstr_sfb_info_dst->tns_active = pstr_sfb_info_src->tns_active;
229
230 memcpy(pstr_sfb_info_dst->parcor, pstr_sfb_info_src->parcor,
231 tns_config.max_order * sizeof(pstr_sfb_info_dst->parcor[0]));
232 }
233 }
234 }
235
ia_enhaacplus_enc_index_search3(FLOAT32 parcor,ixheaace_temporal_noise_shaping_tables * pstr_tns_tab)236 static WORD32 ia_enhaacplus_enc_index_search3(
237 FLOAT32 parcor, ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) {
238 WORD32 index = 0;
239 WORD32 i;
240
241 for (i = 0; i < 8; i++) {
242 if (parcor > pstr_tns_tab->tns_coeff_3_borders[i]) {
243 index = i;
244 }
245 }
246
247 return (index - 4);
248 }
ia_enhaacplus_enc_index_search4(FLOAT32 parcor,ixheaace_temporal_noise_shaping_tables * pstr_tns_tab)249 static WORD32 ia_enhaacplus_enc_index_search4(
250 FLOAT32 parcor, ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) {
251 WORD32 index = 0;
252 WORD32 i;
253 for (i = 0; i < 16; i++) {
254 if (parcor > pstr_tns_tab->tns_coeff_4_borders[i]) {
255 index = i;
256 }
257 }
258
259 return (index - 8);
260 }
261
ia_enhaacplus_enc_parcor_to_index(const FLOAT32 * ptr_parcor,WORD32 * ptr_index,WORD32 order,WORD32 bits_per_coeff,ixheaace_temporal_noise_shaping_tables * pstr_tns_tab)262 static VOID ia_enhaacplus_enc_parcor_to_index(
263 const FLOAT32 *ptr_parcor, WORD32 *ptr_index, WORD32 order, WORD32 bits_per_coeff,
264 ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) {
265 WORD32 i;
266
267 if (bits_per_coeff == 3) {
268 for (i = order - 1; i >= 0; i--) {
269 ptr_index[i] = ia_enhaacplus_enc_index_search3(ptr_parcor[i], pstr_tns_tab);
270 }
271 } else {
272 for (i = order - 1; i >= 0; i--) {
273 ptr_index[i] = ia_enhaacplus_enc_index_search4(ptr_parcor[i], pstr_tns_tab);
274 }
275 }
276 }
277
ia_enhaacplus_enc_index_to_parcor(const WORD32 * ptr_index,FLOAT32 * ptr_parcor,WORD32 order,WORD32 bits_per_coeff,ixheaace_temporal_noise_shaping_tables * pstr_tns_tab)278 static VOID ia_enhaacplus_enc_index_to_parcor(
279 const WORD32 *ptr_index, FLOAT32 *ptr_parcor, WORD32 order, WORD32 bits_per_coeff,
280 ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) {
281 WORD32 i;
282
283 if (bits_per_coeff == 4) {
284 for (i = order - 1; i >= 0; i--) {
285 ptr_parcor[i] = pstr_tns_tab->tns_coeff_4[ptr_index[i] + 8];
286 }
287 } else {
288 for (i = order - 1; i >= 0; i--) {
289 ptr_parcor[i] = pstr_tns_tab->tns_coeff_3[ptr_index[i] + 4];
290 }
291 }
292 }
293
ia_enhaacplus_enc_tns_encode(ixheaace_temporal_noise_shaping_params * pstr_tns_info,ixheaace_temporal_noise_shaping_data * pstr_tns_data,WORD32 num_sfb,ixheaace_temporal_noise_shaping_config tns_config,WORD32 lowpass_line,FLOAT32 * ptr_spectrum,WORD32 sub_blk_num,WORD32 block_type,ixheaace_temporal_noise_shaping_tables * pstr_tns_tab)294 VOID ia_enhaacplus_enc_tns_encode(ixheaace_temporal_noise_shaping_params *pstr_tns_info,
295 ixheaace_temporal_noise_shaping_data *pstr_tns_data,
296 WORD32 num_sfb,
297 ixheaace_temporal_noise_shaping_config tns_config,
298 WORD32 lowpass_line, FLOAT32 *ptr_spectrum,
299 WORD32 sub_blk_num, WORD32 block_type,
300 ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) {
301 WORD32 i;
302 FLOAT32 *ptr_parcor;
303
304 if (block_type != SHORT_WINDOW) {
305 if (pstr_tns_data->data_raw.tns_data_long.sub_block_info.tns_active == 0) {
306 pstr_tns_info->tns_active[sub_blk_num] = 0;
307 return;
308 } else {
309 ia_enhaacplus_enc_parcor_to_index(
310 pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor, &pstr_tns_info->coef[0],
311 tns_config.max_order, tns_config.coef_res, pstr_tns_tab);
312
313 ia_enhaacplus_enc_index_to_parcor(
314 &pstr_tns_info->coef[0], pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor,
315 tns_config.max_order, tns_config.coef_res, pstr_tns_tab);
316
317 ptr_parcor =
318 &pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor[tns_config.max_order - 1];
319
320 for (i = tns_config.max_order - 1; i >= 0; i--) {
321 FLOAT32 tmp_var = *ptr_parcor--;
322
323 if (tmp_var > 0.1f || tmp_var < -0.1f) {
324 break;
325 }
326 }
327 pstr_tns_info->order[sub_blk_num] = i + 1;
328
329 pstr_tns_info->tns_active[sub_blk_num] = 1;
330
331 for (i = sub_blk_num + 1; i < TRANS_FAC; i++) {
332 pstr_tns_info->tns_active[i] = 0;
333 }
334
335 pstr_tns_info->coef_res[sub_blk_num] = (WORD8)tns_config.coef_res;
336
337 pstr_tns_info->length[sub_blk_num] = num_sfb - tns_config.tns_start_band;
338
339 ia_enhaacplus_enc_analysis_filter_lattice(
340 &(ptr_spectrum[tns_config.tns_start_line]),
341 MIN(tns_config.tns_stop_line, lowpass_line) - tns_config.tns_start_line,
342 pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor,
343 pstr_tns_info->order[sub_blk_num], &(ptr_spectrum[tns_config.tns_start_line]));
344 }
345 } else /*short block*/
346 {
347 if (pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].tns_active == 0) {
348 pstr_tns_info->tns_active[sub_blk_num] = 0;
349
350 return;
351 } else {
352 ia_enhaacplus_enc_parcor_to_index(
353 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor,
354 &pstr_tns_info->coef[sub_blk_num * TEMPORAL_NOISE_SHAPING_MAX_ORDER_SHORT],
355 tns_config.max_order, tns_config.coef_res, pstr_tns_tab);
356
357 ia_enhaacplus_enc_index_to_parcor(
358 &pstr_tns_info->coef[sub_blk_num * TEMPORAL_NOISE_SHAPING_MAX_ORDER_SHORT],
359 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor,
360 tns_config.max_order, tns_config.coef_res, pstr_tns_tab);
361
362 ptr_parcor = &pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num]
363 .parcor[tns_config.max_order - 1];
364 for (i = tns_config.max_order - 1; i >= 0; i--) {
365 FLOAT32 tmp_var = *ptr_parcor--;
366 if (tmp_var > 0.1f || tmp_var < -0.1f) {
367 break;
368 }
369 }
370
371 pstr_tns_info->order[sub_blk_num] = i + 1;
372
373 pstr_tns_info->tns_active[sub_blk_num] = 1;
374
375 pstr_tns_info->coef_res[sub_blk_num] = (WORD8)tns_config.coef_res;
376
377 pstr_tns_info->length[sub_blk_num] = num_sfb - tns_config.tns_start_band;
378
379 ia_enhaacplus_enc_analysis_filter_lattice(
380 &(ptr_spectrum[tns_config.tns_start_line]),
381 tns_config.tns_stop_line - tns_config.tns_start_line,
382 pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor,
383 pstr_tns_info->order[sub_blk_num], &(ptr_spectrum[tns_config.tns_start_line]));
384 }
385 }
386
387 return;
388 }
389
ia_enhaacplus_enc_apply_tns_mult_table_to_ratios(WORD32 start_cb,WORD32 stop_cb,FLOAT32 * ptr_thresholds)390 VOID ia_enhaacplus_enc_apply_tns_mult_table_to_ratios(WORD32 start_cb, WORD32 stop_cb,
391 FLOAT32 *ptr_thresholds) {
392 WORD32 i;
393
394 for (i = start_cb; i < stop_cb; i++) {
395 ptr_thresholds[i] = (FLOAT32)(ptr_thresholds[i] * 0.25f);
396 }
397 }
398