xref: /aosp_15_r20/external/libxaac/encoder/ixheaace_psy_mod.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 
24 #include <string.h>
25 
26 #include "ixheaac_type_def.h"
27 #include "ixheaac_constants.h"
28 #include "impd_drc_common_enc.h"
29 #include "impd_drc_uni_drc.h"
30 #include "impd_drc_tables.h"
31 #include "impd_drc_api.h"
32 #include "ixheaace_api.h"
33 #include "ixheaace_aac_constants.h"
34 #include "ixheaac_error_standards.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_common_rom.h"
40 #include "ixheaace_bitbuffer.h"
41 
42 #include "ixheaac_basic_ops32.h"
43 #include "ixheaac_basic_ops16.h"
44 #include "ixheaac_basic_ops40.h"
45 #include "ixheaac_basic_ops.h"
46 
47 #include "ixheaace_block_switch.h"
48 #include "ixheaace_psy_utils_spreading.h"
49 #include "ixheaace_psy_utils.h"
50 #include "ixheaace_calc_ms_band_energy.h"
51 #include "ixheaace_tns.h"
52 #include "ixheaace_adjust_threshold_data.h"
53 #include "ixheaace_dynamic_bits.h"
54 #include "ixheaace_qc_data.h"
55 #include "ixheaace_psy_data.h"
56 #include "ixheaace_ms_stereo.h"
57 #include "ixheaace_interface.h"
58 
59 #include "ixheaace_write_bitstream.h"
60 #include "ixheaace_psy_configuration.h"
61 #include "ixheaace_psy_mod.h"
62 #include "ixheaace_stereo_preproc.h"
63 #include "ixheaace_enc_main.h"
64 #include "ixheaace_group_data.h"
65 
66 #include "ixheaace_tns_func.h"
67 
68 #include "ixheaace_tns_params.h"
69 #include "ixheaace_common_utils.h"
70 #include "ixheaace_fft.h"
71 
72 static WORD32 ia_enhaacplus_enc_block_type_to_window_shape_lc[] = {KBD_WINDOW, SINE_WINDOW,
73                                                                    SINE_WINDOW, KBD_WINDOW};
74 
75 static WORD32 ia_enhaacplus_enc_block_type_to_window_shape_ld[] = {SINE_WINDOW, LD_WINDOW,
76                                                                    LD_WINDOW, SINE_WINDOW};
77 
ia_enhaacplus_enc_psy_new(ixheaace_psy_kernel * pstr_h_psy,WORD32 num_chan,WORD32 * ptr_shared_buffer_2,WORD32 long_frame_len)78 WORD32 ia_enhaacplus_enc_psy_new(ixheaace_psy_kernel *pstr_h_psy, WORD32 num_chan,
79                                  WORD32 *ptr_shared_buffer_2, WORD32 long_frame_len)
80 
81 {
82   WORD32 i;
83   for (i = 0; i < num_chan; i++) {
84     pstr_h_psy->psy_data[i]->ptr_spec_coeffs =
85         (FLOAT32 *)(&ptr_shared_buffer_2[i * long_frame_len]);
86 
87     memset(pstr_h_psy->psy_data[i]->ptr_spec_coeffs, 0,
88            long_frame_len * sizeof(*pstr_h_psy->psy_data[i]->ptr_spec_coeffs));
89   }
90 
91   pstr_h_psy->p_scratch_tns_float = (FLOAT32 *)(&ptr_shared_buffer_2[2 * long_frame_len]);
92   if (long_frame_len == FRAME_LEN_960) {
93     pstr_h_psy->p_scratch_tns_float = pstr_h_psy->p_scratch_tns_float + 128;
94   }
95 
96   memset(pstr_h_psy->p_scratch_tns_float, 0,
97          long_frame_len * sizeof(*pstr_h_psy->p_scratch_tns_float));
98 
99   return IA_NO_ERROR;
100 }
101 
ia_enhaacplus_enc_psy_main_init(ixheaace_psy_kernel * pstr_h_psy,WORD32 sample_rate,WORD32 bit_rate,WORD32 channels,WORD32 tns_mask,WORD32 bandwidth,WORD32 aot,ixheaace_aac_tables * pstr_aac_tables,WORD32 frame_len_long)102 IA_ERRORCODE ia_enhaacplus_enc_psy_main_init(ixheaace_psy_kernel *pstr_h_psy, WORD32 sample_rate,
103                                              WORD32 bit_rate, WORD32 channels, WORD32 tns_mask,
104                                              WORD32 bandwidth, WORD32 aot,
105                                              ixheaace_aac_tables *pstr_aac_tables,
106                                              WORD32 frame_len_long)
107 
108 {
109   WORD32 ch;
110   IA_ERRORCODE err;
111 
112   err = ia_enhaacplus_enc_init_psy_configuration(bit_rate / channels, sample_rate, bandwidth, aot,
113                                                  &(pstr_h_psy->psy_conf_long), pstr_aac_tables,
114                                                  frame_len_long);
115   if (err != IA_NO_ERROR) {
116     return err;
117   }
118 
119   if (!err) {
120     err = ia_enhaacplus_enc_init_tns_configuration(
121         bit_rate, sample_rate, channels, &pstr_h_psy->psy_conf_long.str_tns_conf,
122         &(pstr_h_psy->psy_conf_long), (WORD32)(tns_mask & 1), pstr_aac_tables->pstr_tns_tab,
123         frame_len_long, aot);
124 
125     if (err != IA_NO_ERROR) {
126       return err;
127     }
128   }
129   if (aot == AOT_AAC_LC || aot == AOT_SBR || aot == AOT_PS) {
130     if (!err) {
131       err = ia_enhaacplus_enc_init_psy_configuration_short(
132           bit_rate / channels, sample_rate, bandwidth, aot, &pstr_h_psy->psy_conf_short,
133           pstr_aac_tables, frame_len_long / BLK_SWITCH_WIN);
134       if (err != IA_NO_ERROR) {
135         return err;
136       }
137     }
138 
139     if (!err) {
140       err = ia_enhaacplus_enc_init_tns_configuration_short(
141           bit_rate, sample_rate, channels, &pstr_h_psy->psy_conf_short.str_tns_conf,
142           &(pstr_h_psy->psy_conf_short), (WORD32)(tns_mask & 1), pstr_aac_tables->pstr_tns_tab,
143           frame_len_long / BLK_SWITCH_WIN, aot);
144       if (err != IA_NO_ERROR) {
145         return err;
146       }
147     }
148   }
149 
150   if (!err) {
151     /* pstr_h_psy->psy_data[] */
152     for (ch = 0; ch < channels; ch++) {
153       switch (aot) {
154         case AOT_AAC_LC:
155         case AOT_SBR:
156         case AOT_PS:
157           iaace_init_block_switching(&pstr_h_psy->psy_data[ch]->blk_switch_cntrl, bit_rate,
158                                      channels);
159           break;
160 
161         case AOT_AAC_LD:
162         case AOT_AAC_ELD:
163           pstr_h_psy->psy_data[ch]->blk_switch_cntrl.win_seq = LONG_WINDOW;
164           pstr_h_psy->psy_data[ch]->blk_switch_cntrl.nxt_win_seq = LONG_WINDOW;
165           break;
166       }
167       ia_enhaacplus_enc_init_pre_echo_control(pstr_h_psy->psy_data[ch]->sfb_threshold_nm1_float,
168                                               pstr_h_psy->psy_conf_long.sfb_cnt,
169                                               pstr_h_psy->psy_conf_long.sfb_threshold_quiet);
170     }
171   }
172 
173   return IA_NO_ERROR;
174 }
175 
ia_enhaacplus_enc_advance_psy_long_ms(ixheaace_psy_data ** psy_data,ixheaace_psy_configuration_long * pstr_psy_conf_long)176 static VOID ia_enhaacplus_enc_advance_psy_long_ms(
177     ixheaace_psy_data **psy_data,
178     ixheaace_psy_configuration_long *pstr_psy_conf_long) {
179   ia_enhaacplus_enc_calc_band_energy_ms(
180       psy_data[0]->ptr_spec_coeffs, psy_data[1]->ptr_spec_coeffs, pstr_psy_conf_long->sfb_offsets,
181       pstr_psy_conf_long->sfb_active, pstr_psy_conf_long->sfb_cnt,
182       psy_data[0]->sfb_energy_ms.long_nrg, &psy_data[0]->sfb_energy_sum_ms.long_nrg,
183       psy_data[1]->sfb_energy_ms.long_nrg, &psy_data[1]->sfb_energy_sum_ms.long_nrg);
184 }
185 
ia_enhaacplus_enc_advance_psy_short_ms(ixheaace_psy_data ** psy_data,ixheaace_psy_configuration_short * pstr_psy_conf_short,WORD32 ccfl)186 static VOID ia_enhaacplus_enc_advance_psy_short_ms(
187     ixheaace_psy_data **psy_data,
188     ixheaace_psy_configuration_short *pstr_psy_conf_short, WORD32 ccfl) {
189   WORD32 w;
190   WORD32 frame_len_short = FRAME_LEN_SHORT_128;
191 
192   if (ccfl == FRAME_LEN_960) {
193     frame_len_short = FRAME_LEN_SHORT_120;
194   }
195   for (w = 0; w < TRANS_FAC; w++) {
196     WORD32 w_offset = w * frame_len_short;
197 
198     ia_enhaacplus_enc_calc_band_energy_ms(
199         psy_data[0]->ptr_spec_coeffs + w_offset, psy_data[1]->ptr_spec_coeffs + w_offset,
200         pstr_psy_conf_short->sfb_offsets, pstr_psy_conf_short->sfb_active,
201         pstr_psy_conf_short->sfb_cnt, psy_data[0]->sfb_energy_ms.short_nrg[w],
202         &psy_data[0]->sfb_energy_sum_ms.short_nrg[w], psy_data[1]->sfb_energy_ms.short_nrg[w],
203         &psy_data[1]->sfb_energy_sum_ms.short_nrg[w]);
204   }
205 }
206 
ia_enhaacplus_enc_advance_psy_short(ixheaace_psy_data * pstr_psy_data,ixheaace_temporal_noise_shaping_data * pstr_tns_data,ixheaace_psy_configuration_short * pstr_psy_conf_short,ixheaace_psy_out_channel * pstr_psy_out_ch,FLOAT32 * ptr_tns_scratch,const ixheaace_temporal_noise_shaping_data * ptr_tns_data2,const WORD32 ch,WORD32 aot,FLOAT32 * ptr_shared_buffer1,ixheaace_aac_tables * pstr_aac_tables,WORD32 frame_len_long)207 static IA_ERRORCODE ia_enhaacplus_enc_advance_psy_short(
208     ixheaace_psy_data *pstr_psy_data, ixheaace_temporal_noise_shaping_data *pstr_tns_data,
209     ixheaace_psy_configuration_short *pstr_psy_conf_short,
210     ixheaace_psy_out_channel *pstr_psy_out_ch, FLOAT32 *ptr_tns_scratch,
211     const ixheaace_temporal_noise_shaping_data *ptr_tns_data2, const WORD32 ch, WORD32 aot,
212     FLOAT32 *ptr_shared_buffer1, ixheaace_aac_tables *pstr_aac_tables, WORD32 frame_len_long) {
213   IA_ERRORCODE error_code = IA_NO_ERROR;
214   WORD32 w;
215   FLOAT32 energy_shift = 0.25f;
216   FLOAT32 clip_energy = pstr_psy_conf_short->clip_energy * energy_shift;
217 
218   for (w = 0; w < TRANS_FAC; w++) {
219     WORD32 w_offset = w * frame_len_long;
220     WORD32 i, offset;
221     FLOAT32 *ptr_mdct =
222         &pstr_psy_data->ptr_spec_coeffs[pstr_psy_conf_short->lowpass_line + w_offset];
223 
224     /* Low pass */
225     offset = frame_len_long - pstr_psy_conf_short->lowpass_line;
226     memset(ptr_mdct, 0, sizeof(FLOAT32) * offset);
227 
228     /* Calc sfb-bandwise MDCT-energies for left and right channel */
229     ia_enhaacplus_enc_calc_band_energy(
230         pstr_psy_data->ptr_spec_coeffs + w_offset, pstr_psy_conf_short->sfb_offsets,
231         pstr_psy_conf_short->sfb_active, pstr_psy_data->sfb_energy.short_nrg[w],
232         pstr_psy_conf_short->sfb_cnt, &pstr_psy_data->sfb_energy_sum.short_nrg[w]);
233 
234     /* TNS Detect*/
235     error_code = ia_enhaacplus_enc_tns_detect(
236         pstr_tns_data, pstr_psy_conf_short->str_tns_conf, ptr_tns_scratch,
237         pstr_psy_conf_short->sfb_offsets, pstr_psy_data->ptr_spec_coeffs + w_offset, w,
238         pstr_psy_data->blk_switch_cntrl.win_seq, aot, pstr_psy_data->sfb_energy.short_nrg[w],
239         ptr_shared_buffer1, frame_len_long);
240 
241     if (error_code != IA_NO_ERROR) {
242       return error_code;
243     }
244 
245     /*  TNS Sync */
246     if (ch == 1) {
247       ia_enhaacplus_enc_tns_sync(pstr_tns_data, ptr_tns_data2, pstr_psy_conf_short->str_tns_conf,
248                                  w, (WORD32)pstr_psy_data->blk_switch_cntrl.win_seq);
249     }
250 
251     /* TNS Encode */
252     ia_enhaacplus_enc_tns_encode(
253         &pstr_psy_out_ch->tns_info, pstr_tns_data, pstr_psy_conf_short->sfb_cnt,
254         pstr_psy_conf_short->str_tns_conf, pstr_psy_conf_short->lowpass_line,
255         pstr_psy_data->ptr_spec_coeffs + w_offset, w, pstr_psy_data->blk_switch_cntrl.win_seq,
256         pstr_aac_tables->pstr_tns_tab);
257 
258     for (i = 0; i < pstr_psy_conf_short->sfb_cnt; i++) {
259       pstr_psy_data->sfb_threshold.short_nrg[w][i] =
260           pstr_psy_data->sfb_energy.short_nrg[w][i] * pstr_psy_conf_short->ratio_float;
261 
262       pstr_psy_data->sfb_threshold.short_nrg[w][i] =
263           MIN(pstr_psy_data->sfb_threshold.short_nrg[w][i], clip_energy);
264     }
265 
266     /* Calc sfb-bandwise MDCT-energies for left and right channel again, if TNS has modified the
267      * spectrum */
268     if (pstr_psy_out_ch->tns_info.tns_active[w]) {
269       ia_enhaacplus_enc_calc_band_energy(
270           pstr_psy_data->ptr_spec_coeffs + w_offset, pstr_psy_conf_short->sfb_offsets,
271           pstr_psy_conf_short->sfb_active, pstr_psy_data->sfb_energy.short_nrg[w],
272           pstr_psy_conf_short->sfb_cnt, &pstr_psy_data->sfb_energy_sum.short_nrg[w]);
273     }
274 
275     /* Spreading */
276     ia_enhaacplus_enc_spreading_max(
277         pstr_psy_conf_short->sfb_cnt, pstr_psy_conf_short->sfb_mask_low_factor,
278         pstr_psy_conf_short->sfb_mask_high_factor, pstr_psy_data->sfb_threshold.short_nrg[w]);
279 
280     for (i = 0; i < pstr_psy_conf_short->sfb_cnt; i++) {
281       pstr_psy_data->sfb_threshold.short_nrg[w][i] =
282           MAX(pstr_psy_data->sfb_threshold.short_nrg[w][i],
283               (pstr_psy_conf_short->sfb_threshold_quiet[i] * energy_shift));
284     }
285 
286     /* Pre-echo Control */
287     ia_enhaacplus_enc_pre_echo_control(pstr_psy_data->sfb_threshold_nm1_float,
288                                        pstr_psy_conf_short->sfb_cnt,
289                                        pstr_psy_conf_short->min_remaining_threshold_factor,
290                                        pstr_psy_data->sfb_threshold.short_nrg[w]);
291 
292     /* Apply TNS mult table on CB thresholds */
293     if (pstr_psy_out_ch->tns_info.tns_active[w]) {
294       ia_enhaacplus_enc_apply_tns_mult_table_to_ratios(
295           pstr_psy_conf_short->str_tns_conf.tns_ratio_patch_lowest_cb,
296           pstr_psy_conf_short->str_tns_conf.tns_start_band,
297           pstr_psy_data->sfb_threshold.short_nrg[w]);
298     }
299 
300     /* Spreaded energy for avoid hole detection */
301     for (i = 0; i < pstr_psy_conf_short->sfb_cnt; i++) {
302       pstr_psy_data->sfb_sreaded_energy.short_nrg[w][i] =
303           pstr_psy_data->sfb_energy.short_nrg[w][i];
304     }
305 
306     ia_enhaacplus_enc_spreading_max(pstr_psy_conf_short->sfb_cnt,
307                                     pstr_psy_conf_short->sfb_mask_low_factor_spread_nrg,
308                                     pstr_psy_conf_short->sfb_mask_high_factor_spread_nrg,
309                                     pstr_psy_data->sfb_sreaded_energy.short_nrg[w]);
310   }
311   return error_code;
312 }
313 
ia_enhaacplus_enc_advance_psy_long(ixheaace_psy_data * pstr_psy_data,ixheaace_temporal_noise_shaping_data * pstr_tns_data,ixheaace_psy_configuration_long * pstr_psy_conf_long,ixheaace_psy_out_channel * pstr_psy_out_ch,FLOAT32 * ptr_scratch_tns,const ixheaace_temporal_noise_shaping_data * pstr_tns_data2,const WORD32 ch,WORD32 aot,FLOAT32 * ptr_shared_buffer1,ixheaace_aac_tables * pstr_aac_tables,WORD32 frame_len_long)314 static IA_ERRORCODE ia_enhaacplus_enc_advance_psy_long(
315     ixheaace_psy_data *pstr_psy_data, ixheaace_temporal_noise_shaping_data *pstr_tns_data,
316     ixheaace_psy_configuration_long *pstr_psy_conf_long,
317     ixheaace_psy_out_channel *pstr_psy_out_ch, FLOAT32 *ptr_scratch_tns,
318     const ixheaace_temporal_noise_shaping_data *pstr_tns_data2, const WORD32 ch, WORD32 aot,
319     FLOAT32 *ptr_shared_buffer1, ixheaace_aac_tables *pstr_aac_tables, WORD32 frame_len_long) {
320   WORD32 i;
321   IA_ERRORCODE error_code = IA_NO_ERROR;
322   FLOAT32 energy_shift = 0.25f;
323   FLOAT32 clip_energy = pstr_psy_conf_long->clip_energy / 4;
324   FLOAT32 *ptr_sfb_energy_long = pstr_psy_data->sfb_energy.long_nrg;
325   FLOAT32 *ptr_sfb_spreaded_energy = pstr_psy_data->sfb_sreaded_energy.long_nrg;
326 
327   /* Low pass */
328   memset(&pstr_psy_data->ptr_spec_coeffs[pstr_psy_conf_long->lowpass_line], 0,
329          sizeof(*pstr_psy_data->ptr_spec_coeffs) *
330              (frame_len_long - pstr_psy_conf_long->lowpass_line));
331 
332   /* Calculate scale_factor_band - bandwise MDCT-energies for left and right channels */
333   ia_enhaacplus_enc_calc_band_energy(
334       pstr_psy_data->ptr_spec_coeffs, pstr_psy_conf_long->sfb_offsets,
335       pstr_psy_conf_long->sfb_active, pstr_psy_data->sfb_energy.long_nrg,
336       pstr_psy_conf_long->sfb_cnt, &pstr_psy_data->sfb_energy_sum.long_nrg);
337 
338   /* TNS Detect */
339   error_code = ia_enhaacplus_enc_tns_detect(
340       pstr_tns_data, pstr_psy_conf_long->str_tns_conf, ptr_scratch_tns,
341       pstr_psy_conf_long->sfb_offsets, pstr_psy_data->ptr_spec_coeffs, 0,
342       pstr_psy_data->blk_switch_cntrl.win_seq, aot, pstr_psy_data->sfb_energy.long_nrg,
343       ptr_shared_buffer1, frame_len_long);
344 
345   if (error_code != IA_NO_ERROR) {
346     return error_code;
347   }
348 
349   /* TNS Sync */
350   if (ch == 1) {
351     ia_enhaacplus_enc_tns_sync(pstr_tns_data, pstr_tns_data2, pstr_psy_conf_long->str_tns_conf, 0,
352                                (WORD32)pstr_psy_data->blk_switch_cntrl.win_seq);
353   }
354 
355   /* TNS Encode */
356   ia_enhaacplus_enc_tns_encode(&pstr_psy_out_ch->tns_info, pstr_tns_data,
357                                pstr_psy_conf_long->sfb_cnt, pstr_psy_conf_long->str_tns_conf,
358                                pstr_psy_conf_long->lowpass_line, pstr_psy_data->ptr_spec_coeffs,
359                                0, (WORD32)pstr_psy_data->blk_switch_cntrl.win_seq,
360                                pstr_aac_tables->pstr_tns_tab);
361 
362   if (aot == AOT_AAC_ELD) {
363     for (i = 0; i < pstr_psy_conf_long->sfb_active; i++) {
364       pstr_psy_data->sfb_threshold.long_nrg[i] =
365           pstr_psy_data->sfb_energy.long_nrg[i] * pstr_psy_conf_long->ratio_float;
366 
367       pstr_psy_data->sfb_threshold.long_nrg[i] =
368           MIN(pstr_psy_data->sfb_threshold.long_nrg[i], clip_energy);
369     }
370   } else {
371     for (i = 0; i < pstr_psy_conf_long->sfb_cnt; i++) {
372       pstr_psy_data->sfb_threshold.long_nrg[i] =
373           pstr_psy_data->sfb_energy.long_nrg[i] * pstr_psy_conf_long->ratio_float;
374 
375       pstr_psy_data->sfb_threshold.long_nrg[i] =
376           MIN(pstr_psy_data->sfb_threshold.long_nrg[i], clip_energy);
377     }
378   }
379 
380   /* Calculate scale factor band - bandwise MDCT-energies for left and right channel again, if TNS
381    * has modified the spectrum */
382   if (pstr_psy_out_ch->tns_info.tns_active[0] == 1) {
383     ia_enhaacplus_enc_calc_band_energy(
384         pstr_psy_data->ptr_spec_coeffs, pstr_psy_conf_long->sfb_offsets,
385         pstr_psy_conf_long->sfb_active, pstr_psy_data->sfb_energy.long_nrg,
386         pstr_psy_conf_long->sfb_cnt, &pstr_psy_data->sfb_energy_sum.long_nrg);
387   }
388 
389   /* Spreading */
390   if (aot == AOT_AAC_ELD) {
391     ia_enhaacplus_enc_spreading_max(
392         pstr_psy_conf_long->sfb_active, pstr_psy_conf_long->sfb_mask_low_factor,
393         pstr_psy_conf_long->sfb_mask_high_factor, pstr_psy_data->sfb_threshold.long_nrg);
394   } else {
395     ia_enhaacplus_enc_spreading_max(
396         pstr_psy_conf_long->sfb_cnt, pstr_psy_conf_long->sfb_mask_low_factor,
397         pstr_psy_conf_long->sfb_mask_high_factor, pstr_psy_data->sfb_threshold.long_nrg);
398   }
399 
400   /* Threshold in quiet */
401   if (aot == AOT_AAC_ELD) {
402     for (i = 0; i < pstr_psy_conf_long->sfb_active; i++) {
403       pstr_psy_data->sfb_threshold.long_nrg[i] =
404           MAX(pstr_psy_data->sfb_threshold.long_nrg[i],
405               (pstr_psy_conf_long->sfb_threshold_quiet[i] * energy_shift));
406     }
407   } else {
408     for (i = 0; i < pstr_psy_conf_long->sfb_cnt; i++) {
409       pstr_psy_data->sfb_threshold.long_nrg[i] =
410           MAX(pstr_psy_data->sfb_threshold.long_nrg[i],
411               (pstr_psy_conf_long->sfb_threshold_quiet[i] * energy_shift));
412     }
413   }
414 
415   /* Pre-echo control */
416   if (pstr_psy_data->blk_switch_cntrl.win_seq == STOP_WINDOW) {
417     /* Prevent pre-echo control from comparing stop thresholds with short thresholds */
418     for (i = 0; i < pstr_psy_conf_long->sfb_cnt; i++) {
419       pstr_psy_data->sfb_threshold_nm1_float[i] = 1.0e20f;
420     }
421   }
422 
423   ia_enhaacplus_enc_pre_echo_control(
424       pstr_psy_data->sfb_threshold_nm1_float, pstr_psy_conf_long->sfb_cnt,
425       pstr_psy_conf_long->min_remaining_threshold_factor, pstr_psy_data->sfb_threshold.long_nrg);
426 
427   if (pstr_psy_data->blk_switch_cntrl.win_seq == START_WINDOW) {
428     /* Prevent pre-echo control in next frame from comparing start thresholds with short
429      * thresholds */
430     for (i = 0; i < pstr_psy_conf_long->sfb_cnt; i++) {
431       pstr_psy_data->sfb_threshold_nm1_float[i] = 1.0e20f;
432     }
433   }
434 
435   /* Apply TNS mult table on CB thresholds */
436   if (pstr_psy_out_ch->tns_info.tns_active[0]) {
437     ia_enhaacplus_enc_apply_tns_mult_table_to_ratios(
438         pstr_psy_conf_long->str_tns_conf.tns_ratio_patch_lowest_cb,
439         pstr_psy_conf_long->str_tns_conf.tns_start_band, pstr_psy_data->sfb_threshold.long_nrg);
440   }
441 
442   /* Spreaded energy for avoid hole detection */
443 
444   memcpy(&ptr_sfb_spreaded_energy[0], &ptr_sfb_energy_long[0],
445          sizeof(ptr_sfb_spreaded_energy[0]) * pstr_psy_conf_long->sfb_cnt);
446 
447   if (aot == AOT_AAC_ELD) {
448     ia_enhaacplus_enc_spreading_max(pstr_psy_conf_long->sfb_active,
449                                     pstr_psy_conf_long->sfb_mask_low_factor_spread_nrg,
450                                     pstr_psy_conf_long->sfb_mask_high_factor_spread_nrg,
451                                     pstr_psy_data->sfb_sreaded_energy.long_nrg);
452   } else {
453     ia_enhaacplus_enc_spreading_max(pstr_psy_conf_long->sfb_cnt,
454                                     pstr_psy_conf_long->sfb_mask_low_factor_spread_nrg,
455                                     pstr_psy_conf_long->sfb_mask_high_factor_spread_nrg,
456                                     pstr_psy_data->sfb_sreaded_energy.long_nrg);
457   }
458 
459   return error_code;
460 }
461 
ia_enhaacplus_enc_psy_main(WORD32 time_sn_stride,ixheaace_element_info * pstr_elem_info,const FLOAT32 * ptr_time_signal,WORD32 aot,ixheaace_psy_data ** psy_data,ixheaace_temporal_noise_shaping_data ** tns_data,ixheaace_psy_configuration_long * pstr_psy_conf_long,ixheaace_psy_configuration_short * pstr_psy_conf_short,ixheaace_psy_out_channel ** psy_out_ch,ixheaace_psy_out_element * pstr_psy_out_element,FLOAT32 * ptr_scratch_tns,FLOAT32 * ptr_shared_buffer1,WORD8 * ptr_shared_buffer5,ixheaace_aac_tables * pstr_aac_tables,WORD32 frame_len_long)462 IA_ERRORCODE ia_enhaacplus_enc_psy_main(
463     WORD32 time_sn_stride, ixheaace_element_info *pstr_elem_info, const FLOAT32 *ptr_time_signal,
464     WORD32 aot, ixheaace_psy_data **psy_data,
465     ixheaace_temporal_noise_shaping_data **tns_data,
466     ixheaace_psy_configuration_long *pstr_psy_conf_long,
467     ixheaace_psy_configuration_short *pstr_psy_conf_short,
468     ixheaace_psy_out_channel **psy_out_ch,
469     ixheaace_psy_out_element *pstr_psy_out_element, FLOAT32 *ptr_scratch_tns,
470     FLOAT32 *ptr_shared_buffer1, WORD8 *ptr_shared_buffer5, ixheaace_aac_tables *pstr_aac_tables,
471     WORD32 frame_len_long)
472 
473 {
474   IA_ERRORCODE error_code = IA_NO_ERROR;
475   WORD32 grouped_sfb_offset[IXHEAACE_MAX_CH_IN_BS_ELE][MAXIMUM_GROUPED_SCALE_FACTOR_BAND +
476                                                        1]; /* plus one for last dummy offset ! */
477   FLOAT32 grouped_sfb_min_snr[IXHEAACE_MAX_CH_IN_BS_ELE][MAXIMUM_GROUPED_SCALE_FACTOR_BAND];
478   WORD32 max_sfb_per_grp[IXHEAACE_MAX_CH_IN_BS_ELE] = {0};
479   WORD32 ch, sfb, line;
480   WORD32 num_channels = pstr_elem_info->n_channels_in_el;
481 
482   if (aot == AOT_AAC_LC || aot == AOT_SBR || aot == AOT_PS) {
483     if (pstr_elem_info->el_type != ID_LFE) {
484       for (ch = 0; ch < num_channels; ch++) {
485         iaace_block_switching(&psy_data[ch]->blk_switch_cntrl,
486                               ptr_time_signal + pstr_elem_info->channel_index[ch], frame_len_long,
487                               num_channels);
488       }
489     } else {
490       for (ch = 0; ch < num_channels; ch++) {
491         psy_data[ch]->blk_switch_cntrl.win_seq = LONG_WINDOW;
492       }
493     }
494 
495     /* synch left and right block type */
496     if (num_channels == NUM_CHANS_MONO) {
497       iaace_sync_block_switching(&psy_data[0]->blk_switch_cntrl, NULL, num_channels);
498     }
499     else {
500       iaace_sync_block_switching(&psy_data[0]->blk_switch_cntrl, &psy_data[1]->blk_switch_cntrl,
501                                  num_channels);
502     }
503   } else if (aot == AOT_AAC_LD || aot == AOT_AAC_ELD) {
504     for (ch = 0; ch < num_channels; ch++) {
505       psy_data[ch]->blk_switch_cntrl.win_seq_ld = LONG_WINDOW;
506       psy_data[ch]->blk_switch_cntrl.next_win_seq_ld = LONG_WINDOW;
507       psy_data[ch]->blk_switch_cntrl.win_seq = LONG_WINDOW;
508       psy_data[ch]->blk_switch_cntrl.nxt_win_seq = LONG_WINDOW;
509       psy_data[ch]->blk_switch_cntrl.total_groups_cnt = 1;
510     }
511   }
512   /* transform */
513   for (ch = 0; ch < num_channels; ch++) {
514     if (aot == AOT_AAC_LC || aot == AOT_SBR || aot == AOT_PS) {
515       ixheaace_transform_real_lc_ld(
516           psy_data[ch]->ptr_mdct_delay_buf, ptr_time_signal + pstr_elem_info->channel_index[ch],
517           time_sn_stride, psy_data[ch]->ptr_spec_coeffs, psy_data[ch]->blk_switch_cntrl.win_seq,
518           frame_len_long, ptr_shared_buffer5);
519     } else if (aot == AOT_AAC_LD) {
520       if (frame_len_long == FRAME_LEN_480) {
521         ia_enhaacplus_enc_transform_real(
522             psy_data[ch]->ptr_mdct_delay_buf, ptr_time_signal + pstr_elem_info->channel_index[ch],
523             time_sn_stride, psy_data[ch]->ptr_spec_coeffs, pstr_aac_tables->pstr_mdct_tab,
524             ptr_scratch_tns, ptr_shared_buffer5, frame_len_long);
525       } else {
526         ixheaace_transform_real_lc_ld(
527             psy_data[ch]->ptr_mdct_delay_buf, ptr_time_signal + pstr_elem_info->channel_index[ch],
528             time_sn_stride, psy_data[ch]->ptr_spec_coeffs, psy_data[ch]->blk_switch_cntrl.win_seq,
529             frame_len_long, ptr_shared_buffer5);
530       }
531     } else if (aot == AOT_AAC_ELD) {
532       if (frame_len_long == FRAME_LEN_480) {
533         ia_enhaacplus_enc_transform_real(
534             psy_data[ch]->ptr_mdct_delay_buf, ptr_time_signal + pstr_elem_info->channel_index[ch],
535             time_sn_stride, psy_data[ch]->ptr_spec_coeffs, pstr_aac_tables->pstr_mdct_tab,
536             ptr_scratch_tns, ptr_shared_buffer5, frame_len_long);
537       } else {
538         ia_enhaacplus_enc_transform_real_eld(
539             psy_data[ch]->ptr_mdct_delay_buf, ptr_time_signal + pstr_elem_info->channel_index[ch],
540             time_sn_stride, psy_data[ch]->ptr_spec_coeffs, ptr_shared_buffer5, frame_len_long);
541       }
542     }
543   }
544 
545   for (ch = 0; ch < num_channels; ch++) {
546     if (psy_data[ch]->blk_switch_cntrl.win_seq != SHORT_WINDOW) {
547       error_code = ia_enhaacplus_enc_advance_psy_long(
548           psy_data[ch], tns_data[ch], pstr_psy_conf_long, psy_out_ch[ch], ptr_scratch_tns,
549           tns_data[1 - ch], ch, aot, ptr_shared_buffer1, pstr_aac_tables, frame_len_long);
550 
551       if (error_code != IA_NO_ERROR) {
552         return error_code;
553       }
554 
555       for (sfb = pstr_psy_conf_long->sfb_cnt - 1; sfb >= 0; sfb--) {
556         for (line = pstr_psy_conf_long->sfb_offsets[sfb + 1] - 1;
557              line >= pstr_psy_conf_long->sfb_offsets[sfb]; line--) {
558           if (psy_data[ch]->ptr_spec_coeffs[line] != 0) {
559             break;
560           }
561         }
562         if (line >= pstr_psy_conf_long->sfb_offsets[sfb]) {
563           break;
564         }
565       }
566 
567       max_sfb_per_grp[ch] = sfb + 1;
568 
569       /* Calculate bandwise energies for mid and side channels - only if 2 channels exist */
570       if (ch == 1) {
571         ia_enhaacplus_enc_advance_psy_long_ms(psy_data, pstr_psy_conf_long);
572       }
573     } else {
574       error_code = ia_enhaacplus_enc_advance_psy_short(
575           psy_data[ch], tns_data[ch], pstr_psy_conf_short, psy_out_ch[ch], ptr_scratch_tns,
576           tns_data[1 - ch], ch, aot, ptr_shared_buffer1, pstr_aac_tables, frame_len_long / 8);
577 
578       if (error_code != IA_NO_ERROR) {
579         return error_code;
580       }
581 
582       /* Calculate bandwise energies for mid and side channels - only if 2 channels exist */
583       if (ch == 1) {
584         ia_enhaacplus_enc_advance_psy_short_ms(psy_data, pstr_psy_conf_short, frame_len_long);
585       }
586     }
587   }
588 
589   /* Group short data (max_sfb for short blocks is determined here) */
590   if (aot == AOT_AAC_LC || aot == AOT_SBR || aot == AOT_PS) {
591     for (ch = 0; ch < num_channels; ch++) {
592       if (psy_data[ch]->blk_switch_cntrl.win_seq == SHORT_WINDOW) {
593         iaace_group_short_data(psy_data[ch]->ptr_spec_coeffs, ptr_scratch_tns,
594                                &psy_data[ch]->sfb_threshold, &psy_data[ch]->sfb_energy,
595                                &psy_data[ch]->sfb_energy_ms, &psy_data[ch]->sfb_sreaded_energy,
596                                pstr_psy_conf_short->sfb_cnt, pstr_psy_conf_short->sfb_offsets,
597                                pstr_psy_conf_short->sfb_min_snr, grouped_sfb_offset[ch],
598                                &max_sfb_per_grp[ch], grouped_sfb_min_snr[ch],
599                                psy_data[ch]->blk_switch_cntrl.total_groups_cnt,
600                                psy_data[ch]->blk_switch_cntrl.group_len, frame_len_long);
601       }
602     }
603   }
604 
605 #if (IXHEAACE_MAX_CH_IN_BS_ELE > 1)
606   /* Stereo Processing */
607   if (num_channels == 2) {
608     pstr_psy_out_element->tools_info.ms_digest = MS_NONE;
609 
610     max_sfb_per_grp[0] = max_sfb_per_grp[1] = MAX(max_sfb_per_grp[0], max_sfb_per_grp[1]);
611 
612     if (psy_data[0]->blk_switch_cntrl.win_seq != SHORT_WINDOW) {
613       iaace_ms_apply(
614           psy_data, psy_data[0]->ptr_spec_coeffs, psy_data[1]->ptr_spec_coeffs,
615           &pstr_psy_out_element->tools_info.ms_digest, pstr_psy_out_element->tools_info.ms_mask,
616           pstr_psy_conf_long->sfb_cnt, pstr_psy_conf_long->sfb_cnt, max_sfb_per_grp[0],
617           pstr_psy_conf_long->sfb_offsets, &pstr_psy_out_element->weight_ms_lr_pe_ratio);
618     } else {
619       iaace_ms_apply(psy_data, psy_data[0]->ptr_spec_coeffs, psy_data[1]->ptr_spec_coeffs,
620                      &pstr_psy_out_element->tools_info.ms_digest,
621                      pstr_psy_out_element->tools_info.ms_mask,
622                      psy_data[0]->blk_switch_cntrl.total_groups_cnt *
623                      pstr_psy_conf_short->sfb_cnt,
624                      pstr_psy_conf_short->sfb_cnt, max_sfb_per_grp[0], grouped_sfb_offset[0],
625                      &pstr_psy_out_element->weight_ms_lr_pe_ratio);
626     }
627   }
628 #endif
629 
630   /* Build output */
631   if (aot == AOT_AAC_LC || aot == AOT_SBR || aot == AOT_PS) {
632     for (ch = 0; ch < num_channels; ch++) {
633       if (psy_data[ch]->blk_switch_cntrl.win_seq != SHORT_WINDOW) {
634         ia_enhaacplus_enc_build_interface(
635             psy_data[ch]->ptr_spec_coeffs, &psy_data[ch]->sfb_threshold,
636             &psy_data[ch]->sfb_energy,
637             &psy_data[ch]->sfb_sreaded_energy, psy_data[ch]->sfb_energy_sum,
638             psy_data[ch]->sfb_energy_sum_ms, psy_data[ch]->blk_switch_cntrl.win_seq,
639             ia_enhaacplus_enc_block_type_to_window_shape_lc[psy_data[ch]
640                                                                 ->blk_switch_cntrl.win_seq],
641             pstr_psy_conf_long->sfb_cnt, pstr_psy_conf_long->sfb_offsets, max_sfb_per_grp[ch],
642             pstr_psy_conf_long->sfb_min_snr, psy_data[ch]->blk_switch_cntrl.total_groups_cnt,
643             psy_data[ch]->blk_switch_cntrl.group_len, psy_out_ch[ch]);
644       } else {
645         ia_enhaacplus_enc_build_interface(
646             psy_data[ch]->ptr_spec_coeffs, &psy_data[ch]->sfb_threshold,
647             &psy_data[ch]->sfb_energy,
648             &psy_data[ch]->sfb_sreaded_energy, psy_data[ch]->sfb_energy_sum,
649             psy_data[ch]->sfb_energy_sum_ms, SHORT_WINDOW, SINE_WINDOW,
650             psy_data[ch]->blk_switch_cntrl.total_groups_cnt * pstr_psy_conf_short->sfb_cnt,
651             grouped_sfb_offset[ch], max_sfb_per_grp[ch], grouped_sfb_min_snr[ch],
652             psy_data[ch]->blk_switch_cntrl.total_groups_cnt,
653             psy_data[ch]->blk_switch_cntrl.group_len, psy_out_ch[ch]);
654       }
655     }
656   } else if (aot == AOT_AAC_LD || aot == AOT_AAC_ELD) {
657     for (ch = 0; ch < num_channels; ch++) {
658       ia_enhaacplus_enc_build_interface(
659           psy_data[ch]->ptr_spec_coeffs, &psy_data[ch]->sfb_threshold, &psy_data[ch]->sfb_energy,
660           &psy_data[ch]->sfb_sreaded_energy, psy_data[ch]->sfb_energy_sum,
661           psy_data[ch]->sfb_energy_sum_ms, LONG_WINDOW,
662           ia_enhaacplus_enc_block_type_to_window_shape_ld[psy_data[ch]
663                                                               ->blk_switch_cntrl.win_seq_ld],
664           ((aot == AOT_AAC_ELD) ? pstr_psy_conf_long->sfb_active : pstr_psy_conf_long->sfb_cnt),
665           pstr_psy_conf_long->sfb_offsets, max_sfb_per_grp[ch], pstr_psy_conf_long->sfb_min_snr,
666           psy_data[ch]->blk_switch_cntrl.total_groups_cnt,
667           psy_data[ch]->blk_switch_cntrl.group_len, psy_out_ch[ch]);
668     }
669   }
670   return error_code;
671 }
672