/src/libxaac/decoder/ixheaacd_peak_limiter.c
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * * |
3 | | * Copyright (C) 2018 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 | | #include <stdlib.h> |
21 | | #include <math.h> |
22 | | #include "ixheaac_type_def.h" |
23 | | #include "ixheaacd_cnst.h" |
24 | | #include "ixheaacd_peak_limiter_struct_def.h" |
25 | | #include "ixheaac_constants.h" |
26 | | #include "ixheaac_basic_ops32.h" |
27 | | #include "ixheaac_basic_ops16.h" |
28 | | |
29 | 115M | #define MAX(x, y) ((x) > (y) ? (x) : (y)) |
30 | 8.25M | #define MIN(x, y) ((x) > (y) ? (y) : (x)) |
31 | | |
32 | | /** |
33 | | * ixheaacd_peak_limiter_init |
34 | | * |
35 | | * \brief Peak Limiter initialization |
36 | | * |
37 | | * \param [in/out] peak_limiter Pointer to peak_limiter struct |
38 | | * \param [in] num_channels Number of ouptut channels |
39 | | * \param [in] sample_rate Sampling rate value |
40 | | * \param [in] buffer Peak limiter buffer of size PEAK_LIM_BUFFER_SIZE |
41 | | * |
42 | | * \return WORD32 |
43 | | * |
44 | | */ |
45 | | WORD32 ixheaacd_peak_limiter_init(ia_peak_limiter_struct *peak_limiter, |
46 | | UWORD32 num_channels, UWORD32 sample_rate, |
47 | 9.17k | FLOAT32 *buffer, UWORD32 *delay_in_samples) { |
48 | 9.17k | UWORD32 attack; |
49 | | |
50 | 9.17k | attack = (UWORD32)(DEFAULT_ATTACK_TIME_MS * sample_rate / 1000); |
51 | 9.17k | *delay_in_samples = attack; |
52 | | |
53 | 9.17k | if (attack < 1) return 0; |
54 | | |
55 | 9.06k | peak_limiter->max_buf = buffer; |
56 | 9.06k | peak_limiter->max_idx = 0; |
57 | 9.06k | peak_limiter->cir_buf_pnt = 0; |
58 | 9.06k | peak_limiter->delayed_input = buffer + attack * 4 + 32; |
59 | | |
60 | 9.06k | peak_limiter->delayed_input_index = 0; |
61 | 9.06k | peak_limiter->attack_time = DEFAULT_ATTACK_TIME_MS; |
62 | 9.06k | peak_limiter->release_time = DEFAULT_RELEASE_TIME_MS; |
63 | 9.06k | peak_limiter->attack_time_samples = attack; |
64 | 9.06k | peak_limiter->attack_constant = (FLOAT32)pow(0.1, 1.0 / (attack + 1)); |
65 | 9.06k | peak_limiter->release_constant = (FLOAT32)pow( |
66 | 9.06k | 0.1, 1.0 / (DEFAULT_RELEASE_TIME_MS * sample_rate / 1000 + 1)); |
67 | 9.06k | peak_limiter->num_channels = num_channels; |
68 | 9.06k | peak_limiter->sample_rate = sample_rate; |
69 | 9.06k | peak_limiter->min_gain = 1.0f; |
70 | 9.06k | peak_limiter->limiter_on = 1; |
71 | 9.06k | peak_limiter->pre_smoothed_gain = 1.0f; |
72 | 9.06k | peak_limiter->gain_modified = 1.0f; |
73 | | |
74 | 9.06k | return 0; |
75 | 9.17k | } |
76 | | VOID ixheaacd_peak_limiter_process_float(ia_peak_limiter_struct *peak_limiter, |
77 | | FLOAT32 samples[MAX_NUM_CHANNELS][4096], |
78 | 0 | UWORD32 frame_len) { |
79 | 0 | UWORD32 i, j; |
80 | 0 | FLOAT32 tmp, gain; |
81 | 0 | FLOAT32 min_gain = 1.0f; |
82 | 0 | FLOAT32 maximum; |
83 | 0 | UWORD32 num_channels = peak_limiter->num_channels; |
84 | 0 | UWORD32 attack_time_samples = peak_limiter->attack_time_samples; |
85 | 0 | FLOAT32 attack_constant = peak_limiter->attack_constant; |
86 | 0 | FLOAT32 release_constant = peak_limiter->release_constant; |
87 | 0 | FLOAT32 *max_buf = peak_limiter->max_buf; |
88 | 0 | FLOAT32 gain_modified = peak_limiter->gain_modified; |
89 | 0 | FLOAT32 *delayed_input = peak_limiter->delayed_input; |
90 | 0 | UWORD32 delayed_input_index = peak_limiter->delayed_input_index; |
91 | 0 | FLOAT64 pre_smoothed_gain = peak_limiter->pre_smoothed_gain; |
92 | 0 | FLOAT32 limit_threshold = PEAK_LIM_THR_FLOAT; |
93 | |
|
94 | 0 | if (peak_limiter->limiter_on || (FLOAT32)pre_smoothed_gain) { |
95 | 0 | for (i = 0; i < frame_len; i++) { |
96 | 0 | tmp = 0.0f; |
97 | 0 | for (j = 0; j < num_channels; j++) { |
98 | 0 | tmp = (FLOAT32)MAX(tmp, fabs(samples[j][i])); |
99 | 0 | } |
100 | 0 | max_buf[peak_limiter->cir_buf_pnt] = tmp; |
101 | |
|
102 | 0 | if (peak_limiter->max_idx == peak_limiter->cir_buf_pnt) { |
103 | 0 | peak_limiter->max_idx = 0; |
104 | 0 | for (j = 1; j < (attack_time_samples); j++) { |
105 | 0 | if (max_buf[j] > max_buf[peak_limiter->max_idx]) peak_limiter->max_idx = j; |
106 | 0 | } |
107 | 0 | } else if (tmp >= max_buf[peak_limiter->max_idx]) { |
108 | 0 | peak_limiter->max_idx = peak_limiter->cir_buf_pnt; |
109 | 0 | } |
110 | |
|
111 | 0 | peak_limiter->cir_buf_pnt++; |
112 | |
|
113 | 0 | if (peak_limiter->cir_buf_pnt == (WORD32)(attack_time_samples)) |
114 | 0 | peak_limiter->cir_buf_pnt = 0; |
115 | 0 | maximum = max_buf[peak_limiter->max_idx]; |
116 | |
|
117 | 0 | if (maximum > limit_threshold) { |
118 | 0 | gain = limit_threshold / maximum; |
119 | 0 | } else { |
120 | 0 | gain = 1; |
121 | 0 | } |
122 | |
|
123 | 0 | if (gain < pre_smoothed_gain) { |
124 | 0 | gain_modified = |
125 | 0 | MIN(gain_modified, (gain - 0.1f * (FLOAT32)pre_smoothed_gain) * 1.11111111f); |
126 | 0 | } else { |
127 | 0 | gain_modified = gain; |
128 | 0 | } |
129 | |
|
130 | 0 | if (gain_modified < pre_smoothed_gain) { |
131 | 0 | pre_smoothed_gain = attack_constant * (pre_smoothed_gain - gain_modified) + gain_modified; |
132 | 0 | pre_smoothed_gain = MAX(pre_smoothed_gain, gain); |
133 | 0 | } else { |
134 | 0 | pre_smoothed_gain = |
135 | 0 | release_constant * (pre_smoothed_gain - gain_modified) + gain_modified; |
136 | 0 | } |
137 | |
|
138 | 0 | gain = (FLOAT32)pre_smoothed_gain; |
139 | |
|
140 | 0 | for (j = 0; j < num_channels; j++) { |
141 | 0 | tmp = delayed_input[delayed_input_index * num_channels + j]; |
142 | 0 | delayed_input[delayed_input_index * num_channels + j] = samples[j][i]; |
143 | |
|
144 | 0 | tmp *= gain; |
145 | |
|
146 | 0 | if (tmp > limit_threshold) |
147 | 0 | tmp = limit_threshold; |
148 | 0 | else if (tmp < -limit_threshold) |
149 | 0 | tmp = -limit_threshold; |
150 | |
|
151 | 0 | samples[j][i] = tmp; |
152 | 0 | } |
153 | |
|
154 | 0 | delayed_input_index++; |
155 | 0 | if (delayed_input_index >= attack_time_samples) delayed_input_index = 0; |
156 | |
|
157 | 0 | if (gain < min_gain) min_gain = gain; |
158 | 0 | } |
159 | 0 | } else { |
160 | 0 | for (i = 0; i < frame_len; i++) { |
161 | 0 | for (j = 0; j < num_channels; j++) { |
162 | 0 | tmp = delayed_input[delayed_input_index * num_channels + j]; |
163 | 0 | delayed_input[delayed_input_index * num_channels + j] = samples[j][i]; |
164 | 0 | samples[j][i] = tmp; |
165 | 0 | } |
166 | |
|
167 | 0 | delayed_input_index++; |
168 | 0 | if (delayed_input_index >= attack_time_samples) delayed_input_index = 0; |
169 | 0 | } |
170 | 0 | } |
171 | |
|
172 | 0 | peak_limiter->gain_modified = gain_modified; |
173 | 0 | peak_limiter->delayed_input_index = delayed_input_index; |
174 | 0 | peak_limiter->pre_smoothed_gain = pre_smoothed_gain; |
175 | 0 | peak_limiter->min_gain = min_gain; |
176 | |
|
177 | 0 | return; |
178 | 0 | } |
179 | | |
180 | | /** |
181 | | * ixheaacd_peak_limiter_process |
182 | | * |
183 | | * \brief Peak Limiter process |
184 | | * |
185 | | * \param [in/out] peak_limiter |
186 | | * \param [in] samples |
187 | | * \param [in] frame_len |
188 | | * |
189 | | * \return WORD32 |
190 | | * |
191 | | */ |
192 | | VOID ixheaacd_peak_limiter_process(ia_peak_limiter_struct *peak_limiter, |
193 | | VOID *samples_t, UWORD32 frame_len, |
194 | 106k | UWORD8 *qshift_adj) { |
195 | 106k | UWORD32 i, j; |
196 | 106k | FLOAT32 tmp, gain; |
197 | 106k | FLOAT32 min_gain = 1.0f; |
198 | 106k | FLOAT32 maximum; |
199 | 106k | UWORD32 num_channels = peak_limiter->num_channels; |
200 | 106k | UWORD32 attack_time_samples = peak_limiter->attack_time_samples; |
201 | 106k | FLOAT32 attack_constant = peak_limiter->attack_constant; |
202 | 106k | FLOAT32 release_constant = peak_limiter->release_constant; |
203 | 106k | FLOAT32 *max_buf = peak_limiter->max_buf; |
204 | 106k | FLOAT32 gain_modified = peak_limiter->gain_modified; |
205 | 106k | FLOAT32 *delayed_input = peak_limiter->delayed_input; |
206 | 106k | UWORD32 delayed_input_index = peak_limiter->delayed_input_index; |
207 | 106k | FLOAT64 pre_smoothed_gain = peak_limiter->pre_smoothed_gain; |
208 | 106k | WORD32 limit_threshold = PEAK_LIM_THR_FIX; |
209 | | |
210 | 106k | WORD32 *samples = (WORD32 *)samples_t; |
211 | | |
212 | 106k | if (peak_limiter->limiter_on || (FLOAT32)pre_smoothed_gain) { |
213 | 91.2M | for (i = 0; i < frame_len; i++) { |
214 | 91.1M | tmp = 0.0f; |
215 | 198M | for (j = 0; j < num_channels; j++) { |
216 | 106M | FLOAT32 gain_t = (FLOAT32)(1 << *(qshift_adj + j)); |
217 | 106M | tmp = (FLOAT32)MAX(tmp, fabs((samples[i * num_channels + j] * gain_t))); |
218 | 106M | } |
219 | 91.1M | max_buf[peak_limiter->cir_buf_pnt] = tmp; |
220 | | |
221 | 91.1M | if (peak_limiter->max_idx == peak_limiter->cir_buf_pnt) { |
222 | 5.33M | peak_limiter->max_idx = 0; |
223 | 552M | for (j = 1; j < (attack_time_samples); j++) { |
224 | 546M | if (max_buf[j] > max_buf[peak_limiter->max_idx]) |
225 | 14.2M | peak_limiter->max_idx = j; |
226 | 546M | } |
227 | 85.8M | } else if (tmp >= max_buf[peak_limiter->max_idx]) { |
228 | 42.7M | peak_limiter->max_idx = peak_limiter->cir_buf_pnt; |
229 | 42.7M | } |
230 | 91.1M | peak_limiter->cir_buf_pnt++; |
231 | | |
232 | 91.1M | if (peak_limiter->cir_buf_pnt == (WORD32)(attack_time_samples)) |
233 | 727k | peak_limiter->cir_buf_pnt = 0; |
234 | 91.1M | maximum = max_buf[peak_limiter->max_idx]; |
235 | | |
236 | 91.1M | if (maximum > limit_threshold) { |
237 | 43.5M | gain = limit_threshold / maximum; |
238 | 47.5M | } else { |
239 | 47.5M | gain = 1; |
240 | 47.5M | } |
241 | | |
242 | 91.1M | if (gain < pre_smoothed_gain) { |
243 | 8.25M | gain_modified = |
244 | 8.25M | MIN(gain_modified, |
245 | 8.25M | (gain - 0.1f * (FLOAT32)pre_smoothed_gain) * 1.11111111f); |
246 | | |
247 | 82.8M | } else { |
248 | 82.8M | gain_modified = gain; |
249 | 82.8M | } |
250 | | |
251 | 91.1M | if (gain_modified < pre_smoothed_gain) { |
252 | 8.25M | pre_smoothed_gain = |
253 | 8.25M | attack_constant * (pre_smoothed_gain - gain_modified) + |
254 | 8.25M | gain_modified; |
255 | 8.25M | pre_smoothed_gain = MAX(pre_smoothed_gain, gain); |
256 | 82.8M | } else { |
257 | 82.8M | pre_smoothed_gain = |
258 | 82.8M | release_constant * (pre_smoothed_gain - gain_modified) + |
259 | 82.8M | gain_modified; |
260 | 82.8M | } |
261 | | |
262 | 91.1M | gain = (FLOAT32)pre_smoothed_gain; |
263 | | |
264 | 198M | for (j = 0; j < num_channels; j++) { |
265 | 106M | WORD64 tmp_fix; |
266 | 106M | tmp = delayed_input[delayed_input_index * num_channels + j]; |
267 | 106M | FLOAT32 gain_t = (FLOAT32)(1 << *(qshift_adj + j)); |
268 | 106M | delayed_input[delayed_input_index * num_channels + j] = |
269 | 106M | samples[i * num_channels + j] * gain_t; |
270 | | |
271 | 106M | tmp *= gain; |
272 | | |
273 | 106M | tmp_fix = (WORD64)tmp; |
274 | | |
275 | 106M | if (tmp_fix > limit_threshold) |
276 | 9.91M | tmp_fix = limit_threshold; |
277 | 97.0M | else if (tmp_fix < -limit_threshold) |
278 | 10.1M | tmp_fix = -limit_threshold; |
279 | | |
280 | 106M | samples[i * num_channels + j] = (WORD32)tmp_fix; |
281 | 106M | } |
282 | | |
283 | 91.1M | delayed_input_index++; |
284 | 91.1M | if (delayed_input_index >= attack_time_samples) delayed_input_index = 0; |
285 | | |
286 | 91.1M | if (gain < min_gain) min_gain = gain; |
287 | 91.1M | } |
288 | 106k | } else { |
289 | 0 | for (i = 0; i < frame_len; i++) { |
290 | 0 | for (j = 0; j < num_channels; j++) { |
291 | 0 | tmp = delayed_input[delayed_input_index * num_channels + j]; |
292 | 0 | FLOAT32 gain_t = (FLOAT32)(1 << *(qshift_adj + j)); |
293 | 0 | delayed_input[delayed_input_index * num_channels + j] = |
294 | 0 | samples[i * num_channels + j] * gain_t; |
295 | 0 | samples[i * num_channels + j] = (WORD32)tmp; |
296 | 0 | } |
297 | |
|
298 | 0 | delayed_input_index++; |
299 | 0 | if (delayed_input_index >= attack_time_samples) delayed_input_index = 0; |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | 106k | peak_limiter->gain_modified = gain_modified; |
304 | 106k | peak_limiter->delayed_input_index = delayed_input_index; |
305 | 106k | peak_limiter->pre_smoothed_gain = pre_smoothed_gain; |
306 | 106k | peak_limiter->min_gain = min_gain; |
307 | | |
308 | 106k | return; |
309 | 106k | } |
310 | | |
311 | | /** |
312 | | * ixheaacd_scale_adjust |
313 | | * |
314 | | * \brief Scale adjust process |
315 | | * |
316 | | * \param [in/out] samples |
317 | | * \param [in] qshift_adj |
318 | | * \param [in] frame_len |
319 | | * |
320 | | * \return WORD32 |
321 | | * |
322 | | */ |
323 | | |
324 | | VOID ixheaacd_scale_adjust(WORD32 *samples, UWORD32 frame_len, |
325 | 0 | WORD8 *qshift_adj, WORD num_channels) { |
326 | 0 | UWORD32 i; |
327 | 0 | WORD32 j; |
328 | 0 | for (i = 0; i < frame_len; i++) { |
329 | 0 | for (j = 0; j < num_channels; j++) { |
330 | 0 | WORD32 gain_t = (WORD32)(1 << *(qshift_adj + j)); |
331 | 0 | samples[i * num_channels + j] = (samples[i * num_channels + j] * gain_t); |
332 | 0 | } |
333 | 0 | } |
334 | 0 | } |