xref: /aosp_15_r20/external/libxaac/encoder/ixheaace_tns.c (revision 15dc779a375ca8b5125643b829a8aa4b70d7f451)
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