formats: clarify setting of reverse_bytes
[sox.git] / src / compand.c
blob4c3df5cb79ec0a9e44af261618fdb76051572b52
1 /* libSoX compander effect
3 * Written by Nick Bailey (nick@bailey-family.org.uk or
4 * n.bailey@elec.gla.ac.uk)
6 * Copyright 1999 Chris Bagwell And Nick Bailey
7 * This source code is freely redistributable and may be used for
8 * any purpose. This copyright notice must be maintained.
9 * Chris Bagwell And Nick Bailey are not responsible for
10 * the consequences of using this software.
13 #include "sox_i.h"
15 #include <string.h>
16 #include <stdlib.h>
17 #include "compandt.h"
20 * Compressor/expander effect for libSoX.
22 * Flow diagram for one channel:
24 * ------------ ---------------
25 * | | | | ---
26 * ibuff ---+---| integrator |--->| transfer func |--->| |
27 * | | | | | | |
28 * | ------------ --------------- | | * gain
29 * | | * |----------->obuff
30 * | ------- | |
31 * | | | | |
32 * +----->| delay |-------------------------->| |
33 * | | ---
34 * -------
36 #define compand_usage \
37 "attack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" \
38 "\twhere {} means optional and repeatable and [] means optional.\n" \
39 "\tdB values are floating point or -inf'; times are in seconds."
41 * Note: clipping can occur if the transfer function pushes things too
42 * close to 0 dB. In that case, use a negative gain, or reduce the
43 * output level of the transfer function.
46 typedef struct {
47 sox_compandt_t transfer_fn;
49 struct {
50 double attack_times[2]; /* 0:attack_time, 1:decay_time */
51 double volume; /* Current "volume" of each channel */
52 } * channels;
53 unsigned expectedChannels;/* Also flags that channels aren't to be treated
54 individually when = 1 and input not mono */
55 double delay; /* Delay to apply before companding */
56 sox_sample_t *delay_buf; /* Old samples, used for delay processing */
57 ptrdiff_t delay_buf_size;/* Size of delay_buf in samples */
58 ptrdiff_t delay_buf_index; /* Index into delay_buf */
59 ptrdiff_t delay_buf_cnt; /* No. of active entries in delay_buf */
60 int delay_buf_full; /* Shows buffer situation (important for drain) */
62 char *arg0; /* copies of arguments, so that they may be modified */
63 char *arg1;
64 char *arg2;
65 } priv_t;
67 static int getopts(sox_effect_t * effp, int argc, char * * argv)
69 priv_t * l = (priv_t *) effp->priv;
70 char * s;
71 char dummy; /* To check for extraneous chars. */
72 unsigned pairs, i, j, commas;
74 --argc, ++argv;
75 if (argc < 2 || argc > 5)
76 return lsx_usage(effp);
78 l->arg0 = lsx_strdup(argv[0]);
79 l->arg1 = lsx_strdup(argv[1]);
80 l->arg2 = argc > 2 ? lsx_strdup(argv[2]) : NULL;
82 /* Start by checking the attack and decay rates */
83 for (s = l->arg0, commas = 0; *s; ++s) if (*s == ',') ++commas;
84 if ((commas % 2) == 0) {
85 lsx_fail("there must be an even number of attack/decay parameters");
86 return SOX_EOF;
88 pairs = 1 + commas/2;
89 l->channels = lsx_calloc(pairs, sizeof(*l->channels));
90 l->expectedChannels = pairs;
92 /* Now tokenise the rates string and set up these arrays. Keep
93 them in seconds at the moment: we don't know the sample rate yet. */
94 for (i = 0, s = strtok(l->arg0, ","); s != NULL; ++i) {
95 for (j = 0; j < 2; ++j) {
96 if (sscanf(s, "%lf %c", &l->channels[i].attack_times[j], &dummy) != 1) {
97 lsx_fail("syntax error trying to read attack/decay time");
98 return SOX_EOF;
99 } else if (l->channels[i].attack_times[j] < 0) {
100 lsx_fail("attack & decay times can't be less than 0 seconds");
101 return SOX_EOF;
103 s = strtok(NULL, ",");
107 if (!lsx_compandt_parse(&l->transfer_fn, l->arg1, l->arg2))
108 return SOX_EOF;
110 /* Set the initial "volume" to be attibuted to the input channels.
111 Unless specified, choose 0dB otherwise clipping will
112 result if the user has seleced a long attack time */
113 for (i = 0; i < l->expectedChannels; ++i) {
114 double init_vol_dB = 0;
115 if (argc > 3 && sscanf(argv[3], "%lf %c", &init_vol_dB, &dummy) != 1) {
116 lsx_fail("syntax error trying to read initial volume");
117 return SOX_EOF;
118 } else if (init_vol_dB > 0) {
119 lsx_fail("initial volume is relative to maximum volume so can't exceed 0dB");
120 return SOX_EOF;
122 l->channels[i].volume = pow(10., init_vol_dB / 20);
125 /* If there is a delay, store it. */
126 if (argc > 4 && sscanf(argv[4], "%lf %c", &l->delay, &dummy) != 1) {
127 lsx_fail("syntax error trying to read delay value");
128 return SOX_EOF;
129 } else if (l->delay < 0) {
130 lsx_fail("delay can't be less than 0 seconds");
131 return SOX_EOF;
134 return SOX_SUCCESS;
137 static int start(sox_effect_t * effp)
139 priv_t * l = (priv_t *) effp->priv;
140 unsigned i, j;
142 lsx_debug("%i input channel(s) expected: actually %i",
143 l->expectedChannels, effp->out_signal.channels);
144 for (i = 0; i < l->expectedChannels; ++i)
145 lsx_debug("Channel %i: attack = %g decay = %g", i,
146 l->channels[i].attack_times[0], l->channels[i].attack_times[1]);
147 if (!lsx_compandt_show(&l->transfer_fn, effp->global_info->plot))
148 return SOX_EOF;
150 /* Convert attack and decay rates using number of samples */
151 for (i = 0; i < l->expectedChannels; ++i)
152 for (j = 0; j < 2; ++j)
153 if (l->channels[i].attack_times[j] > 1.0/effp->out_signal.rate)
154 l->channels[i].attack_times[j] = 1.0 -
155 exp(-1.0/(effp->out_signal.rate * l->channels[i].attack_times[j]));
156 else
157 l->channels[i].attack_times[j] = 1.0;
159 /* Allocate the delay buffer */
160 l->delay_buf_size = l->delay * effp->out_signal.rate * effp->out_signal.channels;
161 if (l->delay_buf_size > 0)
162 l->delay_buf = lsx_calloc((size_t)l->delay_buf_size, sizeof(*l->delay_buf));
163 l->delay_buf_index = 0;
164 l->delay_buf_cnt = 0;
165 l->delay_buf_full= 0;
167 return SOX_SUCCESS;
171 * Update a volume value using the given sample
172 * value, the attack rate and decay rate
174 static void doVolume(double *v, double samp, priv_t * l, int chan)
176 double s = -samp / SOX_SAMPLE_MIN;
177 double delta = s - *v;
179 if (delta > 0.0) /* increase volume according to attack rate */
180 *v += delta * l->channels[chan].attack_times[0];
181 else /* reduce volume according to decay rate */
182 *v += delta * l->channels[chan].attack_times[1];
185 static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
186 size_t *isamp, size_t *osamp)
188 priv_t * l = (priv_t *) effp->priv;
189 int len = (*isamp > *osamp) ? *osamp : *isamp;
190 int filechans = effp->out_signal.channels;
191 int idone,odone;
193 for (idone = 0,odone = 0; idone < len; ibuf += filechans) {
194 int chan;
196 /* Maintain the volume fields by simulating a leaky pump circuit */
197 for (chan = 0; chan < filechans; ++chan) {
198 if (l->expectedChannels == 1 && filechans > 1) {
199 /* User is expecting same compander for all channels */
200 int i;
201 double maxsamp = 0.0;
202 for (i = 0; i < filechans; ++i) {
203 double rect = fabs((double)ibuf[i]);
204 if (rect > maxsamp) maxsamp = rect;
206 doVolume(&l->channels[0].volume, maxsamp, l, 0);
207 break;
208 } else
209 doVolume(&l->channels[chan].volume, fabs((double)ibuf[chan]), l, chan);
212 /* Volume memory is updated: perform compand */
213 for (chan = 0; chan < filechans; ++chan) {
214 int ch = l->expectedChannels > 1 ? chan : 0;
215 double level_in_lin = l->channels[ch].volume;
216 double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
217 double checkbuf;
219 if (l->delay_buf_size <= 0) {
220 checkbuf = ibuf[chan] * level_out_lin;
221 SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
222 obuf[odone++] = checkbuf;
223 idone++;
224 } else {
225 if (l->delay_buf_cnt >= l->delay_buf_size) {
226 l->delay_buf_full=1; /* delay buffer is now definitely full */
227 checkbuf = l->delay_buf[l->delay_buf_index] * level_out_lin;
228 SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
229 obuf[odone] = checkbuf;
230 odone++;
231 idone++;
232 } else {
233 l->delay_buf_cnt++;
234 idone++; /* no "odone++" because we did not fill obuf[...] */
236 l->delay_buf[l->delay_buf_index++] = ibuf[chan];
237 l->delay_buf_index %= l->delay_buf_size;
242 *isamp = idone; *osamp = odone;
243 return (SOX_SUCCESS);
246 static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
248 priv_t * l = (priv_t *) effp->priv;
249 size_t chan, done = 0;
251 if (l->delay_buf_full == 0)
252 l->delay_buf_index = 0;
253 while (done+effp->out_signal.channels <= *osamp && l->delay_buf_cnt > 0)
254 for (chan = 0; chan < effp->out_signal.channels; ++chan) {
255 int c = l->expectedChannels > 1 ? chan : 0;
256 double level_in_lin = l->channels[c].volume;
257 double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
258 obuf[done++] = l->delay_buf[l->delay_buf_index++] * level_out_lin;
259 l->delay_buf_index %= l->delay_buf_size;
260 l->delay_buf_cnt--;
262 *osamp = done;
263 return l->delay_buf_cnt > 0 ? SOX_SUCCESS : SOX_EOF;
266 static int stop(sox_effect_t * effp)
268 priv_t * l = (priv_t *) effp->priv;
270 free(l->delay_buf);
271 return SOX_SUCCESS;
274 static int lsx_kill(sox_effect_t * effp)
276 priv_t * l = (priv_t *) effp->priv;
278 lsx_compandt_kill(&l->transfer_fn);
279 free(l->channels);
280 free(l->arg0);
281 free(l->arg1);
282 free(l->arg2);
283 return SOX_SUCCESS;
286 sox_effect_handler_t const * lsx_compand_effect_fn(void)
288 static sox_effect_handler_t handler = {
289 "compand", compand_usage, SOX_EFF_MCHAN | SOX_EFF_GAIN,
290 getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t)
292 return &handler;