1 /* multiband compander effect for SoX
2  * by Daniel Pouzzner <douzzer@mega.nu> 2002-Oct-8
3  *
4  * Compander code adapted from the SoX compand effect, by Nick Bailey
5  *
6  * SoX is Copyright 1999 Chris Bagwell And Nick Bailey This source code is
7  * freely redistributable and may be used for any purpose.  This copyright
8  * notice must be maintained.  Chris Bagwell And Nick Bailey are not
9  * responsible for the consequences of using this software.
10  *
11  *
12  * Usage:
13  *   mcompand quoted_compand_args [crossover_frequency
14  *      quoted_compand_args [...]]
15  *
16  *   quoted_compand_args are as for the compand effect:
17  *
18  *   attack1,decay1[,attack2,decay2...]
19  *                  in-dB1,out-dB1[,in-dB2,out-dB2...]
20  *                 [ gain [ initial-volume [ delay ] ] ]
21  *
22  *   Beware a variety of headroom (clipping) bugaboos.
23  *
24  * Implementation details:
25  *   The input is divided into bands using 4th order Linkwitz-Riley IIRs.
26  *   This is akin to the crossover of a loudspeaker, and results in flat
27  *   frequency response absent compander action.
28  *
29  *   The outputs of the array of companders is summed, and sample truncation
30  *   is done on the final sum.
31  *
32  *   Modifications to the predictive compression code properly maintain
33  *   alignment of the outputs of the array of companders when the companders
34  *   have different prediction intervals (volume application delays).  Note
35  *   that the predictive mode of the limiter needs some TLC - in fact, a
36  *   rewrite - since what's really useful is to assure that a waveform won't
37  *   be clipped, by slewing the volume in advance so that the peak is at
38  *   limit (or below, if there's a higher subsequent peak visible in the
39  *   lookahead window) once it's reached.  */
40 
41 #ifdef NDEBUG /* Enable assert always. */
42 #undef NDEBUG /* Must undef above assert.h or other that might include it. */
43 #endif
44 
45 #include "sox_i.h"
46 #include <assert.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include "compandt.h"
50 #include "mcompand_xover.h"
51 
52 typedef struct {
53   sox_compandt_t transfer_fn;
54 
55   size_t expectedChannels; /* Also flags that channels aren't to be treated
56                            individually when = 1 and input not mono */
57   double *attackRate;   /* An array of attack rates */
58   double *decayRate;    /*    ... and of decay rates */
59   double *volume;       /* Current "volume" of each channel */
60   double delay;         /* Delay to apply before companding */
61   double topfreq;       /* upper bound crossover frequency */
62   crossover_t filter;
63   sox_sample_t *delay_buf;   /* Old samples, used for delay processing */
64   size_t delay_size;    /* lookahead for this band (in samples) - function of delay, above */
65   ptrdiff_t delay_buf_ptr; /* Index into delay_buf */
66   size_t delay_buf_cnt; /* No. of active entries in delay_buf */
67 } comp_band_t;
68 
69 typedef struct {
70   size_t nBands;
71   sox_sample_t *band_buf1, *band_buf2, *band_buf3;
72   size_t band_buf_len;
73   size_t delay_buf_size;/* Size of delay_buf in samples */
74   comp_band_t *bands;
75 
76   char *arg; /* copy of current argument */
77 } priv_t;
78 
79 /*
80  * Process options
81  *
82  * Don't do initialization now.
83  * The 'info' fields are not yet filled in.
84  */
sox_mcompand_getopts_1(comp_band_t * l,size_t n,char ** argv)85 static int sox_mcompand_getopts_1(comp_band_t * l, size_t n, char **argv)
86 {
87       char *s;
88       size_t rates, i, commas;
89 
90       /* Start by checking the attack and decay rates */
91 
92       for (s = argv[0], commas = 0; *s; ++s)
93         if (*s == ',') ++commas;
94 
95       if (commas % 2 == 0) /* There must be an even number of
96                               attack/decay parameters */
97       {
98         lsx_fail("compander: Odd number of attack & decay rate parameters");
99         return (SOX_EOF);
100       }
101 
102       rates = 1 + commas/2;
103       l->attackRate = lsx_malloc(sizeof(double) * rates);
104       l->decayRate  = lsx_malloc(sizeof(double) * rates);
105       l->volume = lsx_malloc(sizeof(double) * rates);
106       l->expectedChannels = rates;
107       l->delay_buf = NULL;
108 
109       /* Now tokenise the rates string and set up these arrays.  Keep
110          them in seconds at the moment: we don't know the sample rate yet. */
111 
112       s = strtok(argv[0], ","); i = 0;
113       do {
114         l->attackRate[i] = atof(s); s = strtok(NULL, ",");
115         l->decayRate[i]  = atof(s); s = strtok(NULL, ",");
116         ++i;
117       } while (s != NULL);
118 
119       if (!lsx_compandt_parse(&l->transfer_fn, argv[1], n>2 ? argv[2] : 0))
120         return SOX_EOF;
121 
122       /* Set the initial "volume" to be attibuted to the input channels.
123          Unless specified, choose 1.0 (maximum) otherwise clipping will
124          result if the user has seleced a long attack time */
125       for (i = 0; i < l->expectedChannels; ++i) {
126         double v = n>=4 ? pow(10.0, atof(argv[3])/20) : 1.0;
127         l->volume[i] = v;
128 
129         /* If there is a delay, store it. */
130         if (n >= 5) l->delay = atof(argv[4]);
131         else l->delay = 0.0;
132       }
133     return (SOX_SUCCESS);
134 }
135 
parse_subarg(char * s,char ** subargv,size_t * subargc)136 static int parse_subarg(char *s, char **subargv, size_t *subargc) {
137   char **ap;
138   char *s_p;
139 
140   s_p = s;
141   *subargc = 0;
142   for (ap = subargv; (*ap = strtok(s_p, " \t")) != NULL;) {
143     s_p = NULL;
144     if (*subargc == 5) {
145       ++*subargc;
146       break;
147     }
148     if (**ap != '\0') {
149       ++ap;
150       ++*subargc;
151     }
152   }
153 
154   if (*subargc < 2 || *subargc > 5)
155     {
156       lsx_fail("Wrong number of parameters for the compander effect within mcompand; usage:\n"
157   "\tattack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n"
158   "\twhere {} means optional and repeatable and [] means optional.\n"
159   "\tdB values are floating point or -inf'; times are in seconds.");
160       return (SOX_EOF);
161     } else
162       return SOX_SUCCESS;
163 }
164 
getopts(sox_effect_t * effp,int argc,char ** argv)165 static int getopts(sox_effect_t * effp, int argc, char **argv)
166 {
167   char *subargv[6], *cp;
168   size_t subargc, i;
169 
170   priv_t * c = (priv_t *) effp->priv;
171   --argc, ++argv;
172 
173   c->band_buf1 = c->band_buf2 = c->band_buf3 = 0;
174   c->band_buf_len = 0;
175 
176   /* how many bands? */
177   if (! (argc&1)) {
178     lsx_fail("mcompand accepts only an odd number of arguments:\argc"
179             "  mcompand quoted_compand_args [crossover_freq quoted_compand_args [...]]");
180     return SOX_EOF;
181   }
182   c->nBands = (argc+1)>>1;
183 
184   c->bands = lsx_calloc(c->nBands, sizeof(comp_band_t));
185 
186   for (i=0;i<c->nBands;++i) {
187     c->arg = lsx_strdup(argv[i<<1]);
188     if (parse_subarg(c->arg,subargv,&subargc) != SOX_SUCCESS)
189       return SOX_EOF;
190     if (sox_mcompand_getopts_1(&c->bands[i], subargc, &subargv[0]) != SOX_SUCCESS)
191       return SOX_EOF;
192     free(c->arg);
193     c->arg = NULL;
194     if (i == (c->nBands-1))
195       c->bands[i].topfreq = 0;
196     else {
197       c->bands[i].topfreq = lsx_parse_frequency(argv[(i<<1)+1],&cp);
198       if (*cp) {
199         lsx_fail("bad frequency in args to mcompand");
200         return SOX_EOF;
201       }
202       if ((i>0) && (c->bands[i].topfreq < c->bands[i-1].topfreq)) {
203         lsx_fail("mcompand crossover frequencies must be in ascending order.");
204         return SOX_EOF;
205       }
206     }
207   }
208 
209   return SOX_SUCCESS;
210 }
211 
212 /*
213  * Prepare processing.
214  * Do all initializations.
215  */
start(sox_effect_t * effp)216 static int start(sox_effect_t * effp)
217 {
218   priv_t * c = (priv_t *) effp->priv;
219   comp_band_t * l;
220   size_t i;
221   size_t band;
222 
223   for (band=0;band<c->nBands;++band) {
224     l = &c->bands[band];
225     l->delay_size = c->bands[band].delay * effp->out_signal.rate * effp->out_signal.channels;
226     if (l->delay_size > c->delay_buf_size)
227       c->delay_buf_size = l->delay_size;
228   }
229 
230   for (band=0;band<c->nBands;++band) {
231     l = &c->bands[band];
232     /* Convert attack and decay rates using number of samples */
233 
234     for (i = 0; i < l->expectedChannels; ++i) {
235       if (l->attackRate[i] > 1.0/effp->out_signal.rate)
236         l->attackRate[i] = 1.0 -
237           exp(-1.0/(effp->out_signal.rate * l->attackRate[i]));
238       else
239         l->attackRate[i] = 1.0;
240       if (l->decayRate[i] > 1.0/effp->out_signal.rate)
241         l->decayRate[i] = 1.0 -
242           exp(-1.0/(effp->out_signal.rate * l->decayRate[i]));
243       else
244         l->decayRate[i] = 1.0;
245     }
246 
247     /* Allocate the delay buffer */
248     if (c->delay_buf_size > 0)
249       l->delay_buf = lsx_calloc(sizeof(long), c->delay_buf_size);
250     l->delay_buf_ptr = 0;
251     l->delay_buf_cnt = 0;
252 
253     if (l->topfreq != 0)
254       crossover_setup(effp, &l->filter, l->topfreq);
255   }
256   return (SOX_SUCCESS);
257 }
258 
259 /*
260  * Update a volume value using the given sample
261  * value, the attack rate and decay rate
262  */
263 
doVolume(double * v,double samp,comp_band_t * l,size_t chan)264 static void doVolume(double *v, double samp, comp_band_t * l, size_t chan)
265 {
266   double s = samp/(~((sox_sample_t)1<<31));
267   double delta = s - *v;
268 
269   if (delta > 0.0) /* increase volume according to attack rate */
270     *v += delta * l->attackRate[chan];
271   else             /* reduce volume according to decay rate */
272     *v += delta * l->decayRate[chan];
273 }
274 
sox_mcompand_flow_1(sox_effect_t * effp,priv_t * c,comp_band_t * l,const sox_sample_t * ibuf,sox_sample_t * obuf,size_t len,size_t filechans)275 static int sox_mcompand_flow_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t len, size_t filechans)
276 {
277   size_t idone, odone;
278 
279   for (idone = 0, odone = 0; idone < len; ibuf += filechans) {
280     size_t chan;
281 
282     /* Maintain the volume fields by simulating a leaky pump circuit */
283 
284     if (l->expectedChannels == 1 && filechans > 1) {
285       /* User is expecting same compander for all channels */
286       double maxsamp = 0.0;
287       for (chan = 0; chan < filechans; ++chan) {
288         double rect = fabs((double)ibuf[chan]);
289         if (rect > maxsamp)
290           maxsamp = rect;
291       }
292       doVolume(&l->volume[0], maxsamp, l, (size_t) 0);
293     } else {
294       for (chan = 0; chan < filechans; ++chan)
295         doVolume(&l->volume[chan], fabs((double)ibuf[chan]), l, chan);
296     }
297 
298     /* Volume memory is updated: perform compand */
299     for (chan = 0; chan < filechans; ++chan) {
300       int ch = l->expectedChannels > 1 ? chan : 0;
301       double level_in_lin = l->volume[ch];
302       double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
303       double checkbuf;
304 
305       if (c->delay_buf_size <= 0) {
306         checkbuf = ibuf[chan] * level_out_lin;
307         SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
308         obuf[odone++] = checkbuf;
309         idone++;
310       } else {
311         /* FIXME: note that this lookahead algorithm is really lame:
312            the response to a peak is released before the peak
313            arrives. */
314 
315         /* because volume application delays differ band to band, but
316            total delay doesn't, the volume is applied in an iteration
317            preceding that in which the sample goes to obuf, except in
318            the band(s) with the longest vol app delay.
319 
320            the offset between delay_buf_ptr and the sample to apply
321            vol to, is a constant equal to the difference between this
322            band's delay and the longest delay of all the bands. */
323 
324         if (l->delay_buf_cnt >= l->delay_size) {
325           checkbuf = l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] * level_out_lin;
326           SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
327           l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] = checkbuf;
328         }
329         if (l->delay_buf_cnt >= c->delay_buf_size) {
330           obuf[odone] = l->delay_buf[l->delay_buf_ptr];
331           odone++;
332           idone++;
333         } else {
334           l->delay_buf_cnt++;
335           idone++; /* no "odone++" because we did not fill obuf[...] */
336         }
337         l->delay_buf[l->delay_buf_ptr++] = ibuf[chan];
338         l->delay_buf_ptr %= c->delay_buf_size;
339       }
340     }
341   }
342 
343   if (idone != odone || idone != len) {
344     /* Emergency brake - will lead to memory corruption otherwise since we
345        cannot report back to flow() how many samples were consumed/emitted.
346        Additionally, flow() doesn't know how to handle diverging
347        sub-compander delays. */
348     lsx_fail("Using a compander delay within mcompand is currently not supported");
349     exit(1);
350     /* FIXME */
351   }
352 
353   return (SOX_SUCCESS);
354 }
355 
356 /*
357  * Processed signed long samples from ibuf to obuf.
358  * Return number of samples processed.
359  */
flow(sox_effect_t * effp,const sox_sample_t * ibuf,sox_sample_t * obuf,size_t * isamp,size_t * osamp)360 static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
361                      size_t *isamp, size_t *osamp) {
362   priv_t * c = (priv_t *) effp->priv;
363   comp_band_t * l;
364   size_t len = min(*isamp, *osamp);
365   size_t band, i;
366   sox_sample_t *abuf, *bbuf, *cbuf, *oldabuf, *ibuf_copy;
367   double out;
368 
369   if (c->band_buf_len < len) {
370     c->band_buf1 = lsx_realloc(c->band_buf1,len*sizeof(sox_sample_t));
371     c->band_buf2 = lsx_realloc(c->band_buf2,len*sizeof(sox_sample_t));
372     c->band_buf3 = lsx_realloc(c->band_buf3,len*sizeof(sox_sample_t));
373     c->band_buf_len = len;
374   }
375 
376   len -= len % effp->out_signal.channels;
377 
378   ibuf_copy = lsx_malloc(*isamp * sizeof(sox_sample_t));
379   memcpy(ibuf_copy, ibuf, *isamp * sizeof(sox_sample_t));
380 
381   /* split ibuf into bands using filters, pipe each band through sox_mcompand_flow_1, then add back together and write to obuf */
382 
383   memset(obuf,0,len * sizeof *obuf);
384   for (band=0,abuf=ibuf_copy,bbuf=c->band_buf2,cbuf=c->band_buf1;band<c->nBands;++band) {
385     l = &c->bands[band];
386 
387     if (l->topfreq)
388       crossover_flow(effp, &l->filter, abuf, bbuf, cbuf, len);
389     else {
390       bbuf = abuf;
391       abuf = cbuf;
392     }
393     if (abuf == ibuf_copy)
394       abuf = c->band_buf3;
395     (void)sox_mcompand_flow_1(effp, c,l,bbuf,abuf,len, (size_t)effp->out_signal.channels);
396     for (i=0;i<len;++i)
397     {
398       out = (double)obuf[i] + (double)abuf[i];
399       SOX_SAMPLE_CLIP_COUNT(out, effp->clips);
400       obuf[i] = out;
401     }
402     oldabuf = abuf;
403     abuf = cbuf;
404     cbuf = oldabuf;
405   }
406 
407   *isamp = *osamp = len;
408 
409   free(ibuf_copy);
410 
411   return SOX_SUCCESS;
412 }
413 
sox_mcompand_drain_1(sox_effect_t * effp,priv_t * c,comp_band_t * l,sox_sample_t * obuf,size_t maxdrain)414 static int sox_mcompand_drain_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, sox_sample_t *obuf, size_t maxdrain)
415 {
416   size_t done;
417   double out;
418 
419   /*
420    * Drain out delay samples.  Note that this loop does all channels.
421    */
422   for (done = 0;  done < maxdrain  &&  l->delay_buf_cnt > 0;  done++) {
423     out = obuf[done] + l->delay_buf[l->delay_buf_ptr++];
424     SOX_SAMPLE_CLIP_COUNT(out, effp->clips);
425     obuf[done] = out;
426     l->delay_buf_ptr %= c->delay_buf_size;
427     l->delay_buf_cnt--;
428   }
429 
430   /* tell caller number of samples played */
431   return done;
432 
433 }
434 
435 /*
436  * Drain out compander delay lines.
437  */
drain(sox_effect_t * effp,sox_sample_t * obuf,size_t * osamp)438 static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
439 {
440   size_t band, drained, mostdrained = 0;
441   priv_t * c = (priv_t *)effp->priv;
442   comp_band_t * l;
443 
444   *osamp -= *osamp % effp->out_signal.channels;
445 
446   memset(obuf,0,*osamp * sizeof *obuf);
447   for (band=0;band<c->nBands;++band) {
448     l = &c->bands[band];
449     drained = sox_mcompand_drain_1(effp, c,l,obuf,*osamp);
450     if (drained > mostdrained)
451       mostdrained = drained;
452   }
453 
454   *osamp = mostdrained;
455 
456   if (mostdrained)
457       return SOX_SUCCESS;
458   else
459       return SOX_EOF;
460 }
461 
462 /*
463  * Clean up compander effect.
464  */
stop(sox_effect_t * effp)465 static int stop(sox_effect_t * effp)
466 {
467   priv_t * c = (priv_t *) effp->priv;
468   comp_band_t * l;
469   size_t band;
470 
471   free(c->band_buf1);
472   c->band_buf1 = NULL;
473   free(c->band_buf2);
474   c->band_buf2 = NULL;
475   free(c->band_buf3);
476   c->band_buf3 = NULL;
477 
478   for (band = 0; band < c->nBands; band++) {
479     l = &c->bands[band];
480     free(l->delay_buf);
481     if (l->topfreq != 0)
482       free(l->filter.previous);
483   }
484 
485   return SOX_SUCCESS;
486 }
487 
lsx_kill(sox_effect_t * effp)488 static int lsx_kill(sox_effect_t * effp)
489 {
490   priv_t * c = (priv_t *) effp->priv;
491   comp_band_t * l;
492   size_t band;
493 
494   for (band = 0; band < c->nBands; band++) {
495     l = &c->bands[band];
496     lsx_compandt_kill(&l->transfer_fn);
497     free(l->decayRate);
498     free(l->attackRate);
499     free(l->volume);
500   }
501   free(c->arg);
502   free(c->bands);
503   c->bands = NULL;
504 
505   return SOX_SUCCESS;
506 }
507 
lsx_mcompand_effect_fn(void)508 const sox_effect_handler_t *lsx_mcompand_effect_fn(void)
509 {
510   static sox_effect_handler_t handler = {
511     "mcompand",
512     "quoted_compand_args [crossover_frequency[k] quoted_compand_args [...]]\n"
513     "\n"
514     "quoted_compand_args are as for the compand effect:\n"
515     "\n"
516     "  attack1,decay1[,attack2,decay2...]\n"
517     "                 in-dB1,out-dB1[,in-dB2,out-dB2...]\n"
518     "                [ gain [ initial-volume [ delay ] ] ]",
519     SOX_EFF_MCHAN | SOX_EFF_GAIN,
520     getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t)
521   };
522 
523   return &handler;
524 }
525