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