1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2015 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENSE.GPL
11 //=============================================================================
12
13 #include <math.h>
14
15 #include "compressor.h"
16
17 namespace Ms {
18
19 #define f_round(f) lrintf(f)
20
21 #define DB_TABLE_SIZE 1024
22 #define DB_MIN -60.0f
23 #define DB_MAX 24.0f
24 #define LIN_TABLE_SIZE 1024
25 #define LIN_MIN 0.0000000002f
26 #define LIN_MAX 9.0f
27
28 enum CompressorParameter {
29 RMS_PEAK, ATTACK, RELEASE, THRESHOLD, RATIO, KNEE, GAIN
30 };
31
32 //---------------------------------------------------------
33 // ParDescr
34 //---------------------------------------------------------
35
36 static const std::vector<ParDescr> pd = {
37 { RMS_PEAK, "rms", false, 0.0, 1.0, 0.0 },
38 { ATTACK, "attack", false, 1.5, 400.0, 1.5 },
39 { RELEASE, "release", false, 2.0, 800.0, 2.0 },
40 { THRESHOLD, "threshold", false, -30.0, 0.0, 0.0 },
41 { RATIO, "ratio", false, 1.0, 20.0, 1.0 },
42 { KNEE, "knee", false, 1.0, 10.0, 1.0 },
43 { GAIN, "gain", false, 0.0, 24.0, 0.0 }
44 };
45 #if 0
46 //---------------------------------------------------------
47 // cube_interp
48 // Cubic interpolation function
49 //---------------------------------------------------------
50
51 static inline float cube_interp(const float fr, const float inm1, const float
52 in, const float inp1, const float inp2)
53 {
54 return in + 0.5f * fr * (inp1 - inm1 +
55 fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 +
56 fr * (3.0f * (in - inp1) - inm1 + inp2)));
57 }
58 #endif
59 //---------------------------------------------------------
60 // f_max
61 //---------------------------------------------------------
62
f_max(float x,float a)63 static inline float f_max(float x, float a)
64 {
65 x -= a;
66 x += fabs(x);
67 x *= 0.5;
68 x += a;
69
70 return x;
71 }
72
73 //---------------------------------------------------------
74 // round_to_zero
75 //---------------------------------------------------------
76
round_to_zero(volatile float * f)77 static inline void round_to_zero(volatile float *f)
78 {
79 *f += 1e-18f;
80 *f -= 1e-18f;
81 }
82
83 // Linearly interpolate [ = a * (1 - f) + b * f]
84 #define LIN_INTERP(f,a,b) ((a) + (f) * ((b) - (a)))
85
86 #ifdef DB_DEFAULT_CUBE
87 #define db2lin(a) f_db2lin_cube(a)
88 #define lin2db(a) f_lin2db_cube(a)
89 #else
90 #define db2lin(a) f_db2lin_lerp(a)
91 #define lin2db(a) f_lin2db_lerp(a)
92 #endif
93
94 float db_data[DB_TABLE_SIZE];
95 float lin_data[LIN_TABLE_SIZE];
96 #if 0
97 //---------------------------------------------------------
98 // f_db2lin_cube
99 //---------------------------------------------------------
100
101 static inline float f_db2lin_cube(float db)
102 {
103 float scale = (db - DB_MIN) * (float)LIN_TABLE_SIZE / (DB_MAX - DB_MIN);
104 int base = f_round(scale - 0.5f);
105 float ofs = scale - base;
106
107 if (base < 1) {
108 return 0.0f;
109 } else if (base > LIN_TABLE_SIZE - 3) {
110 return lin_data[LIN_TABLE_SIZE - 2];
111 }
112 return cube_interp(ofs, lin_data[base-1], lin_data[base], lin_data[base+1], lin_data[base+2]);
113 }
114 #endif
115 //---------------------------------------------------------
116 // f_db2lin_lerp
117 //---------------------------------------------------------
118
f_db2lin_lerp(float db)119 static inline float f_db2lin_lerp(float db)
120 {
121 float scale = (db - DB_MIN) * (float)LIN_TABLE_SIZE / (DB_MAX - DB_MIN);
122 int base = f_round(scale - 0.5f);
123 float ofs = scale - base;
124
125 if (base < 1) {
126 return 0.0f;
127 }
128 else if (base > LIN_TABLE_SIZE - 3) {
129 return lin_data[LIN_TABLE_SIZE - 2];
130 }
131 return (1.0f - ofs) * lin_data[base] + ofs * lin_data[base+1];
132 }
133 #if 0
134 //---------------------------------------------------------
135 // f_lin2db_cube
136 //---------------------------------------------------------
137
138 static inline float f_lin2db_cube(float lin)
139 {
140 float scale = (lin - LIN_MIN) * (float)DB_TABLE_SIZE / (LIN_MAX - LIN_MIN);
141 int base = f_round(scale - 0.5f);
142 float ofs = scale - base;
143
144 if (base < 2) {
145 return db_data[2] * scale * 0.5f - 23 * (2.0f - scale);
146 } else if (base > DB_TABLE_SIZE - 3) {
147 return db_data[DB_TABLE_SIZE - 2];
148 }
149 return cube_interp(ofs, db_data[base-1], db_data[base], db_data[base+1], db_data[base+2]);
150 }
151 #endif
152 //---------------------------------------------------------
153 // f_lin2db_lerp
154 //---------------------------------------------------------
155
f_lin2db_lerp(float lin)156 static inline float f_lin2db_lerp(float lin)
157 {
158 float scale = (lin - LIN_MIN) * (float)DB_TABLE_SIZE / (LIN_MAX - LIN_MIN);
159 int base = f_round(scale - 0.5f);
160 float ofs = scale - base;
161
162 if (base < 2) {
163 return db_data[2] * scale * 0.5f - 23.0f * (2.0f - scale);
164 } else if (base > DB_TABLE_SIZE - 2) {
165 return db_data[DB_TABLE_SIZE - 1];
166 }
167 return (1.0f - ofs) * db_data[base] + ofs * db_data[base+1];
168 }
169
170 //---------------------------------------------------------
171 // db_init
172 //---------------------------------------------------------
173
db_init()174 void db_init()
175 {
176 for (int i=0; i<LIN_TABLE_SIZE; i++) {
177 lin_data[i] = powf(10.0f, ((DB_MAX - DB_MIN) *
178 (float)i/(float)LIN_TABLE_SIZE + DB_MIN) / 20.0f);
179 }
180
181 for (int i=0; i<DB_TABLE_SIZE; i++) {
182 db_data[i] = 20.0f * log10f((LIN_MAX - LIN_MIN) *
183 (float)i/(float)DB_TABLE_SIZE + LIN_MIN);
184 }
185 }
186
187 //---------------------------------------------------------
188 // init
189 //---------------------------------------------------------
190
init(float sr)191 void Compressor::init(float sr)
192 {
193 sampleRate = sr;
194 sum = 0.0f;
195 amp = 0.0f;
196 gain = 0.0f;
197 gain_t = 0.0f;
198 env = 0.0f;
199 env_rms = 0.0f;
200 env_peak = 0.0f;
201 count = 0;
202 as[0] = 1.0f;
203 for (int i = 0; i < A_TBL; ++i)
204 as[i] = expf(-1.0f / (sampleRate * (float)i / (float)A_TBL));
205 db_init();
206 }
207
208 //---------------------------------------------------------
209 // Compressor::process
210 //---------------------------------------------------------
211
process(int frames,float * ip,float * op)212 void Compressor::process(int frames, float* ip, float *op)
213 {
214 const float ga = _attack < 2.0f ? 0.0f : as[f_round(_attack * 0.001f * (float)(A_TBL-1))];
215 const float gr = as[f_round(_release * 0.001f * (float)(A_TBL-1))];
216 const float rs = (_ratio - 1.0f) / _ratio;
217 const float mug = db2lin(_makeupGain);
218 const float knee_min = db2lin(_threshold - _knee);
219 const float knee_max = db2lin(_threshold + _knee);
220 const float ef_a = ga * 0.25f;
221 const float ef_ai = 1.0f - ef_a;
222
223 for (int pos = 0; pos < frames; pos++) {
224 const float la = fabs(ip[pos * 2]);
225 const float ra = fabs(ip[pos * 2 + 1]);
226 const float lev_in = f_max(la, ra);
227
228 sum += lev_in * lev_in;
229 if (amp > env_rms)
230 env_rms = env_rms * ga + amp * (1.0f - ga);
231 else
232 env_rms = env_rms * gr + amp * (1.0f - gr);
233 round_to_zero(&env_rms);
234 if (lev_in > env_peak)
235 env_peak = env_peak * ga + lev_in * (1.0f - ga);
236 else
237 env_peak = env_peak * gr + lev_in * (1.0f - gr);
238 round_to_zero(&env_peak);
239 if ((count++ & 3) == 3) {
240 amp = rms.process(sum * 0.25f);
241 sum = 0.0f;
242 if (qIsNaN(env_rms)) // This can happen sometimes, but I don't know why
243 env_rms = 0.0f;
244 env = LIN_INTERP(rms_peak, env_rms, env_peak);
245 if (env <= knee_min)
246 gain_t = 1.0f;
247 else if (env < knee_max) {
248 const float x = -(_threshold - _knee - lin2db(env)) / _knee;
249 gain_t = db2lin(-_knee * rs * x * x * 0.25f);
250 }
251 else
252 gain_t = db2lin((_threshold - lin2db(env)) * rs);
253 }
254 gain = gain * ef_a + gain_t * ef_ai;
255 op[pos * 2] = ip[pos * 2] * gain * mug;
256 op[pos * 2+1] = ip[pos * 2 + 1] * gain * mug;
257 }
258
259 //printf("gain %f\n", gain);
260
261 // amplitude = lin2db(env);
262 // gain_red = lin2db(gain);
263 }
264
265 //---------------------------------------------------------
266 // setNValue
267 //---------------------------------------------------------
268
setNValue(int idx,double value)269 void Compressor::setNValue(int idx, double value)
270 {
271 switch (idx) {
272 case RMS_PEAK: setRmsPeak(value); break;
273 case ATTACK: setAttack(value); break;
274 case RELEASE: setRelease(value); break;
275 case THRESHOLD: setThreshold(value); break;
276 case RATIO: setRatio(value); break;
277 case KNEE: setKnee(value); break;
278 case GAIN: setMakeupGain(value); break;
279 }
280 }
281
282 //---------------------------------------------------------
283 // value
284 // return normalized value 0-1.0
285 //---------------------------------------------------------
286
nvalue(int idx) const287 double Compressor::nvalue(int idx) const
288 {
289 double v = 0.0;
290 switch (idx) {
291 case RMS_PEAK: v = rmsPeak(); break;
292 case ATTACK: v = attack(); break;
293 case RELEASE: v = release(); break;
294 case THRESHOLD: v = threshold(); break;
295 case RATIO: v = ratio(); break;
296 case KNEE: v = knee(); break;
297 case GAIN: v = makeupGain(); break;
298 }
299 return v;
300 }
301
302 //---------------------------------------------------------
303 // parDescr
304 //---------------------------------------------------------
305
parDescr() const306 const std::vector<ParDescr>& Compressor::parDescr() const
307 {
308 return pd;
309 }
310
311 //---------------------------------------------------------
312 // state
313 //---------------------------------------------------------
314
state() const315 SynthesizerGroup Compressor::state() const
316 {
317 SynthesizerGroup g;
318 g.setName(name());
319
320 for (const ParDescr& d : pd)
321 g.push_back(IdValue(d.id, QString("%1").arg(value(d.id))));
322 return g;
323 }
324
325 //---------------------------------------------------------
326 // setState
327 //---------------------------------------------------------
328
setState(const SynthesizerGroup & g)329 void Compressor::setState(const SynthesizerGroup& g)
330 {
331 for (const IdValue& v : g)
332 setValue(v.id, v.data.toDouble());
333 }
334 }
335
336