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