• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ixheaacd_type_def.h"
23 #include "ixheaacd_cnst.h"
24 #include "ixheaacd_peak_limiter_struct_def.h"
25 #include "ixheaacd_constants.h"
26 #include "ixheaacd_basic_ops32.h"
27 #include "ixheaacd_basic_ops16.h"
28 
29 #define MAX(x, y) ((x) > (y) ? (x) : (y))
30 #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 */
ixheaacd_peak_limiter_init(ia_peak_limiter_struct * peak_limiter,UWORD32 num_channels,UWORD32 sample_rate,FLOAT32 * buffer,UWORD32 * delay_in_samples)45 WORD32 ixheaacd_peak_limiter_init(ia_peak_limiter_struct *peak_limiter,
46                                   UWORD32 num_channels, UWORD32 sample_rate,
47                                   FLOAT32 *buffer, UWORD32 *delay_in_samples) {
48   UWORD32 attack;
49 
50   attack = (UWORD32)(DEFAULT_ATTACK_TIME_MS * sample_rate / 1000);
51   *delay_in_samples = attack;
52 
53   if (attack < 1) return 0;
54 
55   peak_limiter->max_buf = buffer;
56   peak_limiter->max_idx = 0;
57   peak_limiter->cir_buf_pnt = 0;
58   peak_limiter->delayed_input = buffer + attack * 4 + 32;
59 
60   peak_limiter->delayed_input_index = 0;
61   peak_limiter->attack_time = DEFAULT_ATTACK_TIME_MS;
62   peak_limiter->release_time = DEFAULT_RELEASE_TIME_MS;
63   peak_limiter->attack_time_samples = attack;
64   peak_limiter->attack_constant = (FLOAT32)pow(0.1, 1.0 / (attack + 1));
65   peak_limiter->release_constant = (FLOAT32)pow(
66       0.1, 1.0 / (DEFAULT_RELEASE_TIME_MS * sample_rate / 1000 + 1));
67   peak_limiter->num_channels = num_channels;
68   peak_limiter->sample_rate = sample_rate;
69   peak_limiter->min_gain = 1.0f;
70   peak_limiter->limiter_on = 1;
71   peak_limiter->pre_smoothed_gain = 1.0f;
72   peak_limiter->gain_modified = 1.0f;
73 
74   return 0;
75 }
ixheaacd_peak_limiter_process_float(ia_peak_limiter_struct * peak_limiter,FLOAT32 samples[MAX_NUM_CHANNELS][4096],UWORD32 frame_len)76 VOID ixheaacd_peak_limiter_process_float(ia_peak_limiter_struct *peak_limiter,
77                                          FLOAT32 samples[MAX_NUM_CHANNELS][4096],
78                                          UWORD32 frame_len) {
79   UWORD32 i, j;
80   FLOAT32 tmp, gain;
81   FLOAT32 min_gain = 1.0f;
82   FLOAT32 maximum;
83   UWORD32 num_channels = peak_limiter->num_channels;
84   UWORD32 attack_time_samples = peak_limiter->attack_time_samples;
85   FLOAT32 attack_constant = peak_limiter->attack_constant;
86   FLOAT32 release_constant = peak_limiter->release_constant;
87   FLOAT32 *max_buf = peak_limiter->max_buf;
88   FLOAT32 gain_modified = peak_limiter->gain_modified;
89   FLOAT32 *delayed_input = peak_limiter->delayed_input;
90   UWORD32 delayed_input_index = peak_limiter->delayed_input_index;
91   FLOAT64 pre_smoothed_gain = peak_limiter->pre_smoothed_gain;
92   FLOAT32 limit_threshold = PEAK_LIM_THR_FLOAT;
93 
94   if (peak_limiter->limiter_on || (FLOAT32)pre_smoothed_gain) {
95     for (i = 0; i < frame_len; i++) {
96       tmp = 0.0f;
97       for (j = 0; j < num_channels; j++) {
98         tmp = (FLOAT32)MAX(tmp, fabs(samples[j][i]));
99       }
100       max_buf[peak_limiter->cir_buf_pnt] = tmp;
101 
102       if (peak_limiter->max_idx == peak_limiter->cir_buf_pnt) {
103         peak_limiter->max_idx = 0;
104         for (j = 1; j < (attack_time_samples); j++) {
105           if (max_buf[j] > max_buf[peak_limiter->max_idx]) peak_limiter->max_idx = j;
106         }
107       } else if (tmp >= max_buf[peak_limiter->max_idx]) {
108         peak_limiter->max_idx = peak_limiter->cir_buf_pnt;
109       }
110 
111       peak_limiter->cir_buf_pnt++;
112 
113       if (peak_limiter->cir_buf_pnt == (WORD32)(attack_time_samples))
114         peak_limiter->cir_buf_pnt = 0;
115       maximum = max_buf[peak_limiter->max_idx];
116 
117       if (maximum > limit_threshold) {
118         gain = limit_threshold / maximum;
119       } else {
120         gain = 1;
121       }
122 
123       if (gain < pre_smoothed_gain) {
124         gain_modified =
125             MIN(gain_modified, (gain - 0.1f * (FLOAT32)pre_smoothed_gain) * 1.11111111f);
126       } else {
127         gain_modified = gain;
128       }
129 
130       if (gain_modified < pre_smoothed_gain) {
131         pre_smoothed_gain = attack_constant * (pre_smoothed_gain - gain_modified) + gain_modified;
132         pre_smoothed_gain = MAX(pre_smoothed_gain, gain);
133       } else {
134         pre_smoothed_gain =
135             release_constant * (pre_smoothed_gain - gain_modified) + gain_modified;
136       }
137 
138       gain = (FLOAT32)pre_smoothed_gain;
139 
140       for (j = 0; j < num_channels; j++) {
141         tmp = delayed_input[delayed_input_index * num_channels + j];
142         delayed_input[delayed_input_index * num_channels + j] = samples[j][i];
143 
144         tmp *= gain;
145 
146         if (tmp > limit_threshold)
147           tmp = limit_threshold;
148         else if (tmp < -limit_threshold)
149           tmp = -limit_threshold;
150 
151         samples[j][i] = tmp;
152       }
153 
154       delayed_input_index++;
155       if (delayed_input_index >= attack_time_samples) delayed_input_index = 0;
156 
157       if (gain < min_gain) min_gain = gain;
158     }
159   } else {
160     for (i = 0; i < frame_len; i++) {
161       for (j = 0; j < num_channels; j++) {
162         tmp = delayed_input[delayed_input_index * num_channels + j];
163         delayed_input[delayed_input_index * num_channels + j] = samples[j][i];
164         samples[j][i] = tmp;
165       }
166 
167       delayed_input_index++;
168       if (delayed_input_index >= attack_time_samples) delayed_input_index = 0;
169     }
170   }
171 
172   peak_limiter->gain_modified = gain_modified;
173   peak_limiter->delayed_input_index = delayed_input_index;
174   peak_limiter->pre_smoothed_gain = pre_smoothed_gain;
175   peak_limiter->min_gain = min_gain;
176 
177   return;
178 }
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 */
ixheaacd_peak_limiter_process(ia_peak_limiter_struct * peak_limiter,VOID * samples_t,UWORD32 frame_len,UWORD8 * qshift_adj)192 VOID ixheaacd_peak_limiter_process(ia_peak_limiter_struct *peak_limiter,
193                                    VOID *samples_t, UWORD32 frame_len,
194                                    UWORD8 *qshift_adj) {
195   UWORD32 i, j;
196   FLOAT32 tmp, gain;
197   FLOAT32 min_gain = 1.0f;
198   FLOAT32 maximum;
199   UWORD32 num_channels = peak_limiter->num_channels;
200   UWORD32 attack_time_samples = peak_limiter->attack_time_samples;
201   FLOAT32 attack_constant = peak_limiter->attack_constant;
202   FLOAT32 release_constant = peak_limiter->release_constant;
203   FLOAT32 *max_buf = peak_limiter->max_buf;
204   FLOAT32 gain_modified = peak_limiter->gain_modified;
205   FLOAT32 *delayed_input = peak_limiter->delayed_input;
206   UWORD32 delayed_input_index = peak_limiter->delayed_input_index;
207   FLOAT64 pre_smoothed_gain = peak_limiter->pre_smoothed_gain;
208   WORD32 limit_threshold = PEAK_LIM_THR_FIX;
209 
210   WORD32 *samples = (WORD32 *)samples_t;
211 
212   if (peak_limiter->limiter_on || (FLOAT32)pre_smoothed_gain) {
213     for (i = 0; i < frame_len; i++) {
214       tmp = 0.0f;
215       for (j = 0; j < num_channels; j++) {
216         FLOAT32 gain_t = (FLOAT32)(1 << *(qshift_adj + j));
217         tmp = (FLOAT32)MAX(tmp, fabs((samples[i * num_channels + j] * gain_t)));
218       }
219       max_buf[peak_limiter->cir_buf_pnt] = tmp;
220 
221       if (peak_limiter->max_idx == peak_limiter->cir_buf_pnt) {
222         peak_limiter->max_idx = 0;
223         for (j = 1; j < (attack_time_samples); j++) {
224           if (max_buf[j] > max_buf[peak_limiter->max_idx])
225             peak_limiter->max_idx = j;
226         }
227       } else if (tmp >= max_buf[peak_limiter->max_idx]) {
228         peak_limiter->max_idx = peak_limiter->cir_buf_pnt;
229       }
230       peak_limiter->cir_buf_pnt++;
231 
232       if (peak_limiter->cir_buf_pnt == (WORD32)(attack_time_samples))
233         peak_limiter->cir_buf_pnt = 0;
234       maximum = max_buf[peak_limiter->max_idx];
235 
236       if (maximum > limit_threshold) {
237         gain = limit_threshold / maximum;
238       } else {
239         gain = 1;
240       }
241 
242       if (gain < pre_smoothed_gain) {
243         gain_modified =
244             MIN(gain_modified,
245                 (gain - 0.1f * (FLOAT32)pre_smoothed_gain) * 1.11111111f);
246 
247       } else {
248         gain_modified = gain;
249       }
250 
251       if (gain_modified < pre_smoothed_gain) {
252         pre_smoothed_gain =
253             attack_constant * (pre_smoothed_gain - gain_modified) +
254             gain_modified;
255         pre_smoothed_gain = MAX(pre_smoothed_gain, gain);
256       } else {
257         pre_smoothed_gain =
258             release_constant * (pre_smoothed_gain - gain_modified) +
259             gain_modified;
260       }
261 
262       gain = (FLOAT32)pre_smoothed_gain;
263 
264       for (j = 0; j < num_channels; j++) {
265         WORD64 tmp_fix;
266         tmp = delayed_input[delayed_input_index * num_channels + j];
267         FLOAT32 gain_t = (FLOAT32)(1 << *(qshift_adj + j));
268         delayed_input[delayed_input_index * num_channels + j] =
269             samples[i * num_channels + j] * gain_t;
270 
271         tmp *= gain;
272 
273         tmp_fix = (WORD64)tmp;
274 
275         if (tmp_fix > limit_threshold)
276           tmp_fix = limit_threshold;
277         else if (tmp_fix < -limit_threshold)
278           tmp_fix = -limit_threshold;
279 
280         samples[i * num_channels + j] = (WORD32)tmp_fix;
281       }
282 
283       delayed_input_index++;
284       if (delayed_input_index >= attack_time_samples) delayed_input_index = 0;
285 
286       if (gain < min_gain) min_gain = gain;
287     }
288   } else {
289     for (i = 0; i < frame_len; i++) {
290       for (j = 0; j < num_channels; j++) {
291         tmp = delayed_input[delayed_input_index * num_channels + j];
292         FLOAT32 gain_t = (FLOAT32)(1 << *(qshift_adj + j));
293         delayed_input[delayed_input_index * num_channels + j] =
294             samples[i * num_channels + j] * gain_t;
295         samples[i * num_channels + j] = (WORD32)tmp;
296       }
297 
298       delayed_input_index++;
299       if (delayed_input_index >= attack_time_samples) delayed_input_index = 0;
300     }
301   }
302 
303   peak_limiter->gain_modified = gain_modified;
304   peak_limiter->delayed_input_index = delayed_input_index;
305   peak_limiter->pre_smoothed_gain = pre_smoothed_gain;
306   peak_limiter->min_gain = min_gain;
307 
308   return;
309 }
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 
ixheaacd_scale_adjust(WORD32 * samples,UWORD32 frame_len,WORD8 * qshift_adj,WORD num_channels)324 VOID ixheaacd_scale_adjust(WORD32 *samples, UWORD32 frame_len,
325                            WORD8 *qshift_adj, WORD num_channels) {
326   UWORD32 i;
327   WORD32 j;
328   for (i = 0; i < frame_len; i++) {
329     for (j = 0; j < num_channels; j++) {
330       WORD32 gain_t = (WORD32)(1 << *(qshift_adj + j));
331       samples[i * num_channels + j] = (samples[i * num_channels + j] * gain_t);
332     }
333   }
334 }