1 // ------------------------------------------------------------------------
2 // audiofx_compressor.cpp: C++ implementation of John S. Dyson's
3 // compressor code. If you want the original
4 // C-sources, mail me.
5 // Copyright (C) 1999-2000 Kai Vehmanen
6 //
7 // Copyright for the actual algorithm (compressor2.c):
8 // ***************************************************
9 /*
10 * Copyright (c) 1996, John S. Dyson
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * This code (easily) runs realtime on a P5-166 w/EDO, Triton-II on FreeBSD.
23 *
24 * More info/comments: dyson@freebsd.org
25 *
26 * This program provides compression of a stereo 16bit audio stream,
27 * such as that contained by a 16Bit wav file. Extreme measures have
28 * been taken to make the compression as subtile as possible. One
29 * possible purpose for this code would be to master cassette tapes from
30 * CD's for playback in automobiles where dynamic range needs to be
31 * restricted.
32 *
33 * Suitably recoded for an embedded DSP, this would make a killer audio
34 * compressor for broadcast or recording. When writing this code, I
35 * ignored the issues of roundoff error or trucation -- Pentiums have
36 * really nice FP processors :-).
37 */
38 // ------------------------------------------------------------------------
39
40 #include <cmath>
41 #include <vector>
42
43 #include <kvu_dbc.h>
44 #include <kvu_message_item.h>
45
46 #include "samplebuffer_iterators.h"
47
48 #include "audiofx_amplitude.h"
49
50 #include "eca-logger.h"
51
ADVANCED_COMPRESSOR(double peak_limit,double release_time,double cfrate,double crate)52 ADVANCED_COMPRESSOR::ADVANCED_COMPRESSOR (double peak_limit, double release_time, double cfrate,
53 double crate)
54 : rlevelsqn(ADVANCED_COMPRESSOR::NFILT),
55 rlevelsqe(ADVANCED_COMPRESSOR::NEFILT)
56 {
57 init_values();
58
59 set_parameter(1, peak_limit);
60 set_parameter(2, release_time);
61 set_parameter(3, cfrate);
62 set_parameter(4, crate);
63
64 MESSAGE_ITEM otemp;
65 otemp.setprecision(2);
66 otemp << "(audiofx_compressor) Advanced compressor enabled;";
67 otemp << " peak limit " << peakpercent;
68 otemp << " release time " << release_time;
69 otemp << " cfrate " << fastgaincompressionratio;
70 otemp << " crate " << compressionratio << ".";
71 ECA_LOG_MSG(ECA_LOGGER::info, otemp.to_string());
72 }
73
init_values(void)74 void ADVANCED_COMPRESSOR::init_values(void) {
75 mingain = 10000;
76 maxgain = 0;
77
78 /* These filters should filter at least the lowest audio freq */
79 rlevelsq0filter = .001;
80 rlevelsq1filter = .010;
81 /* These are the attack time for the rms measurement */
82 rlevelsq0ffilter = .001;
83 rlevelsqefilter = .001;
84
85 /*
86 * maximum gain for fast compressor
87 */
88 maxfastgain = 3;
89 /*
90 * maximum gain for slow compressor
91 */
92 maxslowgain = 9;
93
94 /*
95 * Level below which gain tracking shuts off
96 */
97 floorlevel = SAMPLE_SPECS::max_amplitude * 0.06; // was 2000
98 // floorlevel = 2000;
99
100 /*
101 * Slow compressor time constants
102 */
103 rmastergain0filter = .000003;
104
105 rpeakgainfilter = .001;
106 rpeaklimitdelay = 2500;
107
108 rgain = rmastergain0 = 1.0;
109 rlevelsq0 = levelsq1 = 0;
110 rlevelsq1 = 0;
111 compress = 1;
112 ndelay = (int)(1.0 / rlevelsq0ffilter);
113 // ECA_LOG_MSG(ECA_LOGGER::user_objects, "(audiofx_compressor) Number of delays : " +
114 // kvu_numtostr(ndelay) + ".");
115
116 rightdelay.resize(ndelay);
117 leftdelay.resize(ndelay);
118
119 // rlevelsqn = new vector<double> (NFILT + 1);
120 // rlevelsqe = new vector<double> (NEFILT + 1);
121
122 rpeakgain0 = 1.0;
123 rpeakgain1 = 1.0;
124 rpeaklimitdelay = 0;
125 ndelayptr = 0;
126 lastrgain = 1.0;
127
128 for(i = 0; i < NFILT;i++)
129 rlevelsqn[i] = 0.0;
130 for(i = 0; i < NEFILT;i++)
131 rlevelsqe[i] = 0.0;
132
133 /* set defaults to some sane values */
134 peakpercent = 100.0f;
135 releasetime = 0;
136 fratio = 1.0;
137 ratio = 1.0;
138 }
139
~ADVANCED_COMPRESSOR(void)140 ADVANCED_COMPRESSOR::~ADVANCED_COMPRESSOR (void)
141 {
142 }
143
set_parameter(int param,CHAIN_OPERATOR::parameter_t value)144 void ADVANCED_COMPRESSOR::set_parameter(int param, CHAIN_OPERATOR::parameter_t value) {
145
146 // cerr << "Param: " << param << ", value: " << value << ".\n";
147
148 switch (param) {
149 case 1:
150 {
151 // ---
152 // target level for compression
153 // ---
154
155 maxlevel = SAMPLE_SPECS::max_amplitude * 0.9; // limiter level (was 32000)
156 // maxlevel = 32000;
157 peakpercent = value;
158 if (peakpercent == 0) peakpercent = 69;
159 targetlevel = maxlevel * peakpercent / 100.0;
160 break;
161 }
162
163 case 2:
164 {
165 // --
166 // Linear gain filters as opposed to the level measurement filters
167 // --
168 DBC_CHECK(samples_per_second() != 0);
169 releasetime = value;
170 if (releasetime == 0) releasetime = 0.01;
171 rgainfilter = 1.0 / (releasetime * samples_per_second());
172 break;
173 }
174
175 case 3:
176 {
177 // --
178 // compression ratio for fast gain. This will determine how
179 // much the audio is made more dense. .5 is equiv to 2:1
180 // compression. 1.0 is equiv to inf:1 compression.
181 // --
182 fratio = value;
183 if (fratio == 0) fratio = 0.5;
184 fastgaincompressionratio = fratio;
185 break;
186 }
187
188 case 4:
189 {
190 // --
191 // overall ompression ratio.
192 // --
193 ratio = value;
194 if (ratio == 0) ratio = 1.0;
195 compressionratio = ratio;
196 break;
197 }
198 }
199 }
200
get_parameter(int param) const201 CHAIN_OPERATOR::parameter_t ADVANCED_COMPRESSOR::get_parameter(int param) const {
202 switch (param)
203 {
204 case 1:
205 return(peakpercent);
206
207 case 2:
208 return(releasetime);
209
210 case 3:
211 return(fratio);
212
213 case 4:
214 return(ratio);
215 }
216
217 return(0.0);
218 }
219
hardlimit(double value,double knee,double limit)220 double ADVANCED_COMPRESSOR::hardlimit(double value, double knee, double limit)
221 {
222 // double lrange = (limit - knee);
223 double ab = fabs(value);
224 /*
225 if (ab > knee) {
226 double abslimit = (limit * 1.1);
227 if (ab < abslimit)
228 value = knee + lrange * sin( ((value - knee)/abslimit) * (3.14 / (4*1.1)));
229 }
230 */
231 if (ab >= limit)
232 value = value > 0 ? limit : -limit;
233 return value;
234 }
235
init(SAMPLE_BUFFER * insample)236 void ADVANCED_COMPRESSOR::init(SAMPLE_BUFFER* insample) {
237 iter.init(insample);
238
239 set_channels(insample->number_of_channels());
240 set_samples_per_second(samples_per_second());
241 }
242
process(void)243 void ADVANCED_COMPRESSOR::process(void) {
244 iter.begin();
245 while(!iter.end()) {
246 // right = insample->get_right() * 32767.0;
247 // left = insample->get_left() * 32767.0;
248
249 left = (*iter.current(0));
250 right = (*iter.current(1));
251
252 rightdelay[ndelayptr] = right;
253 leftdelay[ndelayptr] = left;
254 ndelayptr++;
255
256 // cerr << "1.l:" << left << "\n";
257 // cerr << "1.r:" << right << "\n";
258 // cerr << "2.l:" << leftdelay[ndelayptr - 1] << "should be 1=2\n";
259
260 if (ndelayptr >= ndelay)
261 ndelayptr = 0;
262 /* enable/disable compression */
263
264 skipmode = 0;
265 if (compress == 0) {
266 skipmode = 1;
267 goto skipagc;
268 }
269 levelsq0 = (right) * (right) + (left) * (left);
270
271 // if (ndelayptr == 0) {
272 // cerr << "3.1.l: " << "rlevelsq0 " << rlevelsq0 << "\n";
273 // cerr << "3.2.l: " << "rlevelsq0ffilter " << rlevelsq0ffilter << "\n";
274 // cerr << "3.2.l: " << "rlevelsq0filter " << rlevelsq0filter << "\n";
275 // }
276
277 if (levelsq0 > rlevelsq0) {
278 rlevelsq0 = (levelsq0 * rlevelsq0ffilter) +
279 rlevelsq0 * (1 - rlevelsq0ffilter);
280 } else {
281 rlevelsq0 = (levelsq0 * rlevelsq0filter) +
282 rlevelsq0 * (1 - rlevelsq0filter);
283 }
284
285 if (rlevelsq0 <= floorlevel * floorlevel)
286 goto skipagc;
287
288 // if (ndelayptr == 0)
289 // cerr << "3.3.l: " << "rlevelsq0 " << rlevelsq0 << "\n";
290
291 if (rlevelsq0 > rlevelsq1) {
292 rlevelsq1 = rlevelsq0;
293 } else {
294 rlevelsq1 = rlevelsq0 * rlevelsq1filter +
295 rlevelsq1 * (1 - rlevelsq1filter);
296 }
297
298 // vika.. rlevelsq1 joskus menee pahasti yli ayrauden
299
300 // if (ndelayptr == 0)
301 // cerr << "3.3.l: " << "rlevelsq1 " << rlevelsq1 << "\n";
302
303 rlevelsqn[0] = rlevelsq1;
304 for(i = 0; i < NFILT-1; i++) {
305 if (rlevelsqn[i] > rlevelsqn[i+1])
306 rlevelsqn[i+1] = rlevelsqn[i];
307 else
308 rlevelsqn[i+1] = rlevelsqn[i] * rlevelsq1filter +
309 rlevelsqn[i+1] * (1 - rlevelsq1filter);
310 }
311
312 efilt = rlevelsqefilter;
313 levelsqe = rlevelsqe[0] = rlevelsqn[NFILT-1];
314 for(i = 0; i < NEFILT-1; i++) {
315 // if (rlevelsqe[i] > FLT_MAX) rlevelsqe[i] = FLT_MAX;
316 // else {
317 rlevelsqe[i+1] = rlevelsqe[i] * efilt +
318 rlevelsqe[i+1] * (1.0 - efilt);
319 if (rlevelsqe[i+1] > levelsqe)
320 levelsqe = rlevelsqe[i+1];
321 efilt *= 1.0 / 1.5;
322 }
323
324 gain = targetlevel / sqrt(levelsqe);
325 if (compressionratio < 0.99) {
326 if (compressionratio == 0.50)
327 gain = sqrt(gain);
328 else
329 gain = exp(log(gain) * compressionratio);
330 }
331
332 if (gain < rgain)
333 rgain = gain * rlevelsqefilter/2 +
334 rgain * (1 - rlevelsqefilter/2);
335 else
336 rgain = gain * rgainfilter +
337 rgain * (1 - rgainfilter);
338
339 lastrgain = rgain;
340 if ( gain < lastrgain)
341 lastrgain = gain;
342
343 skipagc:;
344
345 tgain = lastrgain;
346
347 leftd = leftdelay[ndelayptr];
348 rightd = rightdelay[ndelayptr];
349
350 // cerr << "4.l:" << leftd << ", ndelayptr " << ndelayptr << "\n";
351
352 fastgain = tgain;
353 if (fastgain > maxfastgain)
354 fastgain = maxfastgain;
355
356 if (fastgain < 0.0001)
357 fastgain = 0.0001;
358
359 if (fastgaincompressionratio == 0.25) {
360 qgain = sqrt(sqrt(fastgain));
361 } else if (fastgaincompressionratio == 0.5) {
362 qgain = sqrt(fastgain);
363 } else if (fastgaincompressionratio == 1.0) {
364 qgain = fastgain;
365 } else {
366 qgain = exp(log(fastgain) * fastgaincompressionratio);
367 }
368
369 // cerr << "4.4-qgain: " << qgain << "\n";
370
371 tslowgain = tgain / qgain;
372 if (tslowgain > maxslowgain)
373 tslowgain = maxslowgain;
374 if (tslowgain < rmastergain0)
375 rmastergain0 = tslowgain;
376 else
377 rmastergain0 = tslowgain * rmastergain0filter +
378 (1 - rmastergain0filter) * rmastergain0;
379
380 slowgain = rmastergain0;
381 if (skipmode == 0)
382 npeakgain = slowgain * qgain;
383
384 /**/
385 newright = rightd * npeakgain;
386 if (fabs(newright) >= maxlevel)
387 nrgain = maxlevel / fabs(newright);
388 else
389 nrgain = 1.0;
390
391 newleft = leftd * npeakgain;
392 if (fabs(newleft) >= maxlevel)
393 nlgain = maxlevel / fabs(newleft);
394 else
395 nlgain = 1.0;
396
397 // cerr << "4.5.l:" << newleft << "\n";
398
399 ngain = nrgain;
400 if (nlgain < ngain)
401 ngain = nlgain;
402
403 ngsq = ngain * ngain;
404 if (ngsq <= rpeakgain0) {
405 // --debug
406 // if (ngsq < rpeakgain0) // cerr << "*";
407
408 rpeakgain0 = ngsq /* * 0.50 + rpeakgain0 * 0.50 */;
409 rpeaklimitdelay = peaklimitdelay;
410 } else if (rpeaklimitdelay == 0) {
411 if (nrgain > 1.0)
412 tnrgain = 1.0;
413 else
414 tnrgain = nrgain;
415 rpeakgain0 = tnrgain * rpeakgainfilter +
416 (1.0 - rpeakgainfilter) * rpeakgain0;
417 }
418
419 if (rpeakgain0 <= rpeakgain1) {
420 rpeakgain1 = rpeakgain0;
421 rpeaklimitdelay = peaklimitdelay;
422 } else if (rpeaklimitdelay == 0) {
423 rpeakgain1 = rpeakgainfilter * rpeakgain0 +
424 (1.0 - rpeakgainfilter) * rpeakgain1;
425 } else {
426 --rpeaklimitdelay;
427 }
428
429 sqrtrpeakgain = sqrt(rpeakgain1);
430 totalgain = npeakgain * sqrtrpeakgain;
431
432 right = newright * sqrtrpeakgain;
433
434 *iter.current(1) = right;
435 //insample->put_left(left / 32767.0);
436 // *righta = hardlimit(right, 32200, 32767);
437 // cerr << "5.l:" << newleft << "\n";
438
439 left = newleft * sqrtrpeakgain;
440 *iter.current(0) = left;
441 // insample->put_left(left / 32767.0);
442
443 // cerr << "6.l:" << left << "\n";
444 //
445 // *lefta = hardlimit(left, 32200, 32767);
446
447 // if (right != *righta || left != *lefta) {
448 // fprintf(stderr,"!");
449 // }
450
451 if (totalgain > maxgain)
452 maxgain = totalgain;
453 if (totalgain < mingain)
454 mingain = totalgain;
455 if (right > extra_maxlevel)
456 extra_maxlevel = right;
457 if (left > extra_maxlevel)
458 extra_maxlevel = left;
459
460 iter.next();
461 }
462 // cerr << "post:" << insample->get_left() << "\n";
463 }
464