1 /* August 24, 1998
2  * Copyright (C) 1998 Juergen Mueller And Sundry Contributors
3  * This source code is freely redistributable and may be used for
4  * any purpose.  This copyright notice must be maintained.
5  * Juergen Mueller And Sundry Contributors are not responsible for
6  * the consequences of using this software.
7  */
8 
9 /*
10  *      Chorus effect.
11  *
12  * Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ):
13  *
14  *        * gain-in                                           ___
15  * ibuff -----+--------------------------------------------->|   |
16  *            |      _________                               |   |
17  *            |     |         |                   * decay 1  |   |
18  *            +---->| delay 1 |----------------------------->|   |
19  *            |     |_________|                              |   |
20  *            |        /|\                                   |   |
21  *            :         |                                    |   |
22  *            : +-----------------+   +--------------+       | + |
23  *            : | Delay control 1 |<--| mod. speed 1 |       |   |
24  *            : +-----------------+   +--------------+       |   |
25  *            |      _________                               |   |
26  *            |     |         |                   * decay n  |   |
27  *            +---->| delay n |----------------------------->|   |
28  *                  |_________|                              |   |
29  *                     /|\                                   |___|
30  *                      |                                      |
31  *              +-----------------+   +--------------+         | * gain-out
32  *              | Delay control n |<--| mod. speed n |         |
33  *              +-----------------+   +--------------+         +----->obuff
34  *
35  *
36  * The delay i is controled by a sine or triangle modulation i ( 1 <= i <= n).
37  *
38  * Usage:
39  *   chorus gain-in gain-out delay-1 decay-1 speed-1 depth-1 -s1|t1 [
40  *       delay-2 decay-2 speed-2 depth-2 -s2|-t2 ... ]
41  *
42  * Where:
43  *   gain-in, decay-1 ... decay-n :  0.0 ... 1.0      volume
44  *   gain-out :  0.0 ...      volume
45  *   delay-1 ... delay-n :  20.0 ... 100.0 msec
46  *   speed-1 ... speed-n :  0.1 ... 5.0 Hz       modulation 1 ... n
47  *   depth-1 ... depth-n :  0.0 ... 10.0 msec    modulated delay 1 ... n
48  *   -s1 ... -sn : modulation by sine 1 ... n
49  *   -t1 ... -tn : modulation by triangle 1 ... n
50  *
51  * Note:
52  *   when decay is close to 1.0, the samples can begin clipping and the output
53  *   can saturate!
54  *
55  * Hint:
56  *   1 / out-gain < gain-in ( 1 + decay-1 + ... + decay-n )
57  *
58 */
59 
60 /*
61  * libSoX chorus effect file.
62  */
63 
64 #include "sox_i.h"
65 
66 #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
67 #include <string.h>
68 
69 #define MOD_SINE        0
70 #define MOD_TRIANGLE    1
71 #define MAX_CHORUS      7
72 
73 typedef struct {
74         int     num_chorus;
75         int     modulation[MAX_CHORUS];
76         int     counter;
77         long    phase[MAX_CHORUS];
78         float   *chorusbuf;
79         float   in_gain, out_gain;
80         float   delay[MAX_CHORUS], decay[MAX_CHORUS];
81         float   speed[MAX_CHORUS], depth[MAX_CHORUS];
82         long    length[MAX_CHORUS];
83         int     *lookup_tab[MAX_CHORUS];
84         int     depth_samples[MAX_CHORUS], samples[MAX_CHORUS];
85         int maxsamples;
86         unsigned int fade_out;
87 } priv_t;
88 
89 /*
90  * Process options
91  */
sox_chorus_getopts(sox_effect_t * effp,int argc,char ** argv)92 static int sox_chorus_getopts(sox_effect_t * effp, int argc, char **argv)
93 {
94         priv_t * chorus = (priv_t *) effp->priv;
95         int i;
96   --argc, ++argv;
97 
98         chorus->num_chorus = 0;
99         i = 0;
100 
101         if ( ( argc < 7 ) || (( argc - 2 ) % 5 ) )
102           return lsx_usage(effp);
103 
104         sscanf(argv[i++], "%f", &chorus->in_gain);
105         sscanf(argv[i++], "%f", &chorus->out_gain);
106         while ( i < argc ) {
107                 if ( chorus->num_chorus > MAX_CHORUS )
108                 {
109                         lsx_fail("chorus: to many delays, use less than %i delays", MAX_CHORUS);
110                         return (SOX_EOF);
111                 }
112                 sscanf(argv[i++], "%f", &chorus->delay[chorus->num_chorus]);
113                 sscanf(argv[i++], "%f", &chorus->decay[chorus->num_chorus]);
114                 sscanf(argv[i++], "%f", &chorus->speed[chorus->num_chorus]);
115                 sscanf(argv[i++], "%f", &chorus->depth[chorus->num_chorus]);
116                 if ( !strcmp(argv[i], "-s"))
117                         chorus->modulation[chorus->num_chorus] = MOD_SINE;
118                 else if ( ! strcmp(argv[i], "-t"))
119                         chorus->modulation[chorus->num_chorus] = MOD_TRIANGLE;
120                 else
121                   return lsx_usage(effp);
122                 i++;
123                 chorus->num_chorus++;
124         }
125         return (SOX_SUCCESS);
126 }
127 
128 /*
129  * Prepare for processing.
130  */
sox_chorus_start(sox_effect_t * effp)131 static int sox_chorus_start(sox_effect_t * effp)
132 {
133         priv_t * chorus = (priv_t *) effp->priv;
134         int i;
135         float sum_in_volume;
136 
137         chorus->maxsamples = 0;
138 
139         if ( chorus->in_gain < 0.0 )
140         {
141                 lsx_fail("chorus: gain-in must be positive!");
142                 return (SOX_EOF);
143         }
144         if ( chorus->in_gain > 1.0 )
145         {
146                 lsx_fail("chorus: gain-in must be less than 1.0!");
147                 return (SOX_EOF);
148         }
149         if ( chorus->out_gain < 0.0 )
150         {
151                 lsx_fail("chorus: gain-out must be positive!");
152                 return (SOX_EOF);
153         }
154         for ( i = 0; i < chorus->num_chorus; i++ ) {
155                 chorus->samples[i] = (int) ( ( chorus->delay[i] +
156                         chorus->depth[i] ) * effp->in_signal.rate / 1000.0);
157                 chorus->depth_samples[i] = (int) (chorus->depth[i] *
158                         effp->in_signal.rate / 1000.0);
159 
160                 if ( chorus->delay[i] < 20.0 )
161                 {
162                         lsx_fail("chorus: delay must be more than 20.0 msec!");
163                         return (SOX_EOF);
164                 }
165                 if ( chorus->delay[i] > 100.0 )
166                 {
167                         lsx_fail("chorus: delay must be less than 100.0 msec!");
168                         return (SOX_EOF);
169                 }
170                 if ( chorus->speed[i] < 0.1 )
171                 {
172                         lsx_fail("chorus: speed must be more than 0.1 Hz!");
173                         return (SOX_EOF);
174                 }
175                 if ( chorus->speed[i] > 5.0 )
176                 {
177                         lsx_fail("chorus: speed must be less than 5.0 Hz!");
178                         return (SOX_EOF);
179                 }
180                 if ( chorus->depth[i] < 0.0 )
181                 {
182                         lsx_fail("chorus: delay must be more positive!");
183                         return (SOX_EOF);
184                 }
185                 if ( chorus->depth[i] > 10.0 )
186                 {
187                     lsx_fail("chorus: delay must be less than 10.0 msec!");
188                     return (SOX_EOF);
189                 }
190                 if ( chorus->decay[i] < 0.0 )
191                 {
192                         lsx_fail("chorus: decay must be positive!" );
193                         return (SOX_EOF);
194                 }
195                 if ( chorus->decay[i] > 1.0 )
196                 {
197                         lsx_fail("chorus: decay must be less that 1.0!" );
198                         return (SOX_EOF);
199                 }
200                 chorus->length[i] = effp->in_signal.rate / chorus->speed[i];
201                 chorus->lookup_tab[i] = lsx_malloc(sizeof (int) * chorus->length[i]);
202 
203                 if (chorus->modulation[i] == MOD_SINE)
204                   lsx_generate_wave_table(SOX_WAVE_SINE, SOX_INT, chorus->lookup_tab[i],
205                                          (size_t)chorus->length[i], 0., (double)chorus->depth_samples[i], 0.);
206                 else
207                   lsx_generate_wave_table(SOX_WAVE_TRIANGLE, SOX_INT, chorus->lookup_tab[i],
208                                          (size_t)chorus->length[i],
209                                          (double)(chorus->samples[i] - 1 - 2 * chorus->depth_samples[i]),
210                                          (double)(chorus->samples[i] - 1), 3 * M_PI_2);
211                 chorus->phase[i] = 0;
212 
213                 if ( chorus->samples[i] > chorus->maxsamples )
214                   chorus->maxsamples = chorus->samples[i];
215         }
216 
217         /* Be nice and check the hint with warning, if... */
218         sum_in_volume = 1.0;
219         for ( i = 0; i < chorus->num_chorus; i++ )
220                 sum_in_volume += chorus->decay[i];
221         if ( chorus->in_gain * ( sum_in_volume ) > 1.0 / chorus->out_gain )
222         lsx_warn("chorus: warning >>> gain-out can cause saturation or clipping of output <<<");
223 
224 
225         chorus->chorusbuf = lsx_malloc(sizeof (float) * chorus->maxsamples);
226         for ( i = 0; i < chorus->maxsamples; i++ )
227                 chorus->chorusbuf[i] = 0.0;
228 
229         chorus->counter = 0;
230         chorus->fade_out = chorus->maxsamples;
231 
232   effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */
233 
234         return (SOX_SUCCESS);
235 }
236 
237 /*
238  * Processed signed long samples from ibuf to obuf.
239  * Return number of samples processed.
240  */
sox_chorus_flow(sox_effect_t * effp,const sox_sample_t * ibuf,sox_sample_t * obuf,size_t * isamp,size_t * osamp)241 static int sox_chorus_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
242                    size_t *isamp, size_t *osamp)
243 {
244         priv_t * chorus = (priv_t *) effp->priv;
245         int i;
246         float d_in, d_out;
247         sox_sample_t out;
248         size_t len = min(*isamp, *osamp);
249         *isamp = *osamp = len;
250 
251         while (len--) {
252                 /* Store delays as 24-bit signed longs */
253                 d_in = (float) *ibuf++ / 256;
254                 /* Compute output first */
255                 d_out = d_in * chorus->in_gain;
256                 for ( i = 0; i < chorus->num_chorus; i++ )
257                         d_out += chorus->chorusbuf[(chorus->maxsamples +
258                         chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) %
259                         chorus->maxsamples] * chorus->decay[i];
260                 /* Adjust the output volume and size to 24 bit */
261                 d_out = d_out * chorus->out_gain;
262                 out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
263                 *obuf++ = out * 256;
264                 /* Mix decay of delay and input */
265                 chorus->chorusbuf[chorus->counter] = d_in;
266                 chorus->counter =
267                         ( chorus->counter + 1 ) % chorus->maxsamples;
268                 for ( i = 0; i < chorus->num_chorus; i++ )
269                         chorus->phase[i]  =
270                                 ( chorus->phase[i] + 1 ) % chorus->length[i];
271         }
272         /* processed all samples */
273         return (SOX_SUCCESS);
274 }
275 
276 /*
277  * Drain out reverb lines.
278  */
sox_chorus_drain(sox_effect_t * effp,sox_sample_t * obuf,size_t * osamp)279 static int sox_chorus_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
280 {
281         priv_t * chorus = (priv_t *) effp->priv;
282         size_t done;
283         int i;
284 
285         float d_in, d_out;
286         sox_sample_t out;
287 
288         done = 0;
289         while ( ( done < *osamp ) && ( done < chorus->fade_out ) ) {
290                 d_in = 0;
291                 d_out = 0;
292                 /* Compute output first */
293                 for ( i = 0; i < chorus->num_chorus; i++ )
294                         d_out += chorus->chorusbuf[(chorus->maxsamples +
295                 chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) %
296                 chorus->maxsamples] * chorus->decay[i];
297                 /* Adjust the output volume and size to 24 bit */
298                 d_out = d_out * chorus->out_gain;
299                 out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
300                 *obuf++ = out * 256;
301                 /* Mix decay of delay and input */
302                 chorus->chorusbuf[chorus->counter] = d_in;
303                 chorus->counter =
304                         ( chorus->counter + 1 ) % chorus->maxsamples;
305                 for ( i = 0; i < chorus->num_chorus; i++ )
306                         chorus->phase[i]  =
307                                 ( chorus->phase[i] + 1 ) % chorus->length[i];
308                 done++;
309                 chorus->fade_out--;
310         }
311         /* samples played, it remains */
312         *osamp = done;
313         if (chorus->fade_out == 0)
314             return SOX_EOF;
315         else
316             return SOX_SUCCESS;
317 }
318 
319 /*
320  * Clean up chorus effect.
321  */
sox_chorus_stop(sox_effect_t * effp)322 static int sox_chorus_stop(sox_effect_t * effp)
323 {
324         priv_t * chorus = (priv_t *) effp->priv;
325         int i;
326 
327         free(chorus->chorusbuf);
328         chorus->chorusbuf = NULL;
329         for ( i = 0; i < chorus->num_chorus; i++ ) {
330                 free(chorus->lookup_tab[i]);
331                 chorus->lookup_tab[i] = NULL;
332         }
333         return (SOX_SUCCESS);
334 }
335 
336 static sox_effect_handler_t sox_chorus_effect = {
337   "chorus",
338   "gain-in gain-out delay decay speed depth [ -s | -t ]",
339   SOX_EFF_LENGTH | SOX_EFF_GAIN,
340   sox_chorus_getopts,
341   sox_chorus_start,
342   sox_chorus_flow,
343   sox_chorus_drain,
344   sox_chorus_stop,
345   NULL, sizeof(priv_t)
346 };
347 
lsx_chorus_effect_fn(void)348 const sox_effect_handler_t *lsx_chorus_effect_fn(void)
349 {
350     return &sox_chorus_effect;
351 }
352