/src/libxaac/encoder/ixheaace_tns.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
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 | 727k | FLOAT32 *prediction_gain) { |
48 | 727k | WORD32 i, j; |
49 | 727k | FLOAT32 *ptr_work_buf_tmp, tmp_var; |
50 | | |
51 | 727k | memset(ptr_refl_coeff, 0, num_coeff * sizeof(*ptr_refl_coeff)); |
52 | | |
53 | 727k | if (ptr_input[0] == 0) { |
54 | 49.1k | return; |
55 | 49.1k | } |
56 | | |
57 | 678k | ptr_work_buffer[0] = ptr_input[0]; |
58 | 4.88M | for (i = 1; i < num_coeff; i++) { |
59 | 4.20M | tmp_var = ptr_input[i]; |
60 | 4.20M | ptr_work_buffer[i] = tmp_var; |
61 | 4.20M | ptr_work_buffer[i + num_coeff - 1] = tmp_var; |
62 | 4.20M | } |
63 | 678k | ptr_work_buffer[i + num_coeff - 1] = ptr_input[i]; |
64 | | |
65 | 5.56M | for (i = 0; i < num_coeff; i++) { |
66 | 4.88M | FLOAT32 refc, tmp; |
67 | | |
68 | 4.88M | tmp = ptr_work_buffer[num_coeff + i]; |
69 | | |
70 | 4.88M | if (tmp < 0.f) { |
71 | 2.67M | tmp = -tmp; |
72 | 2.67M | } |
73 | | |
74 | 4.88M | if ((ptr_work_buffer[0]) < tmp) { |
75 | 0 | break; |
76 | 0 | } |
77 | | |
78 | 4.88M | if (ptr_work_buffer[0] == 0.f) { |
79 | 0 | refc = 0; |
80 | 4.88M | } else { |
81 | 4.88M | refc = (tmp / ptr_work_buffer[0]); |
82 | 4.88M | } |
83 | | |
84 | 4.88M | if (ptr_work_buffer[num_coeff + i] > 0.f) { |
85 | 2.18M | refc = -refc; |
86 | 2.18M | } |
87 | | |
88 | 4.88M | ptr_refl_coeff[i] = refc; |
89 | | |
90 | 4.88M | ptr_work_buf_tmp = &(ptr_work_buffer[num_coeff]); |
91 | | |
92 | 28.4M | for (j = i; j < num_coeff; j++) { |
93 | 23.5M | FLOAT32 accu1, accu2; |
94 | | |
95 | 23.5M | accu1 = (refc * ptr_work_buffer[j - i]); |
96 | 23.5M | accu1 = (accu1) + ptr_work_buf_tmp[j]; |
97 | | |
98 | 23.5M | accu2 = (refc * ptr_work_buf_tmp[j]); |
99 | 23.5M | accu2 = accu2 + ptr_work_buffer[j - i]; |
100 | | |
101 | 23.5M | ptr_work_buf_tmp[j] = accu1; |
102 | 23.5M | ptr_work_buffer[j - i] = accu2; |
103 | 23.5M | } |
104 | 4.88M | } |
105 | | |
106 | 678k | *prediction_gain = (ptr_input[0] / ptr_work_buffer[0]); |
107 | 678k | } |
108 | | |
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 | 727k | FLOAT32 *prediction_gain) { |
113 | 727k | FLOAT32 auto_corr_buf[TEMPORAL_NOISE_SHAPING_MAX_ORDER + 1]; |
114 | 727k | FLOAT32 par_cor_buf[2 * TEMPORAL_NOISE_SHAPING_MAX_ORDER]; |
115 | 727k | WORD32 i; |
116 | | |
117 | 727k | if (tns_order > TEMPORAL_NOISE_SHAPING_MAX_ORDER) { |
118 | 0 | return IA_EXHEAACE_EXE_FATAL_INVALID_TNS_FILT_ORDER; |
119 | 0 | } |
120 | | |
121 | 727k | memset(&auto_corr_buf[0], 0, (tns_order + 1) * sizeof(auto_corr_buf[0])); |
122 | | |
123 | 727k | ia_enhaacplus_enc_auto_correlation(ptr_signal, auto_corr_buf, num_lines, tns_order + 1); |
124 | | |
125 | 727k | if (ptr_window) { |
126 | 6.80M | for (i = 0; i < tns_order + 1; i++) { |
127 | 6.07M | auto_corr_buf[i] = (auto_corr_buf[i] * ptr_window[i]); |
128 | 6.07M | } |
129 | 727k | } |
130 | | |
131 | 727k | ia_enhaacplus_enc_auto_to_parcor(auto_corr_buf, ptr_parcor, tns_order, par_cor_buf, |
132 | 727k | prediction_gain); |
133 | | |
134 | 727k | return IA_NO_ERROR; |
135 | 727k | } |
136 | | |
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 | 986k | { |
145 | 986k | FLOAT32 prediction_gain = 0; |
146 | 986k | FLOAT32 *ptr_weighted_spec = ptr_scratch_tns + sub_blk_num * long_frame_len; |
147 | 986k | WORD i; |
148 | 986k | FLOAT32 *ptr_weighted_spec_new = ptr_weighted_spec; |
149 | 986k | IA_ERRORCODE error_code = IA_NO_ERROR; |
150 | | |
151 | 986k | if (tns_config.tns_active) { |
152 | 727k | ia_enhaacplus_enc_calc_weighted_spectrum(ptr_spectrum, ptr_weighted_spec, ptr_sfb_energy, |
153 | 727k | ptr_sfb_offset, tns_config.lpc_start_line, |
154 | 727k | tns_config.lpc_stop_line, tns_config.lpc_start_band, |
155 | 727k | tns_config.lpc_stop_band, ptr_shared_buffer1, aot); |
156 | | |
157 | 9.45M | for (i = tns_config.lpc_stop_line; i < (tns_config.lpc_stop_line + 12); i++) { |
158 | 8.72M | ptr_weighted_spec_new[i] = 0; |
159 | 8.72M | } |
160 | | |
161 | 727k | if (block_type != SHORT_WINDOW) { |
162 | 244k | error_code = ia_enhaacplus_enc_calc_tns_filter( |
163 | 244k | &ptr_weighted_spec_new[tns_config.lpc_start_line], tns_config.acf_window_float, |
164 | 244k | tns_config.lpc_stop_line - tns_config.lpc_start_line, tns_config.max_order, |
165 | 244k | pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor, &prediction_gain); |
166 | | |
167 | 244k | if (error_code != IA_NO_ERROR) { |
168 | 0 | return error_code; |
169 | 0 | } |
170 | 244k | pstr_tns_data->data_raw.tns_data_long.sub_block_info.tns_active = |
171 | 244k | ((prediction_gain) > tns_config.threshold) ? 1 : 0; |
172 | | |
173 | 244k | pstr_tns_data->data_raw.tns_data_long.sub_block_info.prediction_gain = prediction_gain; |
174 | 482k | } else { |
175 | 482k | error_code = ia_enhaacplus_enc_calc_tns_filter( |
176 | 482k | &ptr_weighted_spec_new[tns_config.lpc_start_line], tns_config.acf_window_float, |
177 | 482k | tns_config.lpc_stop_line - tns_config.lpc_start_line, tns_config.max_order, |
178 | 482k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor, |
179 | 482k | &prediction_gain); |
180 | | |
181 | 482k | if (error_code != IA_NO_ERROR) { |
182 | 0 | return error_code; |
183 | 0 | } |
184 | | |
185 | 482k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].tns_active = |
186 | 482k | ((prediction_gain) > tns_config.threshold) ? 1 : 0; |
187 | | |
188 | 482k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].prediction_gain = |
189 | 482k | prediction_gain; |
190 | 482k | } |
191 | 727k | } else { |
192 | 259k | if (block_type != SHORT_WINDOW) { |
193 | 120k | pstr_tns_data->data_raw.tns_data_long.sub_block_info.tns_active = 0; |
194 | 120k | pstr_tns_data->data_raw.tns_data_long.sub_block_info.prediction_gain = 0.f; |
195 | 138k | } else { |
196 | 138k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].tns_active = 0; |
197 | 138k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].prediction_gain = 0.f; |
198 | 138k | } |
199 | 259k | } |
200 | 986k | return error_code; |
201 | 986k | } |
202 | | |
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 | 353k | const WORD32 sub_blk_num, const WORD32 block_type) { |
207 | 353k | if (block_type != SHORT_WINDOW) { |
208 | 103k | ixheaace_temporal_noise_shaping_subblock_info_long *pstr_sfb_info_dst; |
209 | 103k | const ixheaace_temporal_noise_shaping_subblock_info_long *pstr_sfb_info_src; |
210 | | |
211 | 103k | pstr_sfb_info_dst = &pstr_tns_data_dst->data_raw.tns_data_long.sub_block_info; |
212 | 103k | pstr_sfb_info_src = &pstr_tns_data_src->data_raw.tns_data_long.sub_block_info; |
213 | 103k | FLOAT32 tmp_var = pstr_sfb_info_dst->prediction_gain; |
214 | 103k | if (fabs(tmp_var - pstr_sfb_info_src->prediction_gain) < (tmp_var * 0.03f)) { |
215 | 52.5k | pstr_sfb_info_dst->tns_active = pstr_sfb_info_src->tns_active; |
216 | | |
217 | 52.5k | memcpy(pstr_sfb_info_dst->parcor, pstr_sfb_info_src->parcor, |
218 | 52.5k | tns_config.max_order * sizeof(pstr_sfb_info_dst->parcor[0])); |
219 | 52.5k | } |
220 | 250k | } else { |
221 | 250k | ixheaace_temporal_noise_shaping_subblock_info_short *pstr_sfb_info_dst; |
222 | 250k | const ixheaace_temporal_noise_shaping_subblock_info_short *pstr_sfb_info_src; |
223 | 250k | pstr_sfb_info_dst = &pstr_tns_data_dst->data_raw.tns_data_short.sub_block_info[sub_blk_num]; |
224 | 250k | pstr_sfb_info_src = &pstr_tns_data_src->data_raw.tns_data_short.sub_block_info[sub_blk_num]; |
225 | | |
226 | 250k | FLOAT32 tmp_var = pstr_sfb_info_dst->prediction_gain; |
227 | 250k | if (fabs(tmp_var - pstr_sfb_info_src->prediction_gain) < (tmp_var * 0.03f)) { |
228 | 165k | pstr_sfb_info_dst->tns_active = pstr_sfb_info_src->tns_active; |
229 | | |
230 | 165k | memcpy(pstr_sfb_info_dst->parcor, pstr_sfb_info_src->parcor, |
231 | 165k | tns_config.max_order * sizeof(pstr_sfb_info_dst->parcor[0])); |
232 | 165k | } |
233 | 250k | } |
234 | 353k | } |
235 | | |
236 | | static WORD32 ia_enhaacplus_enc_index_search3( |
237 | 928k | FLOAT32 parcor, ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) { |
238 | 928k | WORD32 index = 0; |
239 | 928k | WORD32 i; |
240 | | |
241 | 8.35M | for (i = 0; i < 8; i++) { |
242 | 7.42M | if (parcor > pstr_tns_tab->tns_coeff_3_borders[i]) { |
243 | 4.75M | index = i; |
244 | 4.75M | } |
245 | 7.42M | } |
246 | | |
247 | 928k | return (index - 4); |
248 | 928k | } |
249 | | static WORD32 ia_enhaacplus_enc_index_search4( |
250 | 2.17M | FLOAT32 parcor, ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) { |
251 | 2.17M | WORD32 index = 0; |
252 | 2.17M | WORD32 i; |
253 | 37.0M | for (i = 0; i < 16; i++) { |
254 | 34.8M | if (parcor > pstr_tns_tab->tns_coeff_4_borders[i]) { |
255 | 20.6M | index = i; |
256 | 20.6M | } |
257 | 34.8M | } |
258 | | |
259 | 2.17M | return (index - 8); |
260 | 2.17M | } |
261 | | |
262 | | static VOID ia_enhaacplus_enc_parcor_to_index( |
263 | | const FLOAT32 *ptr_parcor, WORD32 *ptr_index, WORD32 order, WORD32 bits_per_coeff, |
264 | 367k | ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) { |
265 | 367k | WORD32 i; |
266 | | |
267 | 367k | if (bits_per_coeff == 3) { |
268 | 1.11M | for (i = order - 1; i >= 0; i--) { |
269 | 928k | ptr_index[i] = ia_enhaacplus_enc_index_search3(ptr_parcor[i], pstr_tns_tab); |
270 | 928k | } |
271 | 185k | } else { |
272 | 2.36M | for (i = order - 1; i >= 0; i--) { |
273 | 2.17M | ptr_index[i] = ia_enhaacplus_enc_index_search4(ptr_parcor[i], pstr_tns_tab); |
274 | 2.17M | } |
275 | 181k | } |
276 | 367k | } |
277 | | |
278 | | static VOID ia_enhaacplus_enc_index_to_parcor( |
279 | | const WORD32 *ptr_index, FLOAT32 *ptr_parcor, WORD32 order, WORD32 bits_per_coeff, |
280 | 367k | ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) { |
281 | 367k | WORD32 i; |
282 | | |
283 | 367k | if (bits_per_coeff == 4) { |
284 | 2.36M | for (i = order - 1; i >= 0; i--) { |
285 | 2.17M | ptr_parcor[i] = pstr_tns_tab->tns_coeff_4[ptr_index[i] + 8]; |
286 | 2.17M | } |
287 | 185k | } else { |
288 | 1.11M | for (i = order - 1; i >= 0; i--) { |
289 | 928k | ptr_parcor[i] = pstr_tns_tab->tns_coeff_3[ptr_index[i] + 4]; |
290 | 928k | } |
291 | 185k | } |
292 | 367k | } |
293 | | |
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 | 986k | ixheaace_temporal_noise_shaping_tables *pstr_tns_tab) { |
301 | 986k | WORD32 i; |
302 | 986k | FLOAT32 *ptr_parcor; |
303 | | |
304 | 986k | if (block_type != SHORT_WINDOW) { |
305 | 365k | if (pstr_tns_data->data_raw.tns_data_long.sub_block_info.tns_active == 0) { |
306 | 184k | pstr_tns_info->tns_active[sub_blk_num] = 0; |
307 | 184k | return; |
308 | 184k | } else { |
309 | 181k | ia_enhaacplus_enc_parcor_to_index( |
310 | 181k | pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor, &pstr_tns_info->coef[0], |
311 | 181k | tns_config.max_order, tns_config.coef_res, pstr_tns_tab); |
312 | | |
313 | 181k | ia_enhaacplus_enc_index_to_parcor( |
314 | 181k | &pstr_tns_info->coef[0], pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor, |
315 | 181k | tns_config.max_order, tns_config.coef_res, pstr_tns_tab); |
316 | | |
317 | 181k | ptr_parcor = |
318 | 181k | &pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor[tns_config.max_order - 1]; |
319 | | |
320 | 812k | for (i = tns_config.max_order - 1; i >= 0; i--) { |
321 | 812k | FLOAT32 tmp_var = *ptr_parcor--; |
322 | | |
323 | 812k | if (tmp_var > 0.1f || tmp_var < -0.1f) { |
324 | 181k | break; |
325 | 181k | } |
326 | 812k | } |
327 | 181k | pstr_tns_info->order[sub_blk_num] = i + 1; |
328 | | |
329 | 181k | pstr_tns_info->tns_active[sub_blk_num] = 1; |
330 | | |
331 | 1.45M | for (i = sub_blk_num + 1; i < TRANS_FAC; i++) { |
332 | 1.27M | pstr_tns_info->tns_active[i] = 0; |
333 | 1.27M | } |
334 | | |
335 | 181k | pstr_tns_info->coef_res[sub_blk_num] = (WORD8)tns_config.coef_res; |
336 | | |
337 | 181k | pstr_tns_info->length[sub_blk_num] = num_sfb - tns_config.tns_start_band; |
338 | | |
339 | 181k | ia_enhaacplus_enc_analysis_filter_lattice( |
340 | 181k | &(ptr_spectrum[tns_config.tns_start_line]), |
341 | 181k | MIN(tns_config.tns_stop_line, lowpass_line) - tns_config.tns_start_line, |
342 | 181k | pstr_tns_data->data_raw.tns_data_long.sub_block_info.parcor, |
343 | 181k | pstr_tns_info->order[sub_blk_num], &(ptr_spectrum[tns_config.tns_start_line])); |
344 | 181k | } |
345 | 365k | } else /*short block*/ |
346 | 621k | { |
347 | 621k | if (pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].tns_active == 0) { |
348 | 435k | pstr_tns_info->tns_active[sub_blk_num] = 0; |
349 | | |
350 | 435k | return; |
351 | 435k | } else { |
352 | 185k | ia_enhaacplus_enc_parcor_to_index( |
353 | 185k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor, |
354 | 185k | &pstr_tns_info->coef[sub_blk_num * TEMPORAL_NOISE_SHAPING_MAX_ORDER_SHORT], |
355 | 185k | tns_config.max_order, tns_config.coef_res, pstr_tns_tab); |
356 | | |
357 | 185k | ia_enhaacplus_enc_index_to_parcor( |
358 | 185k | &pstr_tns_info->coef[sub_blk_num * TEMPORAL_NOISE_SHAPING_MAX_ORDER_SHORT], |
359 | 185k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor, |
360 | 185k | tns_config.max_order, tns_config.coef_res, pstr_tns_tab); |
361 | | |
362 | 185k | ptr_parcor = &pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num] |
363 | 185k | .parcor[tns_config.max_order - 1]; |
364 | 631k | for (i = tns_config.max_order - 1; i >= 0; i--) { |
365 | 631k | FLOAT32 tmp_var = *ptr_parcor--; |
366 | 631k | if (tmp_var > 0.1f || tmp_var < -0.1f) { |
367 | 185k | break; |
368 | 185k | } |
369 | 631k | } |
370 | | |
371 | 185k | pstr_tns_info->order[sub_blk_num] = i + 1; |
372 | | |
373 | 185k | pstr_tns_info->tns_active[sub_blk_num] = 1; |
374 | | |
375 | 185k | pstr_tns_info->coef_res[sub_blk_num] = (WORD8)tns_config.coef_res; |
376 | | |
377 | 185k | pstr_tns_info->length[sub_blk_num] = num_sfb - tns_config.tns_start_band; |
378 | | |
379 | 185k | ia_enhaacplus_enc_analysis_filter_lattice( |
380 | 185k | &(ptr_spectrum[tns_config.tns_start_line]), |
381 | 185k | tns_config.tns_stop_line - tns_config.tns_start_line, |
382 | 185k | pstr_tns_data->data_raw.tns_data_short.sub_block_info[sub_blk_num].parcor, |
383 | 185k | pstr_tns_info->order[sub_blk_num], &(ptr_spectrum[tns_config.tns_start_line])); |
384 | 185k | } |
385 | 621k | } |
386 | | |
387 | 367k | return; |
388 | 986k | } |
389 | | |
390 | | VOID ia_enhaacplus_enc_apply_tns_mult_table_to_ratios(WORD32 start_cb, WORD32 stop_cb, |
391 | 367k | FLOAT32 *ptr_thresholds) { |
392 | 367k | WORD32 i; |
393 | | |
394 | 3.31M | for (i = start_cb; i < stop_cb; i++) { |
395 | 2.94M | ptr_thresholds[i] = (FLOAT32)(ptr_thresholds[i] * 0.25f); |
396 | 2.94M | } |
397 | 367k | } |