• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <math.h>
22 #include <string.h>
23 #include "ixheaac_type_def.h"
24 #include "ixheaac_constants.h"
25 #include "ixheaace_aac_constants.h"
26 #include "ixheaac_basic_ops32.h"
27 #include "ixheaac_basic_ops16.h"
28 #include "ixheaac_basic_ops40.h"
29 #include "ixheaac_basic_ops.h"
30 
31 #include "ixheaace_common_rom.h"
32 #include "ixheaace_sbr_header.h"
33 #include "ixheaace_sbr_def.h"
34 #include "ixheaace_resampler.h"
35 #include "ixheaace_sbr_rom.h"
36 #include "ixheaace_sbr_tran_det.h"
37 #include "ixheaace_sbr_main.h"
38 #include "ixheaace_sbr_frame_info_gen.h"
39 
ixheaace_calc_thresholds(FLOAT32 ** ptr_energies,WORD32 num_cols,WORD32 num_rows,FLOAT32 * ptr_thresholds,ixheaace_sbr_codec_type sbr_codec)40 static VOID ixheaace_calc_thresholds(FLOAT32 **ptr_energies, WORD32 num_cols, WORD32 num_rows,
41                                      FLOAT32 *ptr_thresholds, ixheaace_sbr_codec_type sbr_codec) {
42   FLOAT32 mean_val, std_val, thr;
43   FLOAT32 *ptr_energy;
44   FLOAT32 inv_num_cols = 1.0f / (FLOAT32)(num_cols + num_cols / 2);
45   FLOAT32 inv_num_cols_1 = 1.0f / (FLOAT32)(num_cols + num_cols / 2 - 1);
46 
47   WORD32 i = 0;
48   WORD32 j;
49 
50   while (i < num_rows) {
51     mean_val = std_val = 0;
52 
53     j = num_cols >> 2;
54     while (j < num_cols) {
55       ptr_energy = &ptr_energies[j][i];
56       mean_val += (*ptr_energy);
57       ptr_energy += 64;
58       mean_val += (*ptr_energy);
59       j += 2;
60     }
61 
62     mean_val *= inv_num_cols * 2.0f;
63 
64     j = num_cols >> 2;
65     while (j < num_cols) {
66       FLOAT32 tmp_var;
67       tmp_var = (sbr_codec == HEAAC_SBR) ? mean_val - ptr_energies[j][i] : ptr_energies[j][i];
68       std_val += tmp_var * tmp_var;
69       j++;
70     }
71 
72     std_val = (FLOAT32)((sbr_codec == HEAAC_SBR)
73                             ? sqrt(std_val * inv_num_cols_1)
74                             : sqrt(fabs((mean_val * mean_val) - std_val * inv_num_cols * 2.0f)));
75 
76     thr = 0.66f * ptr_thresholds[i] + 0.34f * IXHEAACE_SBR_TRAN_STD_FAC * std_val;
77     ptr_thresholds[i] = MAX(thr, IXHEAACE_SBR_TRAN_ABS_THR);
78 
79     i++;
80   }
81 }
82 
ixheaace_extract_transient_candidates(FLOAT32 ** ptr_energies,FLOAT32 * ptr_thresholds,FLOAT32 * ptr_transients,WORD32 num_cols,WORD32 start_band,WORD32 stop_band,WORD32 buf_len)83 static VOID ixheaace_extract_transient_candidates(FLOAT32 **ptr_energies, FLOAT32 *ptr_thresholds,
84                                                   FLOAT32 *ptr_transients, WORD32 num_cols,
85                                                   WORD32 start_band, WORD32 stop_band,
86                                                   WORD32 buf_len)
87 
88 {
89   WORD32 idx;
90   WORD32 buf_move = buf_len >> 1;
91   FLOAT32 dt_1, dt_2, dt_3, inv_thr;
92   WORD32 len = num_cols + (num_cols >> 1) - 3;
93   WORD32 band = start_band;
94 
95   memmove(ptr_transients, ptr_transients + num_cols, buf_move * sizeof(ptr_transients[0]));
96   memset(ptr_transients + buf_move, 0, (buf_len - buf_move) * sizeof(ptr_transients[0]));
97 
98   while (band < stop_band) {
99     inv_thr = (FLOAT32)1.0f / ptr_thresholds[band];
100     FLOAT32 temp_energy_1 = ptr_energies[((num_cols >> 1) - 2) / 2][band];
101     FLOAT32 temp_energy_2 = ptr_energies[((num_cols >> 1)) / 2][band];
102     FLOAT32 temp_energy_3 = ptr_energies[((num_cols >> 1) + 2) / 2][band];
103     for (idx = 0; idx < len; idx++) {
104       if (!idx) {
105         dt_1 = temp_energy_2 - temp_energy_1;
106         dt_2 = temp_energy_3 - temp_energy_1;
107         dt_3 = temp_energy_3 - ptr_energies[((num_cols >> 1) - 4) / 2][band];
108       } else {
109         FLOAT32 temp_energy_4 = ptr_energies[(idx + (num_cols >> 1) + 3) / 2][band];
110         dt_1 = temp_energy_3 - temp_energy_2;
111         dt_2 = temp_energy_3 - temp_energy_1 + dt_1;
112         dt_3 = temp_energy_4 - temp_energy_1 + dt_2;
113         temp_energy_1 = temp_energy_2;
114         temp_energy_2 = temp_energy_3;
115         temp_energy_3 = temp_energy_4;
116       }
117       if (dt_1 > ptr_thresholds[band]) {
118         ptr_transients[idx + buf_move] += dt_1 * inv_thr - 1.0f;
119       }
120       if (dt_2 > ptr_thresholds[band]) {
121         ptr_transients[idx + buf_move] += dt_2 * inv_thr - 1.0f;
122       }
123       if (dt_3 > ptr_thresholds[band]) {
124         ptr_transients[idx + buf_move] += dt_3 * inv_thr - 1.0f;
125       }
126     }
127     for (idx = 1; idx < len; idx += 2) {
128       ptr_transients[idx + buf_move + 1] = ptr_transients[idx + buf_move];
129     }
130     band++;
131   }
132 }
133 
ixheaace_detect_transient(FLOAT32 ** ptr_energies,ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_det,WORD32 * ptr_tran_vector,WORD32 time_step,ixheaace_sbr_codec_type sbr_codec)134 VOID ixheaace_detect_transient(FLOAT32 **ptr_energies,
135                                ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_det,
136                                WORD32 *ptr_tran_vector, WORD32 time_step,
137                                ixheaace_sbr_codec_type sbr_codec) {
138   WORD32 i;
139   WORD32 no_cols = pstr_sbr_trans_det->no_cols;
140   WORD32 qmf_start_sample = no_cols + time_step * 4;
141   FLOAT32 int_thr = (FLOAT32)pstr_sbr_trans_det->tran_thr / (FLOAT32)pstr_sbr_trans_det->no_rows;
142   FLOAT32 *ptr_trans = &(pstr_sbr_trans_det->ptr_transients[qmf_start_sample]);
143 
144   ptr_tran_vector[0] = 0;
145   ptr_tran_vector[1] = 0;
146 
147   ixheaace_calc_thresholds(ptr_energies, pstr_sbr_trans_det->no_cols, pstr_sbr_trans_det->no_rows,
148                            pstr_sbr_trans_det->ptr_thresholds, sbr_codec);
149 
150   ixheaace_extract_transient_candidates(
151       ptr_energies, pstr_sbr_trans_det->ptr_thresholds, pstr_sbr_trans_det->ptr_transients,
152       pstr_sbr_trans_det->no_cols, 0, pstr_sbr_trans_det->no_rows,
153       pstr_sbr_trans_det->buffer_length);
154 
155   for (i = 0; i < no_cols; i++) {
156     if ((ptr_trans[i] < 0.9f * ptr_trans[i - 1]) && (ptr_trans[i - 1] > int_thr)) {
157       ptr_tran_vector[0] = (WORD32)floor(i / time_step);
158       ptr_tran_vector[1] = 1;
159       break;
160     }
161   }
162 }
163 
ixheaace_calc_thresholds_4_1(FLOAT32 ** ptr_energies,WORD32 num_cols,WORD32 num_rows,FLOAT32 * ptr_thresholds,ixheaace_sbr_codec_type sbr_codec,WORD32 time_step)164 static VOID ixheaace_calc_thresholds_4_1(FLOAT32 **ptr_energies, WORD32 num_cols, WORD32 num_rows,
165                                          FLOAT32 *ptr_thresholds,
166                                          ixheaace_sbr_codec_type sbr_codec, WORD32 time_step) {
167   FLOAT32 mean_val, std_val, thr;
168   FLOAT32 *ptr_energy;
169   FLOAT32 inv_num_cols = 1.0f / (FLOAT32)((num_cols + num_cols / 2) / time_step);
170   FLOAT32 inv_num_cols_1 = 1.0f / (FLOAT32)((num_cols + num_cols / 2 - 1) / time_step);
171 
172   WORD32 i = 0;
173   WORD32 j;
174   WORD32 start_band = 8;
175   WORD32 end_band = 32;
176 
177   while (i < num_rows) {
178     mean_val = std_val = 0;
179 
180     j = start_band;
181     while (j < end_band) {
182       ptr_energy = &ptr_energies[j][i];
183       mean_val += (*ptr_energy);
184       j++;
185     }
186 
187     mean_val *= inv_num_cols;
188 
189     j = start_band;
190     while (j < end_band) {
191       FLOAT32 tmp_var;
192       tmp_var = mean_val - ptr_energies[j][i];
193       std_val += tmp_var * tmp_var;
194       j++;
195     }
196 
197     std_val = (FLOAT32)sqrt(std_val * inv_num_cols_1);
198 
199     thr = 0.66f * ptr_thresholds[i] + 0.34f * IXHEAACE_SBR_TRAN_STD_FAC * std_val;
200     ptr_thresholds[i] = MAX(thr, IXHEAACE_SBR_TRAN_ABS_THR);
201 
202     i++;
203   }
204 }
205 
ixheaace_extract_transient_candidates_4_1(FLOAT32 ** ptr_energies,FLOAT32 * ptr_thresholds,FLOAT32 * ptr_transients,WORD32 num_cols,WORD32 start_band,WORD32 stop_band,WORD32 buf_len,WORD32 time_step)206 static VOID ixheaace_extract_transient_candidates_4_1(FLOAT32 **ptr_energies,
207                                                       FLOAT32 *ptr_thresholds,
208                                                       FLOAT32 *ptr_transients, WORD32 num_cols,
209                                                       WORD32 start_band, WORD32 stop_band,
210                                                       WORD32 buf_len, WORD32 time_step)
211 
212 {
213   WORD32 idx;
214   WORD32 buf_move = num_cols / 2;
215   WORD32 band = start_band;
216 
217   memmove(ptr_transients, ptr_transients + num_cols, buf_move * sizeof(ptr_transients[0]));
218   memset(ptr_transients + buf_move, 0, num_cols * sizeof(ptr_transients[0]));
219 
220   while (band < stop_band) {
221     for (idx = buf_move; idx < num_cols + buf_move; idx++) {
222       float l = 0, r = 0;
223       for (int d = 1; d < 4; d++) {
224         l = ptr_energies[(idx - d) / time_step][band];
225         r = ptr_energies[(idx + d) / time_step][band];
226         if (r - l > ptr_thresholds[band])
227           ptr_transients[idx] += (r - l - ptr_thresholds[band]) / ptr_thresholds[band];
228       }
229     }
230     band++;
231   }
232 }
233 
ixheaace_detect_transient_4_1(FLOAT32 ** ptr_energies,ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_det,WORD32 * ptr_tran_vector,WORD32 time_step,ixheaace_sbr_codec_type sbr_codec)234 VOID ixheaace_detect_transient_4_1(FLOAT32 **ptr_energies,
235                                    ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_det,
236                                    WORD32 *ptr_tran_vector, WORD32 time_step,
237                                    ixheaace_sbr_codec_type sbr_codec) {
238   WORD32 i;
239   WORD32 no_cols = pstr_sbr_trans_det->no_cols;
240   WORD32 qmf_start_sample = time_step * 4;
241   FLOAT32 int_thr = (FLOAT32)pstr_sbr_trans_det->tran_thr / (FLOAT32)pstr_sbr_trans_det->no_rows;
242   FLOAT32 *ptr_trans = &(pstr_sbr_trans_det->ptr_transients[qmf_start_sample]);
243 
244   ptr_tran_vector[0] = 0;
245   ptr_tran_vector[1] = 0;
246 
247   ixheaace_calc_thresholds_4_1(ptr_energies, pstr_sbr_trans_det->no_cols,
248                                pstr_sbr_trans_det->no_rows, pstr_sbr_trans_det->ptr_thresholds,
249                                sbr_codec, time_step);
250 
251   ixheaace_extract_transient_candidates_4_1(
252       ptr_energies, pstr_sbr_trans_det->ptr_thresholds, pstr_sbr_trans_det->ptr_transients,
253       pstr_sbr_trans_det->no_cols, 0, pstr_sbr_trans_det->no_rows,
254       pstr_sbr_trans_det->buffer_length, time_step);
255 
256   for (i = 0; i < no_cols; i++) {
257     if ((ptr_trans[i] < 0.9f * ptr_trans[i - 1]) && (ptr_trans[i - 1] > int_thr)) {
258       ptr_tran_vector[0] = (WORD32)floor(i / time_step);
259       ptr_tran_vector[1] = 1;
260       break;
261     }
262   }
263 }
264 
ixheaace_detect_transient_eld(FLOAT32 ** ptr_energies,ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_det,WORD32 * ptr_tran_vector)265 VOID ixheaace_detect_transient_eld(FLOAT32 **ptr_energies,
266                                    ixheaace_pstr_sbr_trans_detector pstr_sbr_trans_det,
267                                    WORD32 *ptr_tran_vector) {
268   WORD32 i, band;
269   WORD32 max_idx = 0, is_transient = 0;
270   FLOAT32 delta_max = 0, tmp, min_energy;
271   WORD32 num_slots = pstr_sbr_trans_det->time_slots;
272   WORD32 look_ahead = pstr_sbr_trans_det->look_ahead;
273   WORD32 start_band = pstr_sbr_trans_det->start_band;
274   WORD32 stop_band = pstr_sbr_trans_det->stop_band;
275   FLOAT32 *ptr_energy = pstr_sbr_trans_det->energy;
276   FLOAT32 *ptr_delta_energy = pstr_sbr_trans_det->delta_energy;
277   FLOAT32 *ptr_transients = pstr_sbr_trans_det->ptr_transients;
278   WORD32 ts = look_ahead;
279   FLOAT32 weighted_energy;
280 
281   ptr_tran_vector[0] = ptr_tran_vector[1] = 0;
282   ptr_tran_vector[2] = 0;
283 
284   memset(ptr_transients + look_ahead, 0, num_slots * sizeof(ptr_transients[0]));
285 
286   while (ts < num_slots + look_ahead) {
287     tmp = 0.0f;
288     max_idx = 0;
289     delta_max = 0;
290     is_transient = 0;
291     i = 0;
292     band = start_band;
293 
294     while (band < stop_band) {
295       tmp += (ptr_energies[ts][band] * pstr_sbr_trans_det->coeff[i]);
296       band++;
297       i++;
298     }
299 
300     ptr_energy[ts] = tmp;
301     min_energy = (ptr_energy[ts - 1]) + IXHEAACE_SMALL_ENERGY;
302     ptr_delta_energy[ts] = ptr_energy[ts] / min_energy;
303 
304     weighted_energy = ptr_energy[ts] * (1.0f / 1.4f);
305 
306     if ((ptr_delta_energy[ts] >= IXHEAACE_TRANSIENT_THRESHOLD) &&
307         (((ptr_transients[ts - 2] == 0) && (ptr_transients[ts - 1] == 0)) ||
308          (weighted_energy >= ptr_energy[ts - 1]) || (weighted_energy >= ptr_energy[ts - 2]))) {
309       ptr_transients[ts] = 1;
310     }
311 
312     ts++;
313   }
314 
315   for (ts = 0; ts < num_slots; ts++) {
316     if (ptr_transients[ts] && (ptr_delta_energy[ts] > delta_max)) {
317       delta_max = ptr_delta_energy[ts];
318       max_idx = ts;
319       is_transient = 1;
320     }
321   }
322 
323   if (is_transient) {
324     ptr_tran_vector[0] = max_idx;
325     ptr_tran_vector[1] = 1;
326   }
327 
328   for (ts = 0; ts < look_ahead; ts++) {
329     if (ptr_transients[ts + num_slots]) {
330       ptr_tran_vector[2] = 1;
331     }
332     ptr_energy[ts] = ptr_energy[num_slots + ts];
333     ptr_transients[ts] = ptr_transients[num_slots + ts];
334     ptr_delta_energy[ts] = ptr_delta_energy[num_slots + ts];
335   }
336 }
337