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