xref: /aosp_15_r20/external/libxaac/encoder/iusace_block_switch.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 "iusace_type_def.h"
22 #include "ixheaace_mps_common_define.h"
23 #include "iusace_cnst.h"
24 #include "iusace_block_switch_const.h"
25 #include "iusace_block_switch_struct_def.h"
26 #include "iusace_rom.h"
27 
iusace_fmult(FLOAT32 a,FLOAT32 b)28 static FLOAT32 iusace_fmult(FLOAT32 a, FLOAT32 b) { return (a * b); }
29 
iusace_fadd(FLOAT32 a,FLOAT32 b)30 static FLOAT32 iusace_fadd(FLOAT32 a, FLOAT32 b) { return (a + b); }
31 
iusace_init_block_switching(ia_block_switch_ctrl * pstr_blk_switch_ctrl,const WORD32 bit_rate,const WORD32 num_chans)32 VOID iusace_init_block_switching(ia_block_switch_ctrl *pstr_blk_switch_ctrl,
33                                  const WORD32 bit_rate, const WORD32 num_chans) {
34   WORD32 i, w;
35 
36   if ((num_chans == 1 && bit_rate > 24000) || (num_chans > 1 && bit_rate / num_chans > 16000)) {
37     pstr_blk_switch_ctrl->inv_attack_ratio = INV_ATTACK_RATIO_HIGH_BR;
38   } else {
39     pstr_blk_switch_ctrl->inv_attack_ratio = INV_ATTACK_RATIO_LOW_BR;
40   }
41 
42   for (i = 0; i < BLK_SWITCH_FILT_LEN; i++) {
43     pstr_blk_switch_ctrl->iir_states[i] = 0;
44   }
45 
46   /* Clear Filtered Window Energies */
47   for (w = 0; w < MAX_SHORT_WINDOWS; w++) {
48     pstr_blk_switch_ctrl->win_energy_filt[0][w] = 0;
49     pstr_blk_switch_ctrl->win_energy_filt[1][w] = 0;
50     pstr_blk_switch_ctrl->win_energy[0][w] = 0;
51     pstr_blk_switch_ctrl->win_energy[1][w] = 0;
52   }
53   pstr_blk_switch_ctrl->acc_win_energy = 0;
54 
55   pstr_blk_switch_ctrl->window_seq = ONLY_LONG_SEQUENCE;
56   pstr_blk_switch_ctrl->next_win_seq = ONLY_LONG_SEQUENCE;
57 
58   pstr_blk_switch_ctrl->attack = 0;
59   pstr_blk_switch_ctrl->lastattack = 0;
60   pstr_blk_switch_ctrl->attack_idx = 0;
61   pstr_blk_switch_ctrl->last_attack_idx = 0;
62 
63   return;
64 }
65 
iusace_srch_max_with_idx(const FLOAT32 * ptr_in,WORD32 * index)66 static FLOAT32 iusace_srch_max_with_idx(const FLOAT32 *ptr_in, WORD32 *index) {
67   FLOAT32 max;
68   WORD32 i, idx;
69 
70   max = 0;
71   idx = 0;
72 
73   for (i = 0; i < MAX_SHORT_WINDOWS; i++) {
74     if (ptr_in[i + 1] > max) {
75       max = ptr_in[i + 1];
76       idx = i;
77     }
78   }
79   *index = idx;
80 
81   return max;
82 }
83 
iusace_blk_switch_iir_filt(const FLOAT32 * ptr_in,const FLOAT32 * ptr_iir_coeff,const WORD32 w,FLOAT32 * ptr_iir_states,FLOAT32 * energy_accu,WORD32 block_len)84 static VOID iusace_blk_switch_iir_filt(const FLOAT32 *ptr_in, const FLOAT32 *ptr_iir_coeff,
85                                        const WORD32 w, FLOAT32 *ptr_iir_states,
86                                        FLOAT32 *energy_accu, WORD32 block_len) {
87   FLOAT32 accu1;
88 
89   WORD32 i;
90 
91   FLOAT32 accu_unfilt = 0.0f;
92   FLOAT32 accu_filt = 0.0f;
93   FLOAT32 accu2, temp2, temp1;
94 
95   FLOAT32 state0 = ptr_iir_states[0];
96   FLOAT32 state1 = ptr_iir_states[1];
97 
98   FLOAT32 coeff0 = ptr_iir_coeff[0];
99   FLOAT32 coeff1 = ptr_iir_coeff[1];
100 
101   const FLOAT32 *p_time_signal = &ptr_in[(block_len * w)];
102 
103   for (i = 0; i < block_len; i++) {
104     accu2 = iusace_fmult(state0, coeff1);
105     accu1 = iusace_fmult(state1, coeff0);
106     accu1 += accu2;
107 
108     state0 = p_time_signal[i];
109     state1 = iusace_fmult(state0, coeff1);
110     state1 = (state1 - accu1);
111 
112     temp1 = iusace_fmult(state0, state0);
113     temp2 = iusace_fmult(state1, state1);
114 
115     accu_unfilt = iusace_fadd(accu_unfilt, temp1);
116     accu_filt = iusace_fadd(accu_filt, temp2);
117   }
118 
119   energy_accu[0] = accu_unfilt;
120   energy_accu[1] = accu_filt;
121 
122   ptr_iir_states[0] = state0;
123   ptr_iir_states[1] = state1;
124 
125   return;
126 }
127 
iusace_calc_window_energy(ia_block_switch_ctrl * ptr_blk_switch_ctrl,const FLOAT32 * ptr_in,FLOAT32 * max,WORD32 ccfl)128 static VOID iusace_calc_window_energy(ia_block_switch_ctrl *ptr_blk_switch_ctrl,
129                                       const FLOAT32 *ptr_in, FLOAT32 *max, WORD32 ccfl) {
130   WORD32 w;
131 
132   FLOAT32 energy_accu[2];
133   *max = 0.0f;
134 
135   for (w = 0; w < MAX_SHORT_WINDOWS; w++) {
136     // block length for calculating energy is corecoder frame length / MAX_SHORT_WINDOWS
137     iusace_blk_switch_iir_filt(ptr_in, iusace_iir_hipass_coeffs, w,
138                                ptr_blk_switch_ctrl->iir_states, &energy_accu[0], ccfl >> 3);
139 
140     ptr_blk_switch_ctrl->win_energy[1][w] = energy_accu[0];
141     ptr_blk_switch_ctrl->win_energy_filt[1][w] = energy_accu[1];
142 
143     if (ptr_blk_switch_ctrl->win_energy_filt[1][w] > *max)
144       *max = ptr_blk_switch_ctrl->win_energy_filt[1][w];
145   }
146   return;
147 }
148 
iusace_block_switching(ia_block_switch_ctrl * ptr_blk_switch_ctrl,const FLOAT32 * ptr_in,WORD32 ccfl)149 VOID iusace_block_switching(ia_block_switch_ctrl *ptr_blk_switch_ctrl, const FLOAT32 *ptr_in,
150                             WORD32 ccfl) {
151   WORD32 i;
152 
153   FLOAT32 temp1, temp2;
154   FLOAT32 max;
155   FLOAT32 energy, energy_max;
156 
157   for (i = 0; i < MAX_SHORT_WINDOWS; i++) {
158     ptr_blk_switch_ctrl->group_len[i] = 0;
159   }
160 
161   ptr_blk_switch_ctrl->max_win_energy =
162       iusace_srch_max_with_idx(&ptr_blk_switch_ctrl->win_energy[0][MAX_SHORT_WINDOWS - 1],
163                                &ptr_blk_switch_ctrl->attack_idx);
164 
165   ptr_blk_switch_ctrl->attack_idx = ptr_blk_switch_ctrl->last_attack_idx;
166   ptr_blk_switch_ctrl->tot_grps_cnt = MAXIMUM_NO_OF_GROUPS;
167 
168   for (i = 0; i < MAXIMUM_NO_OF_GROUPS; i++) {
169     ptr_blk_switch_ctrl->group_len[i] =
170         iusace_suggested_grouping_table[ptr_blk_switch_ctrl->attack_idx][i];
171   }
172 
173   for (i = 0; i < MAX_SHORT_WINDOWS; i++) {
174     ptr_blk_switch_ctrl->win_energy[0][i] = ptr_blk_switch_ctrl->win_energy[1][i];
175     ptr_blk_switch_ctrl->win_energy_filt[0][i] = ptr_blk_switch_ctrl->win_energy_filt[1][i];
176   }
177 
178   iusace_calc_window_energy(ptr_blk_switch_ctrl, ptr_in, &max, ccfl);
179 
180   ptr_blk_switch_ctrl->attack = FALSE;
181 
182   energy_max = 0.0f;
183 
184   energy = ptr_blk_switch_ctrl->win_energy_filt[0][MAX_SHORT_WINDOWS - 1];
185 
186   for (i = 0; i < MAX_SHORT_WINDOWS; i++) {
187     temp1 = iusace_fmult(ONE_MINUS_ACC_WINDOW_NRG_FAC, ptr_blk_switch_ctrl->acc_win_energy);
188     temp2 = iusace_fmult(ACC_WINDOW_NRG_FAC, energy);
189     ptr_blk_switch_ctrl->acc_win_energy = iusace_fadd(temp1, temp2);
190 
191     temp1 = iusace_fmult(ptr_blk_switch_ctrl->win_energy_filt[1][i],
192                          ptr_blk_switch_ctrl->inv_attack_ratio);
193     if (temp1 > ptr_blk_switch_ctrl->acc_win_energy) {
194       ptr_blk_switch_ctrl->attack = TRUE;
195       ptr_blk_switch_ctrl->last_attack_idx = i;
196     }
197 
198     energy = ptr_blk_switch_ctrl->win_energy_filt[1][i];
199     if (energy_max < energy) energy_max = energy;
200   }
201 
202   if (ccfl == LEN_SUPERFRAME_768) {
203     energy_max = (energy_max * 4) / 3.0f;
204   }
205   if (energy_max < USAC_MIN_ATTACK_NRG) {
206     ptr_blk_switch_ctrl->attack = FALSE;
207   }
208 
209   if ((!ptr_blk_switch_ctrl->attack) && (ptr_blk_switch_ctrl->lastattack)) {
210     if (ptr_blk_switch_ctrl->attack_idx == MAX_SHORT_WINDOWS - 1) {
211       ptr_blk_switch_ctrl->attack = TRUE;
212     }
213     ptr_blk_switch_ctrl->lastattack = FALSE;
214   } else {
215     ptr_blk_switch_ctrl->lastattack = ptr_blk_switch_ctrl->attack;
216   }
217   ptr_blk_switch_ctrl->window_seq = ptr_blk_switch_ctrl->next_win_seq;
218 
219   if (ptr_blk_switch_ctrl->attack) {
220     ptr_blk_switch_ctrl->next_win_seq = EIGHT_SHORT_SEQUENCE;
221   } else {
222     ptr_blk_switch_ctrl->next_win_seq = ONLY_LONG_SEQUENCE;
223   }
224   if (ptr_blk_switch_ctrl->next_win_seq == EIGHT_SHORT_SEQUENCE) {
225     if (ptr_blk_switch_ctrl->window_seq == ONLY_LONG_SEQUENCE) {
226       ptr_blk_switch_ctrl->window_seq = LONG_START_SEQUENCE;
227     }
228 
229     if (ptr_blk_switch_ctrl->window_seq == LONG_STOP_SEQUENCE) {
230       ptr_blk_switch_ctrl->window_seq = EIGHT_SHORT_SEQUENCE;
231       ptr_blk_switch_ctrl->tot_grps_cnt = 3;
232       ptr_blk_switch_ctrl->group_len[0] = 3;
233       ptr_blk_switch_ctrl->group_len[1] = 3;
234       ptr_blk_switch_ctrl->group_len[2] = 2;
235     }
236   }
237 
238   if (ptr_blk_switch_ctrl->next_win_seq == ONLY_LONG_SEQUENCE) {
239     if (ptr_blk_switch_ctrl->window_seq == EIGHT_SHORT_SEQUENCE) {
240       ptr_blk_switch_ctrl->next_win_seq = LONG_STOP_SEQUENCE;
241     }
242   }
243   return;
244 }
245 
iusace_sync_block_switching(ia_block_switch_ctrl * ptr_blk_switch_left_ctrl,ia_block_switch_ctrl * ptr_blk_switch_right_ctrl)246 VOID iusace_sync_block_switching(ia_block_switch_ctrl *ptr_blk_switch_left_ctrl,
247                                  ia_block_switch_ctrl *ptr_blk_switch_right_ctrl) {
248   WORD32 i;
249   WORD32 patch_type = ONLY_LONG_SEQUENCE;
250 
251   patch_type = iusace_synchronized_block_types[patch_type][ptr_blk_switch_left_ctrl->window_seq];
252   patch_type = iusace_synchronized_block_types[patch_type][ptr_blk_switch_right_ctrl->window_seq];
253 
254   ptr_blk_switch_left_ctrl->window_seq = patch_type;
255   ptr_blk_switch_right_ctrl->window_seq = patch_type;
256 
257   if (patch_type != EIGHT_SHORT_SEQUENCE) { /* tns_data_long Blocks */
258     ptr_blk_switch_left_ctrl->tot_grps_cnt = 1;
259     ptr_blk_switch_right_ctrl->tot_grps_cnt = 1;
260     ptr_blk_switch_left_ctrl->group_len[0] = 1;
261     ptr_blk_switch_right_ctrl->group_len[0] = 1;
262 
263     for (i = 1; i < MAX_SHORT_WINDOWS; i++) {
264       ptr_blk_switch_left_ctrl->group_len[i] = 0;
265       ptr_blk_switch_right_ctrl->group_len[i] = 0;
266     }
267   } else { /* tns_data_short Blocks */
268     if (ptr_blk_switch_left_ctrl->max_win_energy > ptr_blk_switch_right_ctrl->max_win_energy) {
269       ptr_blk_switch_right_ctrl->tot_grps_cnt = ptr_blk_switch_left_ctrl->tot_grps_cnt;
270       for (i = 0; i < ptr_blk_switch_right_ctrl->tot_grps_cnt; i++) {
271         ptr_blk_switch_right_ctrl->group_len[i] = ptr_blk_switch_left_ctrl->group_len[i];
272       }
273     } else {
274       ptr_blk_switch_left_ctrl->tot_grps_cnt = ptr_blk_switch_right_ctrl->tot_grps_cnt;
275       for (i = 0; i < ptr_blk_switch_left_ctrl->tot_grps_cnt; i++) {
276         ptr_blk_switch_left_ctrl->group_len[i] = ptr_blk_switch_right_ctrl->group_len[i];
277       }
278     }
279   }
280 
281   return;
282 }
283