Coverage Report

Created: 2025-10-27 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}