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 <stdio.h>
23#include <string.h>
24
25#include "impd_type_def.h"
26#include "impd_drc_peak_limiter.h"
27
28#ifndef max
29#define max(a, b) (((a) > (b)) ? (a) : (b))
30#endif
31#ifndef min
32#define min(a, b) (((a) < (b)) ? (a) : (b))
33#endif
34
35WORD32 impd_peak_limiter_init(ia_drc_peak_limiter_struct *peak_limiter,
36                              FLOAT32 attack_time, FLOAT32 release_time,
37                              FLOAT32 limit_threshold, UWORD32 num_channels,
38                              UWORD32 sample_rate, FLOAT32 *buffer) {
39  UWORD32 attack;
40  attack = (UWORD32)(attack_time * sample_rate / 1000);
41
42  if (attack < 1) return 0;
43
44  peak_limiter->max_buf = buffer;
45  peak_limiter->delayed_input = buffer + attack * 4 + 32;
46
47  peak_limiter->delayed_input_index = 0;
48  peak_limiter->attack_time = attack_time;
49  peak_limiter->release_time = release_time;
50  peak_limiter->attack_time_samples = attack;
51  peak_limiter->attack_constant = (FLOAT32)pow(0.1, 1.0 / (attack + 1));
52  peak_limiter->release_constant =
53      (FLOAT32)pow(0.1, 1.0 / (release_time * sample_rate / 1000 + 1));
54  peak_limiter->limit_threshold = limit_threshold;
55  peak_limiter->num_channels = num_channels;
56  peak_limiter->sample_rate = sample_rate;
57  peak_limiter->min_gain = 1.0f;
58  peak_limiter->limiter_on = 1;
59  peak_limiter->pre_smoothed_gain = 1.0f;
60  peak_limiter->gain_modified = 1.0f;
61
62  return 0;
63}
64
65WORD32 impd_peak_limiter_reinit(ia_drc_peak_limiter_struct *peak_limiter) {
66  if (peak_limiter) {
67    peak_limiter->delayed_input_index = 0;
68    peak_limiter->pre_smoothed_gain = 1.0f;
69    peak_limiter->gain_modified = 1.0f;
70    peak_limiter->min_gain = 1.0f;
71    memset(peak_limiter->max_buf, 0,
72           (peak_limiter->attack_time_samples + 1) * sizeof(FLOAT32));
73    memset(peak_limiter->delayed_input, 0, peak_limiter->attack_time_samples *
74                                               peak_limiter->num_channels *
75                                               sizeof(FLOAT32));
76  }
77
78  return 0;
79}
80
81WORD32 impd_limiter_process(ia_drc_peak_limiter_struct *peak_limiter,
82                            FLOAT32 *samples, UWORD32 frame_len) {
83  UWORD32 i, j;
84  FLOAT32 tmp, gain;
85  FLOAT32 min_gain = 1;
86  FLOAT32 maximum, sectionMaximum;
87  UWORD32 num_channels = peak_limiter->num_channels;
88  UWORD32 attack_time_samples = peak_limiter->attack_time_samples;
89  FLOAT32 attack_constant = peak_limiter->attack_constant;
90  FLOAT32 release_constant = peak_limiter->release_constant;
91  FLOAT32 limit_threshold = peak_limiter->limit_threshold;
92  FLOAT32 *max_buf = peak_limiter->max_buf;
93  FLOAT32 gain_modified = peak_limiter->gain_modified;
94  FLOAT32 *delayed_input = peak_limiter->delayed_input;
95  UWORD32 delayed_input_index = peak_limiter->delayed_input_index;
96  FLOAT64 pre_smoothed_gain = peak_limiter->pre_smoothed_gain;
97
98  if (peak_limiter->limiter_on || (FLOAT32)pre_smoothed_gain < 1.0f) {
99    for (i = 0; i < frame_len; i++) {
100      tmp = 0.0f;
101      for (j = 0; j < num_channels; j++) {
102        tmp = max(tmp, (FLOAT32)fabs(samples[i * num_channels + j]));
103      }
104
105      for (j = attack_time_samples; j > 0; j--) {
106        max_buf[j] = max_buf[j - 1];
107      }
108      max_buf[0] = tmp;
109      sectionMaximum = tmp;
110      for (j = 1; j < (attack_time_samples + 1); j++) {
111        if (max_buf[j] > sectionMaximum) sectionMaximum = max_buf[j];
112      }
113      maximum = sectionMaximum;
114
115      if (maximum > limit_threshold) {
116        gain = limit_threshold / maximum;
117      } else {
118        gain = 1;
119      }
120
121      if (gain < pre_smoothed_gain) {
122        gain_modified =
123            min(gain_modified,
124                (gain - 0.1f * (FLOAT32)pre_smoothed_gain) * 1.11111111f);
125      } else {
126        gain_modified = gain;
127      }
128
129      if (gain_modified < pre_smoothed_gain) {
130        pre_smoothed_gain =
131            attack_constant * (pre_smoothed_gain - gain_modified) +
132            gain_modified;
133        pre_smoothed_gain = max(pre_smoothed_gain, gain);
134      } else {
135        pre_smoothed_gain =
136            release_constant * (pre_smoothed_gain - gain_modified) +
137            gain_modified;
138      }
139
140      gain = (FLOAT32)pre_smoothed_gain;
141
142      for (j = 0; j < num_channels; j++) {
143        tmp = delayed_input[delayed_input_index * num_channels + j];
144        delayed_input[delayed_input_index * num_channels + j] =
145            samples[i * num_channels + j];
146
147        tmp *= gain;
148        if (tmp > limit_threshold)
149          tmp = limit_threshold;
150        else if (tmp < -limit_threshold)
151          tmp = -limit_threshold;
152
153        samples[i * num_channels + j] = tmp;
154      }
155
156      delayed_input_index++;
157      if (delayed_input_index >= attack_time_samples) delayed_input_index = 0;
158
159      if (gain < min_gain) min_gain = gain;
160    }
161  } else {
162    for (i = 0; i < frame_len; i++) {
163      for (j = 0; j < num_channels; j++) {
164        tmp = delayed_input[delayed_input_index * num_channels + j];
165        delayed_input[delayed_input_index * num_channels + j] =
166            samples[i * num_channels + j];
167        samples[i * num_channels + j] = tmp;
168      }
169
170      delayed_input_index++;
171      if (delayed_input_index >= attack_time_samples) delayed_input_index = 0;
172    }
173  }
174
175  peak_limiter->gain_modified = gain_modified;
176  peak_limiter->delayed_input_index = delayed_input_index;
177  peak_limiter->pre_smoothed_gain = pre_smoothed_gain;
178  peak_limiter->min_gain = min_gain;
179
180  return 0;
181}
182