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 <string.h>
22 #include <math.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <float.h>
26 #include "iusace_type_def.h"
27 #include "ixheaac_error_standards.h"
28 #include "ixheaace_error_codes.h"
29 #include "ixheaace_psy_const.h"
30 #include "ixheaace_tns.h"
31 #include "ixheaace_tns_params.h"
32 #include "ixheaace_rom.h"
33 #include "iusace_block_switch_const.h"
34 #include "iusace_cnst.h"
35 #include "iusace_rom.h"
36 #include "ixheaace_mps_common_define.h"
37 #include "iusace_bitbuffer.h"
38 #include "impd_drc_common_enc.h"
39 #include "impd_drc_uni_drc.h"
40 #include "impd_drc_api.h"
41 #include "impd_drc_uni_drc_eq.h"
42 #include "impd_drc_uni_drc_filter_bank.h"
43 #include "impd_drc_gain_enc.h"
44 #include "impd_drc_struct_def.h"
45
46 #include "ixheaace_memory_standards.h"
47 #include "iusace_tns_usac.h"
48 #include "iusace_psy_mod.h"
49 #include "iusace_config.h"
50 #include "ixheaace_adjust_threshold_data.h"
51 #include "iusace_fd_qc_util.h"
52 #include "iusace_fd_qc_adjthr.h"
53 #include "ixheaace_aac_constants.h"
54 #include "ixheaace_sbr_def.h"
55
iusace_bits_to_pe(const FLOAT32 bits)56 FLOAT32 iusace_bits_to_pe(const FLOAT32 bits) { return (bits * 1.18f); }
57
iusace_adj_thr_init(ia_adj_thr_elem_struct * pstr_adj_thr_ele,const FLOAT32 mean_pe,WORD32 ch_bitrate)58 VOID iusace_adj_thr_init(ia_adj_thr_elem_struct *pstr_adj_thr_ele, const FLOAT32 mean_pe,
59 WORD32 ch_bitrate) {
60 ia_min_snr_adapt_param_struct *pstr_min_snr_params =
61 &pstr_adj_thr_ele->str_min_snr_adapt_params;
62
63 pstr_adj_thr_ele->pe_min = (FLOAT32)0.8f * mean_pe;
64 pstr_adj_thr_ele->pe_max = (FLOAT32)1.2f * mean_pe;
65 pstr_adj_thr_ele->pe_offset = 0.0f;
66
67 if (ch_bitrate < 32000) {
68 pstr_adj_thr_ele->pe_offset =
69 MAX((FLOAT32)50.0f, (FLOAT32)(100.0f) - (FLOAT32)(100.0f / 32000) * (FLOAT32)ch_bitrate);
70 }
71
72 if (ch_bitrate > 20000) {
73 pstr_adj_thr_ele->str_ah_param.modify_min_snr = TRUE;
74 pstr_adj_thr_ele->str_ah_param.start_sfb_long = 15;
75 pstr_adj_thr_ele->str_ah_param.start_sfb_short = 3;
76 } else {
77 pstr_adj_thr_ele->str_ah_param.modify_min_snr = FALSE;
78 pstr_adj_thr_ele->str_ah_param.start_sfb_long = 0;
79 pstr_adj_thr_ele->str_ah_param.start_sfb_short = 0;
80 }
81
82 pstr_min_snr_params->max_red = (FLOAT32)0.25f;
83
84 pstr_min_snr_params->start_ratio = (FLOAT32)10.0f;
85
86 pstr_min_snr_params->max_ratio = (FLOAT32)1000.0f;
87
88 pstr_min_snr_params->red_ratio_fac =
89 (1.0f - pstr_min_snr_params->max_red) /
90 (10.0f * (FLOAT32)log10(pstr_min_snr_params->start_ratio / pstr_min_snr_params->max_ratio));
91
92 pstr_min_snr_params->red_offs = 1.0f - pstr_min_snr_params->red_ratio_fac * 10.0f *
93 (FLOAT32)log10(pstr_min_snr_params->start_ratio);
94
95 pstr_adj_thr_ele->pe_last = (FLOAT32)0.0f;
96 pstr_adj_thr_ele->dyn_bits_last = 0;
97 pstr_adj_thr_ele->pe_correction_fac = (FLOAT32)1.0f;
98 }
99
iusace_calc_sfb_pe_data(ia_qc_pe_data_struct * pstr_qc_pe_data,ia_psy_mod_out_data_struct * pstr_psy_out,WORD32 num_channels,WORD32 chn)100 static VOID iusace_calc_sfb_pe_data(ia_qc_pe_data_struct *pstr_qc_pe_data,
101 ia_psy_mod_out_data_struct *pstr_psy_out, WORD32 num_channels,
102 WORD32 chn) {
103 WORD32 ch, idx = 0;
104 WORD32 scf_band_grp;
105 FLOAT32 num_lines;
106 FLOAT32 ld_thr, ld_ratio;
107 WORD32 i = 0, scf;
108 WORD32 sfb_count;
109 WORD32 scf_band_per_grp;
110 WORD32 max_sfb_per_grp;
111 FLOAT32 *ptr_sfb_energy;
112 FLOAT32 *ptr_sfb_thr;
113 ia_qc_pe_chan_data_struct *str_qc_pe_chan_data;
114
115 pstr_qc_pe_data->pe = pstr_qc_pe_data->offset;
116 pstr_qc_pe_data->const_part = 0.0f;
117 pstr_qc_pe_data->num_active_lines = 0.0f;
118
119 for (ch = chn; ch < chn + num_channels; ch++) {
120 sfb_count = pstr_psy_out[ch].sfb_count;
121 scf_band_per_grp = pstr_psy_out[ch].sfb_per_group;
122 max_sfb_per_grp = pstr_psy_out[ch].max_sfb_per_grp;
123 ptr_sfb_energy = pstr_psy_out[ch].ptr_sfb_energy;
124 ptr_sfb_thr = pstr_psy_out[ch].ptr_sfb_thr;
125 str_qc_pe_chan_data = &pstr_qc_pe_data->pe_ch_data[idx];
126 str_qc_pe_chan_data->pe = 0;
127 str_qc_pe_chan_data->num_active_lines = 0;
128 str_qc_pe_chan_data->const_part = 0;
129
130 for (scf_band_grp = 0; scf_band_grp < sfb_count; scf_band_grp += scf_band_per_grp) {
131 i = scf_band_grp;
132 for (scf = max_sfb_per_grp - 1; scf >= 0; scf--, i++) {
133 if (ptr_sfb_energy[i] > ptr_sfb_thr[i]) {
134 ld_thr = (FLOAT32)log(ptr_sfb_thr[i]) * LOG2_1;
135 ld_ratio = str_qc_pe_chan_data->sfb_ld_energy[i] - ld_thr;
136 num_lines = str_qc_pe_chan_data->sfb_lines[i];
137 if (ld_ratio >= PE_C1) {
138 str_qc_pe_chan_data->sfb_pe[i] = num_lines * ld_ratio;
139 str_qc_pe_chan_data->sfb_const_part[i] =
140 num_lines * str_qc_pe_chan_data->sfb_ld_energy[i];
141 } else {
142 str_qc_pe_chan_data->sfb_pe[i] = num_lines * (PE_C2 + PE_C3 * ld_ratio);
143 str_qc_pe_chan_data->sfb_const_part[i] =
144 num_lines * (PE_C2 + PE_C3 * str_qc_pe_chan_data->sfb_ld_energy[i]);
145 num_lines = num_lines * PE_C3;
146 }
147 str_qc_pe_chan_data->num_sfb_active_lines[i] = num_lines;
148 } else {
149 str_qc_pe_chan_data->sfb_pe[i] = 0.0f;
150 str_qc_pe_chan_data->sfb_const_part[i] = 0.0f;
151 str_qc_pe_chan_data->num_sfb_active_lines[i] = 0.0;
152 }
153
154 str_qc_pe_chan_data->pe += str_qc_pe_chan_data->sfb_pe[i];
155 str_qc_pe_chan_data->const_part += str_qc_pe_chan_data->sfb_const_part[i];
156 str_qc_pe_chan_data->num_active_lines += str_qc_pe_chan_data->num_sfb_active_lines[i];
157 }
158 }
159 pstr_qc_pe_data->pe += str_qc_pe_chan_data->pe;
160 pstr_qc_pe_data->const_part += str_qc_pe_chan_data->const_part;
161 pstr_qc_pe_data->num_active_lines += str_qc_pe_chan_data->num_active_lines;
162 pstr_psy_out[ch].pe = pstr_qc_pe_data->pe;
163 idx++;
164 }
165 return;
166 }
167
iusace_adj_pe_minmax(const FLOAT32 curr_pe,FLOAT32 * pe_min,FLOAT32 * pe_max)168 static VOID iusace_adj_pe_minmax(const FLOAT32 curr_pe, FLOAT32 *pe_min, FLOAT32 *pe_max) {
169 FLOAT32 min_hi_fac = 0.3f, max_hi_fac = 1.0f, min_low_fac = 0.14f, max_low_fac = 0.07f;
170 FLOAT32 diff;
171 FLOAT32 min_diff = curr_pe * (FLOAT32)0.1666666667f;
172
173 if (curr_pe > *pe_max) {
174 diff = (curr_pe - *pe_max);
175 *pe_min += diff * min_hi_fac;
176 *pe_max += diff * max_hi_fac;
177 } else {
178 if (curr_pe < *pe_min) {
179 diff = (*pe_min - curr_pe);
180 *pe_min -= diff * min_low_fac;
181 *pe_max -= diff * max_low_fac;
182 } else {
183 *pe_min += (curr_pe - *pe_min) * min_hi_fac;
184 *pe_max -= (*pe_max - curr_pe) * max_low_fac;
185 }
186 }
187
188 if ((*pe_max - *pe_min) < min_diff) {
189 FLOAT32 low_part, high_part;
190 low_part = MAX((FLOAT32)0.0f, curr_pe - *pe_min);
191 high_part = MAX((FLOAT32)0.0f, *pe_max - curr_pe);
192 *pe_max = curr_pe + high_part / (low_part + high_part) * min_diff;
193 *pe_min = curr_pe - low_part / (low_part + high_part) * min_diff;
194 *pe_min = MAX((FLOAT32)0.0f, *pe_min);
195 }
196
197 return;
198 }
199
iusace_bitres_calc_bitfac(const WORD32 bitres_bits,const WORD32 max_bitres_bits,const FLOAT32 pe,const WORD32 win_seq,const WORD32 avg_bits,const FLOAT32 max_bit_fac,ia_adj_thr_elem_struct * pstr_adj_thr_elem)200 static FLOAT32 iusace_bitres_calc_bitfac(const WORD32 bitres_bits, const WORD32 max_bitres_bits,
201 const FLOAT32 pe, const WORD32 win_seq,
202 const WORD32 avg_bits, const FLOAT32 max_bit_fac,
203 ia_adj_thr_elem_struct *pstr_adj_thr_elem) {
204 FLOAT32 pex;
205 FLOAT32 fill_lvl = 0.0f;
206 FLOAT32 bit_save, bit_spend, bitres_factor;
207
208 if (max_bitres_bits) {
209 fill_lvl = (FLOAT32)bitres_bits / max_bitres_bits;
210 }
211
212 if (win_seq != EIGHT_SHORT_SEQUENCE) {
213 fill_lvl = MAX(fill_lvl, CLIP_SAVE_LO_LONG);
214 fill_lvl = MIN(fill_lvl, CLIP_SAVE_HI_LONG);
215 bit_save = MAX_BITS_SAVE_LONG - (BITS_SAVE_RATIO_LONG * (fill_lvl - CLIP_SAVE_LO_LONG));
216 bit_spend = MIN_BITS_SPEND_LONG + (BITS_SPEND_RATIO_LONG * (fill_lvl - CLIP_SPEND_LO_LONG));
217 } else {
218 fill_lvl = MAX(fill_lvl, CLIP_SPEND_LO_SHORT);
219 fill_lvl = MIN(fill_lvl, CLIP_SPEND_HI_SHORT);
220 bit_save = MAX_BITS_SAVE_SHORT - (BITS_SAVE_RATIO_SHORT * (fill_lvl - CLIP_SAVE_LO_SHORT));
221 bit_spend =
222 MIN_BITS_SPEND_SHORT + (BITS_SPEND_RATIO_SHORT * (fill_lvl - CLIP_SPEND_LO_SHORT));
223 }
224
225 pex = MAX(pe, pstr_adj_thr_elem->pe_min);
226 pex = MIN(pex, pstr_adj_thr_elem->pe_max);
227
228 bitres_factor =
229 (FLOAT32)1.0f - bit_save +
230 ((bit_spend + bit_save) / (pstr_adj_thr_elem->pe_max - pstr_adj_thr_elem->pe_min)) *
231 (pex - pstr_adj_thr_elem->pe_min);
232 bitres_factor = MIN(bitres_factor,
233 (FLOAT32)1.0f - (FLOAT32)0.3f + (FLOAT32)bitres_bits / (FLOAT32)avg_bits);
234
235 bitres_factor = MIN(bitres_factor, max_bit_fac);
236 iusace_adj_pe_minmax(pe, &pstr_adj_thr_elem->pe_min, &pstr_adj_thr_elem->pe_max);
237
238 return bitres_factor;
239 }
240
iusace_calc_pe_correction(FLOAT32 * correction_fac,const FLOAT32 pe_act,const FLOAT32 pe_last,const WORD32 bits_prev)241 static VOID iusace_calc_pe_correction(FLOAT32 *correction_fac, const FLOAT32 pe_act,
242 const FLOAT32 pe_last, const WORD32 bits_prev) {
243 if ((bits_prev > 0) && (pe_act < (FLOAT32)1.5f * pe_last) &&
244 (pe_act > (FLOAT32)0.7f * pe_last) &&
245 ((FLOAT32)1.2f * iusace_bits_to_pe((FLOAT32)bits_prev) > pe_last) &&
246 ((FLOAT32)0.65f * iusace_bits_to_pe((FLOAT32)bits_prev) < pe_last)) {
247 FLOAT32 new_fac = pe_last / iusace_bits_to_pe((FLOAT32)bits_prev);
248
249 if (new_fac < (FLOAT32)1.0f) {
250 new_fac = MIN((FLOAT32)1.1f * new_fac, (FLOAT32)1.0f);
251 new_fac = MAX(new_fac, (FLOAT32)0.85f);
252 } else {
253 new_fac = MAX((FLOAT32)0.9f * new_fac, (FLOAT32)1.0f);
254 new_fac = MIN(new_fac, (FLOAT32)1.15f);
255 }
256 if (((new_fac > (FLOAT32)1.0f) && (*correction_fac < (FLOAT32)1.0f)) ||
257 ((new_fac < (FLOAT32)1.0f) && (*correction_fac > (FLOAT32)1.0f))) {
258 *correction_fac = (FLOAT32)1.0f;
259 }
260
261 if ((*correction_fac < (FLOAT32)1.0f && new_fac < *correction_fac) ||
262 (*correction_fac > (FLOAT32)1.0f && new_fac > *correction_fac))
263 *correction_fac = (FLOAT32)0.85f * (*correction_fac) + (FLOAT32)0.15f * new_fac;
264 else
265 *correction_fac = (FLOAT32)0.7f * (*correction_fac) + (FLOAT32)0.3f * new_fac;
266
267 *correction_fac = MIN(*correction_fac, (FLOAT32)1.15f);
268 *correction_fac = MAX(*correction_fac, (FLOAT32)0.85f);
269 } else {
270 *correction_fac = (FLOAT32)1.0f;
271 }
272
273 return;
274 }
275
iusace_calc_thr_exp(FLOAT32 ** thr_exp,ia_psy_mod_out_data_struct * pstr_psy_out,WORD32 num_chans,WORD32 chn)276 static VOID iusace_calc_thr_exp(FLOAT32 **thr_exp, ia_psy_mod_out_data_struct *pstr_psy_out,
277 WORD32 num_chans, WORD32 chn) {
278 WORD32 sfb, ch, scf_band_grp, idx = 0;
279 ia_psy_mod_out_data_struct *pstr_psy_chan_out;
280 FLOAT32 *scf_band_thr;
281 FLOAT32 *ptr_thr_exp;
282 for (ch = chn; ch < chn + num_chans; ch++) {
283 pstr_psy_chan_out = &pstr_psy_out[ch];
284 ptr_thr_exp = thr_exp[idx];
285 for (scf_band_grp = 0; scf_band_grp < pstr_psy_chan_out->sfb_count;
286 scf_band_grp += pstr_psy_chan_out->sfb_per_group) {
287 FLOAT32 *thr_exp1 = &ptr_thr_exp[scf_band_grp];
288 scf_band_thr = &pstr_psy_chan_out->ptr_sfb_thr[scf_band_grp];
289 for (sfb = 0; sfb < pstr_psy_chan_out->max_sfb_per_grp; sfb++) {
290 thr_exp1[sfb] = (FLOAT32)pow(*scf_band_thr++, RED_EXP_VAL);
291 }
292 }
293 idx++;
294 }
295
296 return;
297 }
298
iusace_adapt_min_snr(ia_psy_mod_out_data_struct * pstr_psy_out,ia_min_snr_adapt_param_struct * pstr_min_snr_params,WORD32 num_chans,WORD32 chn)299 static VOID iusace_adapt_min_snr(ia_psy_mod_out_data_struct *pstr_psy_out,
300 ia_min_snr_adapt_param_struct *pstr_min_snr_params,
301 WORD32 num_chans, WORD32 chn) {
302 WORD32 num_sfb = 0, ch, scf_band_cnt, sfb_off, sfb;
303 FLOAT32 avg_energy = 0.0f, db_ratio, min_snr_red;
304 WORD32 i;
305 for (ch = chn; ch < chn + num_chans; ch++) {
306 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
307
308 num_sfb = 0;
309 avg_energy = 0;
310 scf_band_cnt = pstr_psy_chan_out->max_sfb_per_grp;
311
312 for (sfb_off = 0; sfb_off < pstr_psy_chan_out->sfb_count;
313 sfb_off += pstr_psy_chan_out->sfb_per_group) {
314 FLOAT32 *sfb_energy = &pstr_psy_chan_out->ptr_sfb_energy[sfb_off];
315 for (sfb = scf_band_cnt - 1; sfb >= 0; sfb--) {
316 avg_energy += sfb_energy[sfb];
317 }
318 num_sfb += scf_band_cnt;
319 }
320
321 if (num_sfb > 0) {
322 avg_energy /= num_sfb;
323 }
324
325 for (sfb_off = 0; sfb_off < pstr_psy_chan_out->sfb_count;
326 sfb_off += pstr_psy_chan_out->sfb_per_group) {
327 i = sfb_off;
328 for (sfb = scf_band_cnt - 1; sfb >= 0; sfb--, i++) {
329 if (pstr_min_snr_params->start_ratio * pstr_psy_chan_out->ptr_sfb_energy[i] <
330 avg_energy) {
331 db_ratio =
332 (FLOAT32)(10.0 * log10((MIN_FLT_VAL + avg_energy) /
333 (MIN_FLT_VAL + pstr_psy_chan_out->ptr_sfb_energy[i])));
334 min_snr_red =
335 pstr_min_snr_params->red_offs + pstr_min_snr_params->red_ratio_fac * db_ratio;
336 min_snr_red = MAX(min_snr_red, pstr_min_snr_params->max_red);
337 pstr_psy_chan_out->sfb_min_snr[i] =
338 (FLOAT32)pow(pstr_psy_out[ch].sfb_min_snr[i], min_snr_red);
339 pstr_psy_chan_out->sfb_min_snr[i] = MIN(MIN_SNR_LIMIT, pstr_psy_out[ch].sfb_min_snr[i]);
340 }
341 }
342 }
343 }
344
345 return;
346 }
347
iusace_init_avoid_hole_flag(WORD32 ** ah_flag,ia_psy_mod_out_data_struct * pstr_psy_out,ia_ah_param_struct * pstr_ah_param,WORD32 num_chans,WORD32 chn)348 static VOID iusace_init_avoid_hole_flag(WORD32 **ah_flag,
349 ia_psy_mod_out_data_struct *pstr_psy_out,
350 ia_ah_param_struct *pstr_ah_param, WORD32 num_chans,
351 WORD32 chn) {
352 WORD32 ch, idx;
353 FLOAT32 sfb_energy;
354 FLOAT32 scale_spread_energy;
355 WORD32 scf_band_grp, sfb, scf_band;
356 FLOAT32 *ptr_scf_band_spread_energy, *ptr_scf_band_energy, *ptr_scf_band_min_snr;
357 for (ch = chn; ch < chn + num_chans; ch++) {
358 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
359
360 if (pstr_psy_chan_out->window_sequence != EIGHT_SHORT_SEQUENCE) {
361 scale_spread_energy = 0.5f;
362 } else {
363 scale_spread_energy = 0.63f;
364 }
365
366 for (scf_band_grp = 0; scf_band_grp < pstr_psy_chan_out->sfb_count;
367 scf_band_grp += pstr_psy_chan_out->sfb_per_group) {
368 ptr_scf_band_spread_energy = &pstr_psy_chan_out->ptr_sfb_spread_energy[scf_band_grp];
369 sfb = pstr_psy_chan_out->max_sfb_per_grp;
370 for (scf_band = sfb - 1; scf_band >= 0; scf_band--) {
371 *ptr_scf_band_spread_energy = *ptr_scf_band_spread_energy * scale_spread_energy;
372 ptr_scf_band_spread_energy++;
373 }
374 }
375 }
376
377 if (pstr_ah_param->modify_min_snr) {
378 for (ch = chn; ch < chn + num_chans; ch++) {
379 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
380 ptr_scf_band_energy = pstr_psy_chan_out->ptr_sfb_energy;
381
382 ptr_scf_band_min_snr = pstr_psy_chan_out->sfb_min_snr;
383
384 for (scf_band_grp = 0; scf_band_grp < pstr_psy_chan_out->sfb_count;
385 scf_band_grp += pstr_psy_chan_out->sfb_per_group) {
386 for (scf_band = 0; scf_band < pstr_psy_chan_out->max_sfb_per_grp; scf_band++) {
387 FLOAT32 sfb_en_m1, sfb_en_p1, avg_energy;
388 if (scf_band > 0) {
389 sfb_en_m1 = ptr_scf_band_energy[scf_band_grp + scf_band - 1];
390 } else {
391 sfb_en_m1 = ptr_scf_band_energy[scf_band_grp];
392 }
393 if (scf_band < pstr_psy_chan_out->max_sfb_per_grp - 1)
394 sfb_en_p1 = ptr_scf_band_energy[scf_band_grp + scf_band + 1];
395 else
396 sfb_en_p1 = ptr_scf_band_energy[scf_band_grp + scf_band];
397
398 avg_energy = (sfb_en_m1 + sfb_en_p1) / (FLOAT32)2.0f;
399 sfb_energy = ptr_scf_band_energy[scf_band_grp + scf_band];
400
401 if (sfb_energy > avg_energy) {
402 FLOAT32 temp_min_snr = MAX((FLOAT32)0.8f * avg_energy / sfb_energy, (FLOAT32)0.316f);
403 if (pstr_psy_chan_out->window_sequence != EIGHT_SHORT_SEQUENCE)
404 temp_min_snr = MAX(temp_min_snr, (FLOAT32)0.316f);
405 else
406 temp_min_snr = MAX(temp_min_snr, (FLOAT32)0.5f);
407 ptr_scf_band_min_snr[scf_band_grp + scf_band] =
408 MIN(ptr_scf_band_min_snr[scf_band_grp + scf_band], temp_min_snr);
409 }
410
411 if (((FLOAT32)2.0f * sfb_energy < avg_energy) && (sfb_energy > (FLOAT32)0.0f)) {
412 FLOAT32 temp_min_snr = avg_energy / ((FLOAT32)2.0f * sfb_energy) *
413 ptr_scf_band_min_snr[scf_band_grp + scf_band];
414 temp_min_snr = MIN((FLOAT32)0.8f, temp_min_snr);
415 ptr_scf_band_min_snr[scf_band_grp + scf_band] =
416 MIN(temp_min_snr, ptr_scf_band_min_snr[scf_band_grp + scf_band] * (FLOAT32)3.16f);
417 }
418 }
419 }
420 }
421 }
422
423 if (num_chans == 2) {
424 ia_psy_mod_out_data_struct *psy_out_mid = &pstr_psy_out[chn];
425 ia_psy_mod_out_data_struct *psy_out_side = &pstr_psy_out[chn + 1];
426
427 for (sfb = 0; sfb < psy_out_mid->sfb_count; sfb++) {
428 if (pstr_psy_out[chn].ms_used[sfb]) {
429 FLOAT32 sfb_en_mid = psy_out_mid->ptr_sfb_energy[sfb];
430 FLOAT32 sfb_en_side = psy_out_side->ptr_sfb_energy[sfb];
431 FLOAT32 max_sfb_en = MAX(sfb_en_mid, sfb_en_side);
432 FLOAT32 max_thr = 0.25f * psy_out_mid->sfb_min_snr[sfb] * max_sfb_en;
433
434 psy_out_mid->sfb_min_snr[sfb] = (FLOAT32)MAX(
435 psy_out_mid->sfb_min_snr[sfb],
436 MIN(MAX_FLT_VAL, ((double)max_thr / (MIN_FLT_VAL + (double)sfb_en_mid))));
437
438 if (psy_out_mid->ptr_sfb_energy[sfb] <= 1.0f) {
439 psy_out_mid->ptr_sfb_energy[sfb] = MIN(psy_out_mid->ptr_sfb_energy[sfb], 0.8f);
440 }
441
442 psy_out_side->sfb_min_snr[sfb] = (FLOAT32)MAX(
443 psy_out_side->sfb_min_snr[sfb],
444 MIN(MAX_FLT_VAL, ((double)max_thr / (MIN_FLT_VAL + (double)sfb_en_side))));
445
446 if (psy_out_side->sfb_min_snr[sfb] <= 1.0f) {
447 psy_out_side->sfb_min_snr[sfb] = MIN(psy_out_side->sfb_min_snr[sfb], 0.8f);
448 }
449
450 if (sfb_en_mid > psy_out_mid->ptr_sfb_spread_energy[sfb]) {
451 psy_out_side->ptr_sfb_spread_energy[sfb] = 0.9f * sfb_en_side;
452 }
453
454 if (sfb_en_side > psy_out_side->ptr_sfb_spread_energy[sfb]) {
455 psy_out_mid->ptr_sfb_spread_energy[sfb] = 0.9f * sfb_en_mid;
456 }
457 }
458 }
459 }
460 idx = 0;
461 for (ch = chn; ch < chn + num_chans; ch++) {
462 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
463 for (scf_band_grp = 0; scf_band_grp < pstr_psy_chan_out->sfb_count;
464 scf_band_grp += pstr_psy_chan_out->sfb_per_group) {
465 for (scf_band = 0; scf_band < pstr_psy_chan_out->max_sfb_per_grp; scf_band++) {
466 if (pstr_psy_chan_out->ptr_sfb_spread_energy[scf_band_grp + scf_band] >
467 pstr_psy_chan_out->ptr_sfb_energy[scf_band_grp + scf_band] ||
468 pstr_psy_chan_out->sfb_min_snr[scf_band_grp + scf_band] > (float)1.0) {
469 ah_flag[idx][scf_band_grp + scf_band] = NO_AH;
470 } else {
471 ah_flag[idx][scf_band_grp + scf_band] = AH_INACTIVE;
472 }
473 }
474
475 for (scf_band = pstr_psy_chan_out->max_sfb_per_grp;
476 scf_band < pstr_psy_chan_out->sfb_per_group; scf_band++) {
477 ah_flag[idx][scf_band_grp + scf_band] = NO_AH;
478 }
479 }
480 idx++;
481 }
482
483 return;
484 }
485
iusace_reduce_thr(ia_psy_mod_out_data_struct * pstr_psy_out,WORD32 ** ah_flag,FLOAT32 ** thr_exp,const FLOAT32 red_value,WORD32 num_channels,WORD32 chn)486 static VOID iusace_reduce_thr(ia_psy_mod_out_data_struct *pstr_psy_out, WORD32 **ah_flag,
487 FLOAT32 **thr_exp, const FLOAT32 red_value, WORD32 num_channels,
488 WORD32 chn) {
489 WORD32 ch, sfb_group, sfb, idx = 0;
490 FLOAT32 sfb_energy, sfb_threshold, sfb_thr_reduced;
491 FLOAT32 *sfb_energy_fix, *sfb_threshold_fix, *sfb_min_snr_fix, *thr_exp_fix;
492 for (ch = chn; ch < chn + num_channels; ch++) {
493 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
494 sfb_energy_fix = pstr_psy_chan_out->ptr_sfb_energy;
495 sfb_threshold_fix = pstr_psy_chan_out->ptr_sfb_thr;
496 sfb_min_snr_fix = pstr_psy_chan_out->sfb_min_snr;
497 thr_exp_fix = &thr_exp[idx][0];
498 for (sfb_group = 0; sfb_group < pstr_psy_chan_out->sfb_count;
499 sfb_group += pstr_psy_chan_out->sfb_per_group) {
500 for (sfb = 0; sfb < pstr_psy_chan_out->max_sfb_per_grp; sfb++) {
501 sfb_energy = sfb_energy_fix[sfb_group + sfb];
502 sfb_threshold = sfb_threshold_fix[sfb_group + sfb];
503 if (sfb_energy > sfb_threshold) {
504 sfb_thr_reduced =
505 (FLOAT32)pow((thr_exp_fix[sfb_group + sfb] + red_value), INV_RED_EXP_VAL);
506
507 if ((sfb_thr_reduced > sfb_min_snr_fix[sfb_group + sfb] * sfb_energy) &&
508 (ah_flag[idx][sfb_group + sfb] != NO_AH)) {
509 sfb_thr_reduced = MAX(sfb_min_snr_fix[sfb_group + sfb] * sfb_energy, sfb_threshold);
510 ah_flag[idx][sfb_group + sfb] = AH_ACTIVE;
511 }
512 sfb_threshold_fix[sfb_group + sfb] = sfb_thr_reduced;
513 }
514 }
515 }
516 idx++;
517 }
518
519 return;
520 }
521
iusace_calc_pe_no_active_holes(FLOAT32 * pe,FLOAT32 * const_part,FLOAT32 * nactive_lines,ia_qc_pe_data_struct * pstr_qs_pe_data,WORD32 ** ah_flag,ia_psy_mod_out_data_struct * pstr_psy_out,WORD32 num_channels,WORD32 chn)522 static VOID iusace_calc_pe_no_active_holes(FLOAT32 *pe, FLOAT32 *const_part,
523 FLOAT32 *nactive_lines,
524 ia_qc_pe_data_struct *pstr_qs_pe_data,
525 WORD32 **ah_flag,
526 ia_psy_mod_out_data_struct *pstr_psy_out,
527 WORD32 num_channels, WORD32 chn) {
528 WORD32 ch, sfb_group, sfb, idx = 0;
529 *pe = 0.0f;
530 *const_part = 0.0f;
531 *nactive_lines = 0;
532 for (ch = chn; ch < chn + num_channels; ch++) {
533 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
534 ia_qc_pe_chan_data_struct *pe_channel_data = &pstr_qs_pe_data->pe_ch_data[idx];
535
536 for (sfb_group = 0; sfb_group < pstr_psy_chan_out->sfb_count;
537 sfb_group += pstr_psy_chan_out->sfb_per_group) {
538 for (sfb = 0; sfb < pstr_psy_chan_out->max_sfb_per_grp; sfb++) {
539 if (ah_flag[idx][sfb_group + sfb] < AH_ACTIVE) {
540 *pe += pe_channel_data->sfb_pe[sfb_group + sfb];
541 *const_part += pe_channel_data->sfb_const_part[sfb_group + sfb];
542 *nactive_lines += pe_channel_data->num_sfb_active_lines[sfb_group + sfb];
543 }
544 }
545 }
546 idx++;
547 }
548
549 return;
550 }
551
iusace_correct_thr(ia_psy_mod_out_data_struct * pstr_psy_out,WORD32 ** ah_flag,ia_qc_pe_data_struct * pstr_qs_pe_data,FLOAT32 ** thr_exp,const FLOAT32 red_value,const FLOAT32 delta_pe,WORD32 num_channels,WORD32 chn,UWORD8 * ptr_scratch)552 static IA_ERRORCODE iusace_correct_thr(ia_psy_mod_out_data_struct *pstr_psy_out, WORD32 **ah_flag,
553 ia_qc_pe_data_struct *pstr_qs_pe_data, FLOAT32 **thr_exp,
554 const FLOAT32 red_value, const FLOAT32 delta_pe,
555 WORD32 num_channels, WORD32 chn, UWORD8 *ptr_scratch) {
556 WORD32 i, ch, sfb_group, sfb, idx = 0;
557 FLOAT32 delta_sfb_pe;
558 FLOAT32 thr_factor;
559 FLOAT32 norm_factor[2] = {0};
560 FLOAT32 *sfb_pe_factors[2];
561 for (i = 0; i < 2; i++) {
562 sfb_pe_factors[i] = (FLOAT32 *)ptr_scratch;
563 ptr_scratch += (MAX_NUM_GROUPED_SFB) * sizeof(sfb_pe_factors[0][0]);
564 }
565 FLOAT32 sfb_en, sfb_thr, sfb_thr_reduced;
566 FLOAT32 *p_thr_exp;
567 FLOAT32 *p_sfb_energy, *p_sfb_thr, *p_sfb_min_snr;
568 ia_psy_mod_out_data_struct *pstr_psy_chan_out = NULL;
569 ia_qc_pe_chan_data_struct *pe_channel_data = NULL;
570
571 for (ch = chn; ch < chn + num_channels; ch++) {
572 if (idx >= IXHEAACE_MAX_CH_IN_BS_ELE) {
573 return IA_EXHEAACE_EXE_FATAL_USAC_INVALID_NUM_CHANNEL;
574 }
575 pstr_psy_chan_out = &pstr_psy_out[ch];
576 pe_channel_data = &pstr_qs_pe_data->pe_ch_data[idx];
577 norm_factor[idx] = MIN_FLT_VAL;
578 p_thr_exp = thr_exp[idx];
579
580 for (sfb_group = 0; sfb_group < pstr_psy_chan_out->sfb_count;
581 sfb_group += pstr_psy_chan_out->sfb_per_group) {
582 for (sfb = 0; sfb < pstr_psy_chan_out->max_sfb_per_grp; sfb++) {
583 if ((ah_flag[idx][sfb_group + sfb] < AH_ACTIVE) || (delta_pe > 0)) {
584 sfb_pe_factors[idx][sfb_group + sfb] =
585 pe_channel_data->num_sfb_active_lines[sfb_group + sfb] /
586 (p_thr_exp[sfb_group + sfb] + red_value);
587 norm_factor[idx] += sfb_pe_factors[idx][sfb_group + sfb];
588 } else {
589 sfb_pe_factors[idx][sfb_group + sfb] = 0.0f;
590 }
591 }
592 }
593 idx++;
594 }
595 if (num_channels > 1) {
596 norm_factor[0] = norm_factor[0] + norm_factor[1];
597 }
598 norm_factor[0] = 1.0f / norm_factor[0];
599 idx = 0;
600 for (ch = chn; ch < chn + num_channels; ch++) {
601 if (idx >= IXHEAACE_MAX_CH_IN_BS_ELE) {
602 return IA_EXHEAACE_EXE_FATAL_USAC_INVALID_NUM_CHANNEL;
603 }
604 pstr_psy_chan_out = &pstr_psy_out[ch];
605 pe_channel_data = &pstr_qs_pe_data->pe_ch_data[idx];
606 p_sfb_energy = pstr_psy_chan_out->ptr_sfb_energy;
607 p_sfb_thr = pstr_psy_chan_out->ptr_sfb_thr;
608 p_sfb_min_snr = pstr_psy_chan_out->sfb_min_snr;
609
610 for (sfb_group = 0; sfb_group < pstr_psy_chan_out->sfb_count;
611 sfb_group += pstr_psy_chan_out->sfb_per_group) {
612 i = sfb_group;
613 for (sfb = pstr_psy_chan_out->max_sfb_per_grp - 1; sfb >= 0; sfb--, i++) {
614 delta_sfb_pe = sfb_pe_factors[idx][i] * norm_factor[0] * delta_pe;
615 if (pe_channel_data->num_sfb_active_lines[i] > (FLOAT32)0.5f) {
616 sfb_en = p_sfb_energy[i];
617 sfb_thr = p_sfb_thr[i];
618 thr_factor = MIN(-delta_sfb_pe / pe_channel_data->num_sfb_active_lines[i], 20.f);
619 thr_factor = (FLOAT32)pow(2.0f, thr_factor);
620 sfb_thr_reduced = sfb_thr * thr_factor;
621
622 if ((sfb_thr_reduced > p_sfb_min_snr[i] * sfb_en) && (ah_flag[idx][i] == AH_INACTIVE)) {
623 sfb_thr_reduced = MAX(p_sfb_min_snr[i] * sfb_en, sfb_thr);
624 ah_flag[idx][i] = AH_ACTIVE;
625 }
626 p_sfb_thr[i] = sfb_thr_reduced;
627 }
628 }
629 }
630 idx++;
631 }
632
633 return IA_NO_ERROR;
634 }
635
iusace_reduce_min_snr(ia_psy_mod_out_data_struct * pstr_psy_out,ia_qc_pe_data_struct * pstr_qs_pe_data,WORD32 ** ah_flag,const FLOAT32 desired_pe,WORD32 num_channels,WORD32 chn)636 static VOID iusace_reduce_min_snr(ia_psy_mod_out_data_struct *pstr_psy_out,
637 ia_qc_pe_data_struct *pstr_qs_pe_data, WORD32 **ah_flag,
638 const FLOAT32 desired_pe, WORD32 num_channels, WORD32 chn) {
639 WORD32 sfb, sfb_sub_win, ch, idx;
640 FLOAT32 delta_pe;
641
642 sfb_sub_win = pstr_psy_out[chn].max_sfb_per_grp;
643
644 while (pstr_qs_pe_data->pe > desired_pe && sfb_sub_win > 0) {
645 sfb_sub_win--;
646 for (sfb = sfb_sub_win; sfb < pstr_psy_out[chn].sfb_count;
647 sfb += pstr_psy_out[chn].sfb_per_group) {
648 idx = 0;
649 for (ch = chn; ch < chn + num_channels; ch++) {
650 if (ah_flag[idx][sfb] != NO_AH && pstr_psy_out[ch].sfb_min_snr[sfb] < MIN_SNR_LIMIT) {
651 pstr_psy_out[ch].sfb_min_snr[sfb] = MIN_SNR_LIMIT;
652 pstr_psy_out[ch].ptr_sfb_thr[sfb] =
653 pstr_psy_out[ch].ptr_sfb_energy[sfb] * pstr_psy_out[ch].sfb_min_snr[sfb];
654 delta_pe = pstr_qs_pe_data->pe_ch_data[idx].sfb_lines[sfb] * 1.5f -
655 pstr_qs_pe_data->pe_ch_data[idx].sfb_pe[sfb];
656 pstr_qs_pe_data->pe += delta_pe;
657 pstr_qs_pe_data->pe_ch_data[idx].pe += delta_pe;
658 }
659 idx++;
660 }
661 if (pstr_qs_pe_data->pe <= desired_pe) break;
662 }
663 }
664
665 return;
666 }
667
iusace_allow_more_holes(ia_psy_mod_out_data_struct * pstr_psy_out,ia_qc_pe_data_struct * pstr_qs_pe_data,WORD32 ** ah_flag,const ia_ah_param_struct * str_ah_param,const FLOAT32 desired_pe,WORD32 num_channels,WORD32 chn,UWORD8 * ptr_scratch)668 static VOID iusace_allow_more_holes(ia_psy_mod_out_data_struct *pstr_psy_out,
669 ia_qc_pe_data_struct *pstr_qs_pe_data, WORD32 **ah_flag,
670 const ia_ah_param_struct *str_ah_param,
671 const FLOAT32 desired_pe, WORD32 num_channels, WORD32 chn,
672 UWORD8 *ptr_scratch) {
673 WORD32 sfb, ch, idx;
674 FLOAT32 act_pe = pstr_qs_pe_data->pe;
675
676 if (num_channels == 2 &&
677 pstr_psy_out[chn].window_sequence == pstr_psy_out[chn + 1].window_sequence) {
678 ia_psy_mod_out_data_struct *psy_out_left = &pstr_psy_out[chn];
679 ia_psy_mod_out_data_struct *psy_out_right = &pstr_psy_out[chn + 1];
680
681 for (sfb = 0; sfb < psy_out_left->sfb_count; sfb++) {
682 if (pstr_psy_out[chn].ms_used[sfb]) {
683 if (ah_flag[1][sfb] != NO_AH &&
684 0.4f * psy_out_left->sfb_min_snr[sfb] * psy_out_left->ptr_sfb_energy[sfb] >
685 psy_out_right->ptr_sfb_energy[sfb]) {
686 ah_flag[1][sfb] = NO_AH;
687
688 psy_out_right->ptr_sfb_thr[sfb] = 2.0f * psy_out_right->ptr_sfb_energy[sfb];
689
690 act_pe -= pstr_qs_pe_data->pe_ch_data[1].sfb_pe[sfb];
691 } else {
692 if (ah_flag[0][sfb] != NO_AH &&
693 0.4f * psy_out_right->sfb_min_snr[sfb] * psy_out_right->ptr_sfb_energy[sfb] >
694 psy_out_left->ptr_sfb_energy[sfb]) {
695 ah_flag[0][sfb] = NO_AH;
696
697 psy_out_left->ptr_sfb_thr[sfb] = 2.0f * psy_out_left->ptr_sfb_energy[sfb];
698
699 act_pe -= pstr_qs_pe_data->pe_ch_data[0].sfb_pe[sfb];
700 }
701 }
702 if (act_pe < desired_pe) break;
703 }
704 }
705 }
706 if (act_pe > desired_pe) {
707 WORD32 *start_sfb = (WORD32 *)ptr_scratch;
708 memset(start_sfb, 0, MAX_TIME_CHANNELS * sizeof(start_sfb[0]));
709 FLOAT32 average_energy, min_energy;
710 WORD32 ah_cnt;
711 WORD32 en_idx;
712 FLOAT32 energy[4];
713 WORD32 min_sfb, max_sfb;
714 WORD32 done;
715 for (ch = chn; ch < chn + num_channels; ch++) {
716 if (pstr_psy_out[ch].window_sequence != EIGHT_SHORT_SEQUENCE)
717 start_sfb[ch] = str_ah_param->start_sfb_long;
718 else
719 start_sfb[ch] = str_ah_param->start_sfb_short;
720 }
721
722 average_energy = 0.0f;
723 min_energy = MAX_FLT_VAL;
724 ah_cnt = 0;
725 idx = 0;
726 for (ch = chn; ch < chn + num_channels; ch++) {
727 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
728 for (sfb = start_sfb[ch]; sfb < pstr_psy_chan_out->sfb_count; sfb++) {
729 if ((ah_flag[idx][sfb] != NO_AH) &&
730 (pstr_psy_chan_out->ptr_sfb_energy[sfb] > pstr_psy_chan_out->ptr_sfb_thr[sfb])) {
731 min_energy = MIN(min_energy, pstr_psy_chan_out->ptr_sfb_energy[sfb]);
732 average_energy += pstr_psy_chan_out->ptr_sfb_energy[sfb];
733 ah_cnt++;
734 }
735 }
736 idx++;
737 }
738
739 average_energy = MIN(MAX_FLT_VAL, average_energy / (ah_cnt + MIN_FLT_VAL));
740
741 for (en_idx = 0; en_idx < 4; en_idx++) {
742 energy[en_idx] = min_energy * (FLOAT32)pow(average_energy / (min_energy + MIN_FLT_VAL),
743 (2 * en_idx + 1) / 7.0f);
744 }
745 max_sfb = pstr_psy_out[chn].sfb_count - 1;
746 min_sfb = start_sfb[chn];
747
748 if (num_channels == 2) {
749 max_sfb = MAX(max_sfb, pstr_psy_out[chn + 1].sfb_count - 1);
750
751 min_sfb = MIN(min_sfb, start_sfb[chn + 1]);
752 }
753
754 sfb = max_sfb;
755 en_idx = 0;
756 done = 0;
757 while (!done) {
758 idx = 0;
759 for (ch = chn; ch < chn + num_channels; ch++) {
760 ia_psy_mod_out_data_struct *pstr_psy_chan_out = &pstr_psy_out[ch];
761 if (sfb >= start_sfb[ch] && sfb < pstr_psy_chan_out->sfb_count) {
762 if (ah_flag[idx][sfb] != NO_AH &&
763 pstr_psy_chan_out->ptr_sfb_energy[sfb] < energy[en_idx]) {
764 ah_flag[idx][sfb] = NO_AH;
765 pstr_psy_chan_out->ptr_sfb_thr[sfb] = 2.0f * pstr_psy_chan_out->ptr_sfb_energy[sfb];
766 act_pe -= pstr_qs_pe_data->pe_ch_data[idx].sfb_pe[sfb];
767 }
768
769 if (act_pe < desired_pe) {
770 done = 1;
771 break;
772 }
773 }
774 idx++;
775 }
776 sfb--;
777 if (sfb < min_sfb) {
778 sfb = max_sfb;
779 en_idx++;
780 if (en_idx >= 4) {
781 done = 1;
782 }
783 }
784 }
785 }
786
787 return;
788 }
789
iusace_adapt_thr_to_pe(ia_psy_mod_out_data_struct * pstr_psy_out,ia_qc_pe_data_struct * pstr_qs_pe_data,const FLOAT32 desired_pe,ia_ah_param_struct * str_ah_param,ia_min_snr_adapt_param_struct * msa_param,WORD32 num_channels,WORD32 chn,UWORD8 * ptr_scratch)790 static IA_ERRORCODE iusace_adapt_thr_to_pe(ia_psy_mod_out_data_struct *pstr_psy_out,
791 ia_qc_pe_data_struct *pstr_qs_pe_data,
792 const FLOAT32 desired_pe,
793 ia_ah_param_struct *str_ah_param,
794 ia_min_snr_adapt_param_struct *msa_param,
795 WORD32 num_channels, WORD32 chn, UWORD8 *ptr_scratch) {
796 IA_ERRORCODE err_code;
797 FLOAT32 no_red_pe, red_pe, red_pe_no_ah;
798 FLOAT32 const_part, const_part_no_ah;
799 FLOAT32 nactive_lines, nactive_lines_no_ah;
800 FLOAT32 desired_pe_no_ah;
801 FLOAT32 redval = 0.0f;
802 WORD32 *ah_flag[2];
803 WORD32 iteration;
804 for (WORD32 i = 0; i < 2; i++) {
805 ah_flag[i] = (WORD32 *)ptr_scratch;
806 ptr_scratch += (MAX_NUM_GROUPED_SFB) * sizeof(ah_flag[0][0]);
807 }
808 FLOAT32 *thr_exp[2];
809 for (WORD32 i = 0; i < 2; i++) {
810 thr_exp[i] = (FLOAT32 *)ptr_scratch;
811 ptr_scratch += (MAX_NUM_GROUPED_SFB) * sizeof(thr_exp[0][0]);
812 }
813
814 iusace_calc_thr_exp(thr_exp, pstr_psy_out, num_channels, chn);
815 iusace_adapt_min_snr(pstr_psy_out, msa_param, num_channels, chn);
816 iusace_init_avoid_hole_flag(ah_flag, pstr_psy_out, str_ah_param, num_channels, chn);
817
818 no_red_pe = pstr_qs_pe_data->pe;
819 const_part = pstr_qs_pe_data->const_part;
820 nactive_lines = pstr_qs_pe_data->num_active_lines;
821 if (nactive_lines > FLT_EPSILON) {
822 FLOAT32 avg_thr_exp = (FLOAT32)pow(2.0f, (const_part - no_red_pe) /
823 (INV_RED_EXP_VAL * nactive_lines));
824 redval = (FLOAT32)pow(2.0f, (const_part - desired_pe) / (INV_RED_EXP_VAL * nactive_lines)) -
825 avg_thr_exp;
826 redval = MAX(0.0f, redval);
827 iusace_reduce_thr(pstr_psy_out, ah_flag, thr_exp, redval, num_channels, chn);
828 }
829
830 iusace_calc_sfb_pe_data(pstr_qs_pe_data, pstr_psy_out, num_channels, chn);
831 red_pe = pstr_qs_pe_data->pe;
832
833 iteration = 0;
834 do {
835 iusace_calc_pe_no_active_holes(&red_pe_no_ah, &const_part_no_ah, &nactive_lines_no_ah,
836 pstr_qs_pe_data, ah_flag, pstr_psy_out, num_channels, chn);
837
838 desired_pe_no_ah = MAX(desired_pe - (red_pe - red_pe_no_ah), 0);
839 if (nactive_lines_no_ah > FLT_EPSILON) {
840 FLOAT32 avg_thr_exp = (FLOAT32)pow(
841 2.0f, (const_part_no_ah - red_pe_no_ah) / (INV_RED_EXP_VAL * nactive_lines_no_ah));
842 redval += (FLOAT32)pow(2.0f, (const_part_no_ah - desired_pe_no_ah) /
843 (INV_RED_EXP_VAL * nactive_lines_no_ah)) -
844 avg_thr_exp;
845 redval = MAX(0.0f, redval);
846 iusace_reduce_thr(pstr_psy_out, ah_flag, thr_exp, redval, num_channels, chn);
847 }
848
849 iusace_calc_sfb_pe_data(pstr_qs_pe_data, pstr_psy_out, num_channels, chn);
850 red_pe = pstr_qs_pe_data->pe;
851 iteration++;
852 } while ((fabs(red_pe - desired_pe) > (0.05f) * desired_pe) && (iteration < 2));
853 if (red_pe < 1.15f * desired_pe) {
854 err_code = iusace_correct_thr(pstr_psy_out, ah_flag, pstr_qs_pe_data, thr_exp, redval,
855 desired_pe - red_pe, num_channels, chn, ptr_scratch);
856 if (err_code != IA_NO_ERROR) {
857 return err_code;
858 }
859 } else {
860 iusace_reduce_min_snr(pstr_psy_out, pstr_qs_pe_data, ah_flag, 1.05f * desired_pe,
861 num_channels, chn);
862 iusace_allow_more_holes(pstr_psy_out, pstr_qs_pe_data, ah_flag, str_ah_param,
863 1.05f * desired_pe, num_channels, chn, ptr_scratch);
864 }
865
866 return IA_NO_ERROR;
867 }
868
iusace_adj_thr(ia_adj_thr_elem_struct * pstr_adj_thr_elem,ia_psy_mod_out_data_struct * pstr_psy_out,FLOAT32 * ch_bit_dist,ia_qc_out_data_struct * pstr_qc_out,const WORD32 avg_bits,const WORD32 bitres_bits,const WORD32 max_bitres_bits,const WORD32 side_info_bits,FLOAT32 * max_bit_fac,WORD32 num_channels,WORD32 chn,iusace_scratch_mem * pstr_scratch)869 IA_ERRORCODE iusace_adj_thr(ia_adj_thr_elem_struct *pstr_adj_thr_elem,
870 ia_psy_mod_out_data_struct *pstr_psy_out, FLOAT32 *ch_bit_dist,
871 ia_qc_out_data_struct *pstr_qc_out, const WORD32 avg_bits,
872 const WORD32 bitres_bits, const WORD32 max_bitres_bits,
873 const WORD32 side_info_bits, FLOAT32 *max_bit_fac,
874 WORD32 num_channels, WORD32 chn, iusace_scratch_mem *pstr_scratch) {
875 IA_ERRORCODE err_code;
876 FLOAT32 no_red_pe, granted_pe, granted_pe_corr;
877 WORD32 curr_win_sequence;
878 ia_qc_pe_data_struct *pstr_qc_pe_data = (ia_qc_pe_data_struct *)pstr_scratch->ptr_fd_scratch;
879 pUWORD8 ptr_scratch = pstr_scratch->ptr_fd_scratch + sizeof(ia_qc_pe_data_struct);
880 FLOAT32 bit_factor;
881 WORD32 ch;
882
883 pstr_qc_pe_data->pe_ch_data[0].sfb_lines = pstr_scratch->ptr_sfb_num_relevant_lines[0];
884 pstr_qc_pe_data->pe_ch_data[0].sfb_ld_energy = pstr_scratch->ptr_sfb_ld_energy[0];
885 if (num_channels == 2) {
886 pstr_qc_pe_data->pe_ch_data[1].sfb_lines = pstr_scratch->ptr_sfb_num_relevant_lines[1];
887 pstr_qc_pe_data->pe_ch_data[1].sfb_ld_energy = pstr_scratch->ptr_sfb_ld_energy[1];
888 }
889 pstr_qc_pe_data->offset = pstr_adj_thr_elem->pe_offset;
890
891 iusace_calc_sfb_pe_data(pstr_qc_pe_data, pstr_psy_out, num_channels, chn);
892 no_red_pe = pstr_qc_pe_data->pe;
893
894 curr_win_sequence = ONLY_LONG_SEQUENCE;
895 if (num_channels == 2) {
896 if ((pstr_psy_out[chn].window_sequence == EIGHT_SHORT_SEQUENCE) ||
897 (pstr_psy_out[chn + 1].window_sequence == EIGHT_SHORT_SEQUENCE)) {
898 curr_win_sequence = EIGHT_SHORT_SEQUENCE;
899 }
900 } else {
901 curr_win_sequence = pstr_psy_out[chn].window_sequence;
902 }
903
904 bit_factor =
905 iusace_bitres_calc_bitfac(bitres_bits, max_bitres_bits, no_red_pe + 5.0f * side_info_bits,
906 curr_win_sequence, avg_bits, *max_bit_fac, pstr_adj_thr_elem);
907 granted_pe = bit_factor * iusace_bits_to_pe((FLOAT32)avg_bits);
908 iusace_calc_pe_correction(&(pstr_adj_thr_elem->pe_correction_fac), MIN(granted_pe, no_red_pe),
909 pstr_adj_thr_elem->pe_last, pstr_adj_thr_elem->dyn_bits_last);
910 granted_pe_corr = granted_pe * pstr_adj_thr_elem->pe_correction_fac;
911
912 if (granted_pe_corr < no_red_pe) {
913 err_code = iusace_adapt_thr_to_pe(
914 pstr_psy_out, pstr_qc_pe_data, granted_pe_corr, &pstr_adj_thr_elem->str_ah_param,
915 &pstr_adj_thr_elem->str_min_snr_adapt_params, num_channels, chn, ptr_scratch);
916 if (err_code != IA_NO_ERROR) {
917 return err_code;
918 }
919 }
920
921 for (ch = 0; ch < num_channels; ch++) {
922 FLOAT32 tmp_var, temp1;
923 if (pstr_qc_pe_data->pe) {
924 tmp_var = 1.0f - num_channels * 0.2f;
925 temp1 = pstr_qc_pe_data->pe_ch_data[ch].pe / pstr_qc_pe_data->pe;
926 temp1 = temp1 * tmp_var;
927 ch_bit_dist[ch] = temp1 + 0.2f;
928 if (ch_bit_dist[ch] < 0.2f) ch_bit_dist[ch] = 0.2f;
929 } else {
930 ch_bit_dist[ch] = 0.2f;
931 }
932 }
933
934 pstr_qc_out->pe = no_red_pe;
935 pstr_adj_thr_elem->pe_last = granted_pe;
936
937 return IA_NO_ERROR;
938 }
939
iusace_calc_form_fac_per_chan(ia_psy_mod_out_data_struct * pstr_psy_out_chan,iusace_scratch_mem * pstr_scratch,WORD32 i_ch)940 VOID iusace_calc_form_fac_per_chan(ia_psy_mod_out_data_struct *pstr_psy_out_chan,
941 iusace_scratch_mem *pstr_scratch, WORD32 i_ch) {
942 WORD32 i, j, sfb_offs;
943 WORD32 sfb, sfb_width;
944 FLOAT32 *ptr_sfb_form_factor = pstr_scratch->ptr_sfb_form_fac[i_ch];
945 FLOAT32 *ptr_sfb_num_relevant_lines = pstr_scratch->ptr_sfb_num_relevant_lines[i_ch];
946 FLOAT32 *ptr_sfb_ld_energy = pstr_scratch->ptr_sfb_ld_energy[i_ch];
947 FLOAT64 spec_coef = 0;
948
949 memset(ptr_sfb_num_relevant_lines, 0, sizeof(FLOAT32) * pstr_psy_out_chan->sfb_count);
950
951 for (sfb_offs = 0; sfb_offs < pstr_psy_out_chan->sfb_count;
952 sfb_offs += pstr_psy_out_chan->sfb_per_group) {
953 i = sfb_offs;
954 for (sfb = 0; sfb < pstr_psy_out_chan->max_sfb_per_grp; sfb++, i++) {
955 ptr_sfb_form_factor[i] = MIN_FLT_VAL;
956 if (pstr_psy_out_chan->ptr_sfb_energy[i] > pstr_psy_out_chan->ptr_sfb_thr[i]) {
957 FLOAT32 avg_form_factor;
958
959 for (j = pstr_psy_out_chan->sfb_offsets[i]; j < pstr_psy_out_chan->sfb_offsets[i + 1];
960 j++) {
961 spec_coef = fabs(pstr_psy_out_chan->ptr_spec_coeffs[j]);
962 if (spec_coef < EPS && spec_coef != 0) spec_coef = EPS;
963 ptr_sfb_form_factor[i] += (FLOAT32)sqrt(spec_coef);
964 }
965
966 sfb_width = pstr_psy_out_chan->sfb_offsets[i + 1] - pstr_psy_out_chan->sfb_offsets[i];
967 avg_form_factor =
968 (FLOAT32)pow(pstr_psy_out_chan->ptr_sfb_energy[i] / (FLOAT32)sfb_width, 0.25);
969 ptr_sfb_num_relevant_lines[i] = ptr_sfb_form_factor[i] / avg_form_factor;
970 ptr_sfb_ld_energy[i] = (FLOAT32)(log(pstr_psy_out_chan->ptr_sfb_energy[i]) * LOG2_1);
971 }
972 }
973 }
974
975 return;
976 }
977
iusace_quantize_lines(const WORD32 gain,const WORD32 num_lines,FLOAT32 * ptr_exp_spectrum,WORD16 * ptr_quant_spectrum,FLOAT32 * ptr_mdct_spec)978 VOID iusace_quantize_lines(const WORD32 gain, const WORD32 num_lines, FLOAT32 *ptr_exp_spectrum,
979 WORD16 *ptr_quant_spectrum, FLOAT32 *ptr_mdct_spec) {
980 FLOAT32 quantizer;
981 FLOAT32 k = 0.4054f;
982 WORD32 line;
983
984 quantizer = ixheaace_fd_quant_table[gain + 128];
985 for (line = 0; line < num_lines; line++) {
986 FLOAT32 tmp = ptr_mdct_spec[line];
987 if (tmp < 0.0f) {
988 ptr_exp_spectrum[line] = (FLOAT32)sqrt(-tmp);
989 ptr_exp_spectrum[line] *= (FLOAT32)sqrt(ptr_exp_spectrum[line]);
990 ptr_quant_spectrum[line] = -(WORD16)(k + quantizer * ptr_exp_spectrum[line]);
991 } else {
992 ptr_exp_spectrum[line] = (FLOAT32)sqrt(tmp);
993 ptr_exp_spectrum[line] *= (FLOAT32)sqrt(ptr_exp_spectrum[line]);
994 ptr_quant_spectrum[line] = (WORD16)(k + quantizer * ptr_exp_spectrum[line]);
995 }
996 }
997 return;
998 }
999
iusace_calculate_exp_spec(const WORD32 num_lines,FLOAT32 * ptr_exp_spectrum,FLOAT32 * ptr_mdct_spec)1000 VOID iusace_calculate_exp_spec(const WORD32 num_lines, FLOAT32 *ptr_exp_spectrum,
1001 FLOAT32 *ptr_mdct_spec) {
1002 WORD32 line;
1003
1004 for (line = 0; line < num_lines; line++) {
1005 ptr_exp_spectrum[line] = (FLOAT32)sqrt(fabs(ptr_mdct_spec[line]));
1006 ptr_exp_spectrum[line] *= (FLOAT32)sqrt(ptr_exp_spectrum[line]);
1007 }
1008 return;
1009 }
1010
iusace_scf_delta_bit_count(WORD32 delta)1011 static WORD32 iusace_scf_delta_bit_count(WORD32 delta) {
1012 if (delta > 60) {
1013 return (iusace_huffman_code_table[120][0]);
1014 }
1015 if (delta < -60) {
1016 return (iusace_huffman_code_table[0][0]);
1017 }
1018 return (iusace_huffman_code_table[delta + 60][0]);
1019 }
1020
iusace_count_single_scf_bits(WORD32 scf,WORD32 left_scf,WORD32 right_scf)1021 static WORD32 iusace_count_single_scf_bits(WORD32 scf, WORD32 left_scf, WORD32 right_scf) {
1022 WORD32 scf_bits;
1023
1024 scf_bits =
1025 iusace_scf_delta_bit_count(left_scf - scf) + iusace_scf_delta_bit_count(scf - right_scf);
1026
1027 return scf_bits;
1028 }
1029
iusace_calc_single_spec_pe(WORD32 scf,FLOAT32 sfb_const_pe_part,FLOAT32 num_lines)1030 static FLOAT32 iusace_calc_single_spec_pe(WORD32 scf, FLOAT32 sfb_const_pe_part,
1031 FLOAT32 num_lines) {
1032 FLOAT32 spec_pe;
1033 FLOAT32 ld_ratio;
1034
1035 ld_ratio = sfb_const_pe_part - (FLOAT32)0.375f * (FLOAT32)scf;
1036
1037 if (ld_ratio >= PE_C1) {
1038 spec_pe = (FLOAT32)0.7f * num_lines * ld_ratio;
1039 } else {
1040 spec_pe = (FLOAT32)0.7f * num_lines * (PE_C2 + PE_C3 * ld_ratio);
1041 }
1042
1043 return spec_pe;
1044 }
1045
iusace_count_scf_bits_diff(WORD16 * ptr_sfb_prev,WORD16 * ptr_sfb_new,WORD32 sfb_count,WORD32 start_sfb,WORD32 stop_sfb)1046 static WORD32 iusace_count_scf_bits_diff(WORD16 *ptr_sfb_prev, WORD16 *ptr_sfb_new,
1047 WORD32 sfb_count, WORD32 start_sfb, WORD32 stop_sfb) {
1048 WORD32 scf_bits_diff = 0;
1049 WORD32 sfb = 0, sfb_last;
1050 WORD32 sfb_prev, sfb_next;
1051
1052 sfb_last = start_sfb;
1053
1054 while ((sfb_last < stop_sfb) && (ptr_sfb_prev[sfb_last] == SHRT_MIN)) {
1055 sfb_last++;
1056 }
1057
1058 sfb_prev = start_sfb - 1;
1059
1060 while ((sfb_prev >= 0) && (ptr_sfb_prev[sfb_prev] == SHRT_MIN)) {
1061 sfb_prev--;
1062 }
1063
1064 if (sfb_prev >= 0) {
1065 scf_bits_diff += iusace_scf_delta_bit_count(ptr_sfb_new[sfb_prev] - ptr_sfb_new[sfb_last]) -
1066 iusace_scf_delta_bit_count(ptr_sfb_prev[sfb_prev] - ptr_sfb_prev[sfb_last]);
1067 }
1068
1069 for (sfb = sfb_last + 1; sfb < stop_sfb; sfb++) {
1070 if (ptr_sfb_prev[sfb] != SHRT_MIN) {
1071 scf_bits_diff += iusace_scf_delta_bit_count(ptr_sfb_new[sfb_last] - ptr_sfb_new[sfb]) -
1072 iusace_scf_delta_bit_count(ptr_sfb_prev[sfb_last] - ptr_sfb_prev[sfb]);
1073
1074 sfb_last = sfb;
1075 }
1076 }
1077
1078 sfb_next = stop_sfb;
1079
1080 while ((sfb_next < sfb_count) && (ptr_sfb_prev[sfb_next] == SHRT_MIN)) {
1081 sfb_next++;
1082 }
1083
1084 if (sfb_next < sfb_count) {
1085 scf_bits_diff += iusace_scf_delta_bit_count(ptr_sfb_new[sfb_last] - ptr_sfb_new[sfb_next]) -
1086 iusace_scf_delta_bit_count(ptr_sfb_prev[sfb_last] - ptr_sfb_prev[sfb_next]);
1087 }
1088
1089 return scf_bits_diff;
1090 }
1091
iusace_calc_spec_pe_diff(ia_psy_mod_out_data_struct * pstr_psy_out,WORD16 * scf_prev,WORD16 * scf_new,FLOAT32 * ptr_sfb_const_pe_part,FLOAT32 * ptr_sfb_form_fac,FLOAT32 * ptr_sfb_num_rel_lines,WORD32 start_sfb,WORD32 stop_sfb)1092 static FLOAT32 iusace_calc_spec_pe_diff(ia_psy_mod_out_data_struct *pstr_psy_out,
1093 WORD16 *scf_prev, WORD16 *scf_new,
1094 FLOAT32 *ptr_sfb_const_pe_part, FLOAT32 *ptr_sfb_form_fac,
1095 FLOAT32 *ptr_sfb_num_rel_lines, WORD32 start_sfb,
1096 WORD32 stop_sfb) {
1097 FLOAT32 spec_pe_diff = 0.0f;
1098 WORD32 sfb;
1099
1100 for (sfb = start_sfb; sfb < stop_sfb; sfb++) {
1101 if (scf_prev[sfb] != SHRT_MIN) {
1102 FLOAT32 ld_ratio_prev, ld_ratio_new, pe_prev, pe_new;
1103
1104 if (ptr_sfb_const_pe_part[sfb] == MIN_FLT_VAL) {
1105 ptr_sfb_const_pe_part[sfb] = (FLOAT32)log(pstr_psy_out->ptr_sfb_energy[sfb] *
1106 (FLOAT32)6.75f / ptr_sfb_form_fac[sfb]) *
1107 LOG2_1;
1108 }
1109
1110 ld_ratio_prev = ptr_sfb_const_pe_part[sfb] - 0.375f * scf_prev[sfb];
1111 ld_ratio_new = ptr_sfb_const_pe_part[sfb] - 0.375f * scf_new[sfb];
1112
1113 if (ld_ratio_prev >= PE_C1) {
1114 pe_prev = ld_ratio_prev;
1115 } else {
1116 pe_prev = PE_C2 + PE_C3 * ld_ratio_prev;
1117 }
1118
1119 if (ld_ratio_new >= PE_C1) {
1120 pe_new = ld_ratio_new;
1121 } else {
1122 pe_new = PE_C2 + PE_C3 * ld_ratio_new;
1123 }
1124
1125 spec_pe_diff += (FLOAT32)0.7f * ptr_sfb_num_rel_lines[sfb] * (pe_new - pe_prev);
1126 }
1127 }
1128
1129 return spec_pe_diff;
1130 }
1131
iusace_calc_sfb_dist(const FLOAT32 * ptr_spec,const FLOAT32 * ptr_exp_spec,WORD16 * ptr_quant_spec,WORD32 sfb_width,WORD32 gain)1132 FLOAT32 iusace_calc_sfb_dist(const FLOAT32 *ptr_spec, const FLOAT32 *ptr_exp_spec,
1133 WORD16 *ptr_quant_spec, WORD32 sfb_width, WORD32 gain) {
1134 WORD32 i;
1135 FLOAT32 dist = 0;
1136 FLOAT32 k = 0.4054f;
1137 FLOAT32 quantizer = ixheaace_fd_quant_table[gain + 128];
1138 FLOAT32 inv_quantizer = ixheaace_fd_inv_quant_table[gain + 128];
1139
1140 for (i = 0; i < sfb_width; i++) {
1141 FLOAT32 iq_val;
1142 FLOAT32 diff;
1143
1144 ptr_quant_spec[i] = (WORD16)(k + quantizer * ptr_exp_spec[i]);
1145
1146 if (ptr_quant_spec[i] < 64) {
1147 iq_val = ixheaace_pow_4_3_table[ptr_quant_spec[i]] * inv_quantizer;
1148 } else {
1149 iq_val = (FLOAT32)((pow((FLOAT32)abs(ptr_quant_spec[i]), 4.0f / 3.0f)) * inv_quantizer);
1150 }
1151
1152 diff = (FLOAT32)fabs(ptr_spec[i]) - iq_val;
1153
1154 dist += diff * diff;
1155 }
1156
1157 return dist;
1158 }
1159
iusace_improve_scf(FLOAT32 * ptr_spec,FLOAT32 * ptr_exp_spec,WORD16 * ptr_quant_spec,WORD16 * ptr_quant_spec_temp,WORD32 sfb_width,FLOAT32 threshold,WORD16 scf,WORD16 min_scf,FLOAT32 * dist,WORD16 * ptr_min_calc_scf)1160 static WORD16 iusace_improve_scf(FLOAT32 *ptr_spec, FLOAT32 *ptr_exp_spec, WORD16 *ptr_quant_spec,
1161 WORD16 *ptr_quant_spec_temp, WORD32 sfb_width, FLOAT32 threshold,
1162 WORD16 scf, WORD16 min_scf, FLOAT32 *dist,
1163 WORD16 *ptr_min_calc_scf) {
1164 FLOAT32 sfb_dist;
1165 WORD16 best_scf = scf;
1166 WORD32 j;
1167
1168 sfb_dist = iusace_calc_sfb_dist(ptr_spec, ptr_exp_spec, ptr_quant_spec, sfb_width, scf);
1169
1170 *ptr_min_calc_scf = scf;
1171
1172 if (sfb_dist > (1.25 * threshold)) {
1173 WORD16 estimated_scf = scf;
1174 FLOAT32 best_sfb_dist = sfb_dist;
1175 WORD32 count;
1176
1177 count = 0;
1178
1179 while ((sfb_dist > (1.25 * threshold)) && (count++ < SCF_COUNT_LIMIT_THREE)) {
1180 scf++;
1181
1182 sfb_dist =
1183 iusace_calc_sfb_dist(ptr_spec, ptr_exp_spec, ptr_quant_spec_temp, sfb_width, scf);
1184
1185 if (sfb_dist < best_sfb_dist) {
1186 best_scf = scf;
1187 best_sfb_dist = sfb_dist;
1188
1189 memcpy(ptr_quant_spec, ptr_quant_spec_temp, sfb_width * sizeof(WORD16));
1190 }
1191 }
1192
1193 count = 0;
1194 scf = estimated_scf;
1195 sfb_dist = best_sfb_dist;
1196
1197 while ((sfb_dist > (1.25 * threshold)) && (count++ < SCF_COUNT_LIMIT_ONE) &&
1198 (scf > min_scf)) {
1199 scf--;
1200
1201 sfb_dist =
1202 iusace_calc_sfb_dist(ptr_spec, ptr_exp_spec, ptr_quant_spec_temp, sfb_width, scf);
1203
1204 if (sfb_dist < best_sfb_dist) {
1205 best_scf = scf;
1206 best_sfb_dist = sfb_dist;
1207
1208 memcpy(ptr_quant_spec, ptr_quant_spec_temp, sfb_width * sizeof(WORD16));
1209 }
1210 *ptr_min_calc_scf = scf;
1211 }
1212 *dist = best_sfb_dist;
1213 } else {
1214 FLOAT32 best_sfb_dist = sfb_dist;
1215 FLOAT32 allowed_sfb_dist = MIN(sfb_dist * 1.25f, threshold);
1216 WORD32 count;
1217
1218 for (count = 0; count < SCF_COUNT_LIMIT_THREE; count++) {
1219 scf++;
1220
1221 sfb_dist =
1222 iusace_calc_sfb_dist(ptr_spec, ptr_exp_spec, ptr_quant_spec_temp, sfb_width, scf);
1223
1224 if (sfb_dist < allowed_sfb_dist) {
1225 *ptr_min_calc_scf = best_scf + 1;
1226
1227 best_scf = scf;
1228 best_sfb_dist = sfb_dist;
1229 memcpy(ptr_quant_spec, ptr_quant_spec_temp, sfb_width * sizeof(WORD16));
1230 }
1231 }
1232 *dist = best_sfb_dist;
1233 }
1234
1235 for (j = 0; j < sfb_width; j++) {
1236 if (ptr_spec[j] < 0) {
1237 ptr_quant_spec[j] = -ptr_quant_spec[j];
1238 }
1239 }
1240
1241 return best_scf;
1242 }
1243
iusace_assimilate_single_scf(ia_psy_mod_out_data_struct * pstr_psy_out,FLOAT32 * ptr_exp_spec,WORD16 * ptr_quant_spec,WORD16 * ptr_quant_spec_temp,WORD16 * scf,WORD16 * ptr_min_scf,FLOAT32 * ptr_sfb_dist,FLOAT32 * ptr_sfb_const_pe_part,FLOAT32 * ptr_sfb_form_fac,FLOAT32 * ptr_sfb_num_lines,WORD16 * ptr_min_calc_scf,FLOAT32 * ptr_mdct_spec_float)1244 static VOID iusace_assimilate_single_scf(ia_psy_mod_out_data_struct *pstr_psy_out,
1245 FLOAT32 *ptr_exp_spec, WORD16 *ptr_quant_spec,
1246 WORD16 *ptr_quant_spec_temp, WORD16 *scf,
1247 WORD16 *ptr_min_scf, FLOAT32 *ptr_sfb_dist,
1248 FLOAT32 *ptr_sfb_const_pe_part,
1249 FLOAT32 *ptr_sfb_form_fac, FLOAT32 *ptr_sfb_num_lines,
1250 WORD16 *ptr_min_calc_scf, FLOAT32 *ptr_mdct_spec_float) {
1251 WORD32 sfb_prev, sfb_act, sfb_next;
1252 WORD16 scf_act = 0, *scf_prev, *scf_next, min_scf, max_scf;
1253 WORD32 sfb_width, sfb_offs;
1254 FLOAT32 energy;
1255 FLOAT32 sfb_pe_prev, sfb_pe_new;
1256 FLOAT32 sfb_dist_new;
1257 WORD32 j;
1258 WORD32 success = 0;
1259 FLOAT32 delta_pe = 0.0f, delta_pe_new, delta_pe_temp;
1260 WORD16 prev_scf_last[MAX_NUM_GROUPED_SFB], prev_scf_next[MAX_NUM_GROUPED_SFB];
1261 FLOAT32 delta_pe_last[MAX_NUM_GROUPED_SFB];
1262 WORD32 update_min_scf;
1263
1264 for (j = 0; j < pstr_psy_out->sfb_count; j++) {
1265 prev_scf_last[j] = SHRT_MAX;
1266 prev_scf_next[j] = SHRT_MAX;
1267 delta_pe_last[j] = MAX_FLT_VAL;
1268 }
1269
1270 sfb_prev = -1;
1271 sfb_act = -1;
1272 sfb_next = -1;
1273 scf_prev = 0;
1274 scf_next = 0;
1275 min_scf = SHRT_MAX;
1276 max_scf = SHRT_MAX;
1277
1278 do {
1279 sfb_next++;
1280
1281 while ((sfb_next < pstr_psy_out->sfb_count) && (scf[sfb_next] == SHRT_MIN)) {
1282 sfb_next++;
1283 }
1284
1285 if ((sfb_prev >= 0) && (sfb_act >= 0) && (sfb_next < pstr_psy_out->sfb_count)) {
1286 scf_act = scf[sfb_act];
1287
1288 scf_prev = scf + sfb_prev;
1289 scf_next = scf + sfb_next;
1290
1291 min_scf = MIN(*scf_prev, *scf_next);
1292
1293 max_scf = MAX(*scf_prev, *scf_next);
1294 } else {
1295 if ((sfb_prev == -1) && (sfb_act >= 0) && (sfb_next < pstr_psy_out->sfb_count)) {
1296 scf_act = scf[sfb_act];
1297
1298 scf_prev = &scf_act;
1299
1300 scf_next = scf + sfb_next;
1301
1302 min_scf = *scf_next;
1303
1304 max_scf = *scf_next;
1305 } else {
1306 if ((sfb_prev >= 0) && (sfb_act >= 0) && (sfb_next == pstr_psy_out->sfb_count)) {
1307 scf_act = scf[sfb_act];
1308
1309 scf_prev = scf + sfb_prev;
1310
1311 scf_next = &scf_act;
1312
1313 min_scf = *scf_prev;
1314
1315 max_scf = *scf_prev;
1316 }
1317 }
1318 }
1319
1320 if (sfb_act >= 0) {
1321 min_scf = MAX(min_scf, ptr_min_scf[sfb_act]);
1322 }
1323
1324 if ((sfb_act >= 0) && (sfb_prev >= 0 || sfb_next < pstr_psy_out->sfb_count) &&
1325 (scf_act > min_scf) && (scf_act <= min_scf + MAX_SCF_DELTA) &&
1326 (scf_act >= max_scf - MAX_SCF_DELTA) &&
1327 (*scf_prev != prev_scf_last[sfb_act] || *scf_next != prev_scf_next[sfb_act] ||
1328 delta_pe < delta_pe_last[sfb_act])) {
1329 success = 0;
1330
1331 sfb_width = pstr_psy_out->sfb_offsets[sfb_act + 1] - pstr_psy_out->sfb_offsets[sfb_act];
1332
1333 sfb_offs = pstr_psy_out->sfb_offsets[sfb_act];
1334
1335 energy = pstr_psy_out->ptr_sfb_energy[sfb_act];
1336
1337 if (ptr_sfb_const_pe_part[sfb_act] == MIN_FLT_VAL) {
1338 ptr_sfb_const_pe_part[sfb_act] =
1339 (FLOAT32)log(energy * (FLOAT32)6.75f / ptr_sfb_form_fac[sfb_act]) * LOG2_1;
1340 }
1341
1342 sfb_pe_prev = iusace_calc_single_spec_pe(scf_act, ptr_sfb_const_pe_part[sfb_act],
1343 ptr_sfb_num_lines[sfb_act]) +
1344 iusace_count_single_scf_bits(scf_act, *scf_prev, *scf_next);
1345
1346 delta_pe_new = delta_pe;
1347 update_min_scf = 1;
1348
1349 do {
1350 scf_act--;
1351
1352 if (scf_act < ptr_min_calc_scf[sfb_act] && scf_act >= max_scf - MAX_SCF_DELTA) {
1353 sfb_pe_new = iusace_calc_single_spec_pe(scf_act, ptr_sfb_const_pe_part[sfb_act],
1354 ptr_sfb_num_lines[sfb_act]) +
1355 (FLOAT32)iusace_count_single_scf_bits(scf_act, *scf_prev, *scf_next);
1356
1357 delta_pe_temp = delta_pe + sfb_pe_new - sfb_pe_prev;
1358
1359 if (delta_pe_temp < (FLOAT32)10.0f) {
1360 sfb_dist_new =
1361 iusace_calc_sfb_dist(ptr_mdct_spec_float + sfb_offs, ptr_exp_spec + sfb_offs,
1362 ptr_quant_spec_temp + sfb_offs, sfb_width, scf_act);
1363
1364 if (sfb_dist_new < ptr_sfb_dist[sfb_act]) {
1365 scf[sfb_act] = scf_act;
1366 ptr_sfb_dist[sfb_act] = sfb_dist_new;
1367
1368 for (j = sfb_offs; j < sfb_offs + sfb_width; j++) {
1369 ptr_quant_spec[j] = ptr_quant_spec_temp[j];
1370
1371 if (ptr_mdct_spec_float[j] < 0.0f) {
1372 ptr_quant_spec[j] = -ptr_quant_spec[j];
1373 }
1374 }
1375 delta_pe_new = delta_pe_temp;
1376 success = 1;
1377 }
1378
1379 if (update_min_scf) {
1380 ptr_min_calc_scf[sfb_act] = scf_act;
1381 }
1382 } else {
1383 update_min_scf = 0;
1384 }
1385 }
1386 } while (scf_act > min_scf);
1387
1388 delta_pe = delta_pe_new;
1389
1390 prev_scf_last[sfb_act] = *scf_prev;
1391 prev_scf_next[sfb_act] = *scf_next;
1392 delta_pe_last[sfb_act] = delta_pe;
1393 }
1394
1395 if (success) {
1396 sfb_prev = -1;
1397 sfb_act = -1;
1398 sfb_next = -1;
1399 scf_prev = 0;
1400 scf_next = 0;
1401 min_scf = SHRT_MAX;
1402 max_scf = SHRT_MAX;
1403 success = 0;
1404 } else {
1405 sfb_prev = sfb_act;
1406 sfb_act = sfb_next;
1407 }
1408 } while (sfb_next < pstr_psy_out->sfb_count);
1409 return;
1410 }
1411
iusace_assimilate_multiple_scf(ia_psy_mod_out_data_struct * pstr_psy_out,FLOAT32 * ptr_exp_spec,WORD16 * ptr_quant_spec,WORD16 * ptr_quant_spec_temp,WORD16 * ptr_scf,WORD16 * ptr_min_scf,FLOAT32 * ptr_sfb_dist,FLOAT32 * ptr_sfb_const_pe_part,FLOAT32 * ptr_sfb_form_fac,FLOAT32 * ptr_sfb_num_lines,FLOAT32 * ptr_mdct_spec_float,pUWORD8 pstr_scratch)1412 static VOID iusace_assimilate_multiple_scf(ia_psy_mod_out_data_struct *pstr_psy_out,
1413 FLOAT32 *ptr_exp_spec, WORD16 *ptr_quant_spec,
1414 WORD16 *ptr_quant_spec_temp, WORD16 *ptr_scf,
1415 WORD16 *ptr_min_scf, FLOAT32 *ptr_sfb_dist,
1416 FLOAT32 *ptr_sfb_const_pe_part,
1417 FLOAT32 *ptr_sfb_form_fac, FLOAT32 *ptr_sfb_num_lines,
1418 FLOAT32 *ptr_mdct_spec_float, pUWORD8 pstr_scratch) {
1419 WORD32 sfb, start_sfb, stop_sfb;
1420 WORD16 scf_temp[MAX_NUM_GROUPED_SFB], min_scf, max_scf, scf_act;
1421 WORD32 possible_region_found;
1422 WORD32 sfb_width, sfb_offs, j;
1423 FLOAT32 prev_dist_sum, new_dist_sum;
1424 WORD32 delta_scf_bits;
1425 FLOAT32 delta_spec_pe;
1426 FLOAT32 delta_pe = 0.0f, delta_pe_new;
1427 WORD32 sfb_count = pstr_psy_out->sfb_count;
1428 FLOAT32 *sfb_dist_new = (FLOAT32 *)pstr_scratch;
1429 min_scf = SHRT_MAX;
1430 max_scf = SHRT_MIN;
1431
1432 for (sfb = 0; sfb < sfb_count; sfb++) {
1433 if (ptr_scf[sfb] != SHRT_MIN) {
1434 min_scf = MIN(min_scf, ptr_scf[sfb]);
1435
1436 max_scf = MAX(max_scf, ptr_scf[sfb]);
1437 }
1438 }
1439
1440 if (max_scf != SHRT_MIN && max_scf <= min_scf + MAX_SCF_DELTA) {
1441 scf_act = max_scf;
1442
1443 do {
1444 scf_act--;
1445
1446 memcpy(scf_temp, ptr_scf, MAX_NUM_GROUPED_SFB * sizeof(WORD16));
1447
1448 stop_sfb = 0;
1449
1450 do {
1451 sfb = stop_sfb;
1452
1453 while (sfb < sfb_count && (ptr_scf[sfb] == SHRT_MIN || ptr_scf[sfb] <= scf_act)) {
1454 sfb++;
1455 }
1456
1457 start_sfb = sfb;
1458
1459 sfb++;
1460
1461 while (sfb < sfb_count && (ptr_scf[sfb] == SHRT_MIN || ptr_scf[sfb] > scf_act)) {
1462 sfb++;
1463 }
1464
1465 stop_sfb = sfb;
1466
1467 possible_region_found = 0;
1468
1469 if (start_sfb < sfb_count) {
1470 possible_region_found = 1;
1471
1472 for (sfb = start_sfb; sfb < stop_sfb; sfb++) {
1473 if (ptr_scf[sfb] != SHRT_MIN) {
1474 if (scf_act < ptr_min_scf[sfb]) {
1475 possible_region_found = 0;
1476 break;
1477 }
1478 }
1479 }
1480 }
1481
1482 if (possible_region_found) {
1483 for (sfb = start_sfb; sfb < stop_sfb; sfb++) {
1484 if (scf_temp[sfb] != SHRT_MIN) {
1485 scf_temp[sfb] = scf_act;
1486 }
1487 }
1488
1489 delta_scf_bits =
1490 iusace_count_scf_bits_diff(ptr_scf, scf_temp, sfb_count, start_sfb, stop_sfb);
1491
1492 delta_spec_pe =
1493 iusace_calc_spec_pe_diff(pstr_psy_out, ptr_scf, scf_temp, ptr_sfb_const_pe_part,
1494 ptr_sfb_form_fac, ptr_sfb_num_lines, start_sfb, stop_sfb);
1495
1496 delta_pe_new = delta_pe + (FLOAT32)delta_scf_bits + delta_spec_pe;
1497
1498 if (delta_pe_new < (FLOAT32)10.0f) {
1499 prev_dist_sum = new_dist_sum = 0.0f;
1500
1501 for (sfb = start_sfb; sfb < stop_sfb; sfb++) {
1502 if (scf_temp[sfb] != SHRT_MIN) {
1503 prev_dist_sum += ptr_sfb_dist[sfb];
1504
1505 sfb_width = pstr_psy_out->sfb_offsets[sfb + 1] - pstr_psy_out->sfb_offsets[sfb];
1506
1507 sfb_offs = pstr_psy_out->sfb_offsets[sfb];
1508
1509 sfb_dist_new[sfb] =
1510 iusace_calc_sfb_dist(ptr_mdct_spec_float + sfb_offs, ptr_exp_spec + sfb_offs,
1511 ptr_quant_spec_temp + sfb_offs, sfb_width, scf_act);
1512
1513 if (sfb_dist_new[sfb] > pstr_psy_out->ptr_sfb_thr[sfb]) {
1514 new_dist_sum = (FLOAT32)2.0f * prev_dist_sum;
1515 break;
1516 }
1517
1518 new_dist_sum += sfb_dist_new[sfb];
1519 }
1520 }
1521
1522 if (new_dist_sum < prev_dist_sum) {
1523 delta_pe = delta_pe_new;
1524
1525 for (sfb = start_sfb; sfb < stop_sfb; sfb++) {
1526 if (ptr_scf[sfb] != SHRT_MIN) {
1527 sfb_width = pstr_psy_out->sfb_offsets[sfb + 1] - pstr_psy_out->sfb_offsets[sfb];
1528
1529 sfb_offs = pstr_psy_out->sfb_offsets[sfb];
1530 ptr_scf[sfb] = scf_act;
1531 ptr_sfb_dist[sfb] = sfb_dist_new[sfb];
1532
1533 for (j = sfb_offs; j < sfb_offs + sfb_width; j++) {
1534 ptr_quant_spec[j] = ptr_quant_spec_temp[j];
1535
1536 if (ptr_mdct_spec_float[j] < 0.0f) {
1537 ptr_quant_spec[j] = -ptr_quant_spec[j];
1538 }
1539 }
1540 }
1541 }
1542 }
1543 }
1544 }
1545
1546 } while (stop_sfb <= sfb_count);
1547
1548 } while (scf_act > min_scf);
1549 }
1550 return;
1551 }
1552
iusace_estimate_scfs_chan(ia_psy_mod_out_data_struct * pstr_psy_out,ia_qc_out_chan_struct * str_qc_out_chan,WORD32 num_channels,WORD32 chn,iusace_scratch_mem * pstr_scratch)1553 VOID iusace_estimate_scfs_chan(ia_psy_mod_out_data_struct *pstr_psy_out,
1554 ia_qc_out_chan_struct *str_qc_out_chan, WORD32 num_channels,
1555 WORD32 chn, iusace_scratch_mem *pstr_scratch) {
1556 WORD16 *ptr_scalefactor;
1557 WORD32 *global_gain;
1558 FLOAT32 *p_sfb_form_factor;
1559 FLOAT32 *p_sfb_num_relevant_lines;
1560 WORD16 *ptr_quant_spec;
1561 WORD32 i, ch, j, idx = 0;
1562 FLOAT32 thresh, energy, energy_part, thr_part;
1563 FLOAT32 scf_float;
1564 WORD16 scf_int = 0, min_scf = 0, max_scf = 0;
1565 FLOAT64 max_spec = 0.0f;
1566 WORD16 min_sf_max_quant[MAX_NUM_GROUPED_SFB] = {0};
1567 pUWORD8 ptr_scratch = pstr_scratch->ptr_fd_scratch;
1568 FLOAT32 *ptr_sfb_dist = (FLOAT32 *)ptr_scratch;
1569 ptr_scratch += MAX_NUM_GROUPED_SFB * sizeof(ptr_sfb_dist[0]);
1570 WORD16 min_calc_scf[MAX_NUM_GROUPED_SFB] = {0};
1571
1572 WORD16 *ptr_quant_spec_temp = pstr_scratch->p_adjthr_quant_spec_temp;
1573 FLOAT32 *ptr_exp_spec = pstr_scratch->p_adjthr_ptr_exp_spec;
1574 FLOAT32 *ptr_mdct_spec_float = pstr_scratch->p_adjthr_mdct_spec_float;
1575 FLOAT32 *sfb_const_pe_part = (FLOAT32 *)ptr_scratch;
1576
1577 FLOAT32 **ptr_sfb_form_factor = &pstr_scratch->ptr_sfb_form_fac[0];
1578 FLOAT32 **ptr_sfb_num_relevant_lines = &pstr_scratch->ptr_sfb_num_relevant_lines[0];
1579
1580 ptr_scratch += MAX_NUM_GROUPED_SFB * sizeof(sfb_const_pe_part[0]);
1581
1582 memset(ptr_quant_spec_temp, 0, FRAME_LEN_LONG * sizeof(WORD16));
1583 memset(ptr_mdct_spec_float, 0, FRAME_LEN_LONG * sizeof(FLOAT32));
1584 memset(ptr_exp_spec, 0, FRAME_LEN_LONG * sizeof(FLOAT32));
1585 memset(ptr_sfb_dist, 0, MAX_NUM_GROUPED_SFB * sizeof(FLOAT32));
1586 for (ch = chn; ch < chn + num_channels; ch++) {
1587 ia_psy_mod_out_data_struct *ptr_psy_out = &pstr_psy_out[ch];
1588 str_qc_out_chan[idx].global_gain = 0;
1589
1590 memset(str_qc_out_chan[idx].scalefactor, 0,
1591 sizeof(str_qc_out_chan[idx].scalefactor[0]) * pstr_psy_out[ch].sfb_count);
1592 memset(str_qc_out_chan[idx].quant_spec, 0,
1593 sizeof(str_qc_out_chan[idx].quant_spec[0]) * FRAME_LEN_LONG);
1594
1595 ptr_scalefactor = str_qc_out_chan[idx].scalefactor;
1596 global_gain = &str_qc_out_chan[idx].global_gain;
1597 p_sfb_form_factor = &ptr_sfb_form_factor[idx][0];
1598 p_sfb_num_relevant_lines = &ptr_sfb_num_relevant_lines[idx][0];
1599 ptr_quant_spec = str_qc_out_chan[idx].quant_spec;
1600 for (i = 0; i < ptr_psy_out->sfb_count; i++) {
1601 thresh = ptr_psy_out->ptr_sfb_thr[i];
1602 energy = ptr_psy_out->ptr_sfb_energy[i];
1603 max_spec = 0.0;
1604
1605 for (j = ptr_psy_out->sfb_offsets[i]; j < ptr_psy_out->sfb_offsets[i + 1]; j++) {
1606 max_spec = MAX(max_spec, fabs(ptr_psy_out->ptr_spec_coeffs[j]));
1607 }
1608
1609 ptr_scalefactor[i] = MIN_SHRT_VAL;
1610 min_sf_max_quant[i] = MIN_SHRT_VAL;
1611
1612 if ((max_spec > 0.0) && (energy > thresh) && (p_sfb_form_factor[i] != MIN_FLT_VAL)) {
1613 energy_part = (FLOAT32)log10(p_sfb_form_factor[i] + FLT_EPSILON);
1614
1615 thr_part = (FLOAT32)log10(6.75 * thresh + MIN_FLT_VAL);
1616 scf_float = 8.8585f * (thr_part - energy_part);
1617 scf_int = (WORD16)floor(scf_float);
1618 min_sf_max_quant[i] = (WORD16)ceil(C1_SF + C2_SF * log(max_spec));
1619 scf_int = MAX(scf_int, min_sf_max_quant[i]);
1620 scf_int = MAX(scf_int, MIN_GAIN_INDEX);
1621 scf_int = MIN(scf_int, (MAX_GAIN_INDEX - SCF_COUNT_LIMIT_THREE));
1622 for (j = 0; j < ptr_psy_out->sfb_offsets[i + 1] - ptr_psy_out->sfb_offsets[i]; j++) {
1623 ptr_exp_spec[ptr_psy_out->sfb_offsets[i] + j] =
1624 (FLOAT32)(ptr_psy_out->ptr_spec_coeffs[ptr_psy_out->sfb_offsets[i] + j]);
1625 ptr_mdct_spec_float[ptr_psy_out->sfb_offsets[i] + j] =
1626 (FLOAT32)(ptr_psy_out->ptr_spec_coeffs[ptr_psy_out->sfb_offsets[i] + j]);
1627 }
1628
1629 iusace_calculate_exp_spec(ptr_psy_out->sfb_offsets[i + 1] - ptr_psy_out->sfb_offsets[i],
1630 ptr_exp_spec + ptr_psy_out->sfb_offsets[i],
1631 ptr_mdct_spec_float + ptr_psy_out->sfb_offsets[i]);
1632
1633 scf_int = iusace_improve_scf(
1634 ptr_mdct_spec_float + ptr_psy_out->sfb_offsets[i],
1635 ptr_exp_spec + ptr_psy_out->sfb_offsets[i],
1636 ptr_quant_spec + ptr_psy_out->sfb_offsets[i],
1637 ptr_quant_spec_temp + ptr_psy_out->sfb_offsets[i],
1638 ptr_psy_out->sfb_offsets[i + 1] - ptr_psy_out->sfb_offsets[i], thresh, scf_int,
1639 min_sf_max_quant[i], &ptr_sfb_dist[i], &min_calc_scf[i]);
1640
1641 ptr_scalefactor[i] = scf_int;
1642 }
1643 }
1644
1645 for (i = 0; i < ptr_psy_out->sfb_count; i++) {
1646 sfb_const_pe_part[i] = MIN_FLT_VAL;
1647 }
1648
1649 iusace_assimilate_single_scf(ptr_psy_out, ptr_exp_spec, ptr_quant_spec, ptr_quant_spec_temp,
1650 ptr_scalefactor, min_sf_max_quant, ptr_sfb_dist,
1651 sfb_const_pe_part, p_sfb_form_factor, p_sfb_num_relevant_lines,
1652 min_calc_scf, ptr_mdct_spec_float);
1653
1654 iusace_assimilate_multiple_scf(ptr_psy_out, ptr_exp_spec, ptr_quant_spec, ptr_quant_spec_temp,
1655 ptr_scalefactor, min_sf_max_quant, ptr_sfb_dist,
1656 sfb_const_pe_part, p_sfb_form_factor, p_sfb_num_relevant_lines,
1657 ptr_mdct_spec_float, ptr_scratch);
1658
1659 max_scf = MIN_SHRT_VAL;
1660 min_scf = MAX_SHRT_VAL;
1661 for (i = 0; i < ptr_psy_out->sfb_count; i++) {
1662 if (max_scf < ptr_scalefactor[i]) {
1663 max_scf = ptr_scalefactor[i];
1664 }
1665 if ((ptr_scalefactor[i] != MIN_SHRT_VAL) && (min_scf > ptr_scalefactor[i])) {
1666 min_scf = ptr_scalefactor[i];
1667 }
1668 }
1669
1670 for (i = 0; i < pstr_psy_out[ch].sfb_count; i++) {
1671 if ((ptr_scalefactor[i] != MIN_SHRT_VAL) &&
1672 (min_scf + MAX_SCF_DELTA) < ptr_scalefactor[i]) {
1673 ptr_scalefactor[i] = min_scf + MAX_SCF_DELTA;
1674
1675 iusace_calc_sfb_dist(ptr_mdct_spec_float + ptr_psy_out->sfb_offsets[i],
1676 ptr_exp_spec + ptr_psy_out->sfb_offsets[i],
1677 ptr_quant_spec + ptr_psy_out->sfb_offsets[i],
1678 ptr_psy_out->sfb_offsets[i + 1] - ptr_psy_out->sfb_offsets[i],
1679 ptr_scalefactor[i]);
1680 }
1681 }
1682
1683 max_scf = MIN((min_scf + MAX_SCF_DELTA), max_scf);
1684
1685 if (max_scf > MIN_SHRT_VAL) {
1686 *global_gain = max_scf;
1687 for (i = 0; i < ptr_psy_out->sfb_count; i++) {
1688 if (ptr_scalefactor[i] == MIN_SHRT_VAL) {
1689 ptr_scalefactor[i] = 0;
1690 memset(
1691 &ptr_psy_out->ptr_spec_coeffs[ptr_psy_out->sfb_offsets[i]], 0,
1692 (ptr_psy_out->sfb_offsets[i + 1] - ptr_psy_out->sfb_offsets[i]) * sizeof(FLOAT64));
1693 } else {
1694 ptr_scalefactor[i] = max_scf - ptr_scalefactor[i];
1695 }
1696 }
1697 } else {
1698 *global_gain = 0;
1699 for (i = 0; i < ptr_psy_out->sfb_count; i++) {
1700 ptr_scalefactor[i] = 0;
1701 memset(&ptr_psy_out->ptr_spec_coeffs[ptr_psy_out->sfb_offsets[i]], 0,
1702 (ptr_psy_out->sfb_offsets[i + 1] - ptr_psy_out->sfb_offsets[i]) * sizeof(FLOAT64));
1703 }
1704 }
1705 idx++;
1706 }
1707
1708 return;
1709 }
1710