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 
impd_peak_limiter_init(ia_drc_peak_limiter_struct * peak_limiter,FLOAT32 attack_time,FLOAT32 release_time,FLOAT32 limit_threshold,UWORD32 num_channels,UWORD32 sample_rate,FLOAT32 * buffer)35 WORD32 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 
impd_peak_limiter_reinit(ia_drc_peak_limiter_struct * peak_limiter)65 VOID 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;
79 }
80 
impd_limiter_process(ia_drc_peak_limiter_struct * peak_limiter,FLOAT32 * samples,UWORD32 frame_len)81 VOID 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;
181 }
182