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.
12 * Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ):
15 * ibuff -----+--------------------------------------------->| |
18 * +---->| delay 1 |----------------------------->| |
22 * : +-----------------+ +--------------+ | + |
23 * : | Delay control 1 |<--| mod. speed 1 | | |
24 * : +-----------------+ +--------------+ | |
27 * +---->| delay n |----------------------------->| |
31 * +-----------------+ +--------------+ | * gain-out
32 * | Delay control n |<--| mod. speed n | |
33 * +-----------------+ +--------------+ +----->obuff
36 * The delay i is controled by a sine or triangle modulation i ( 1 <= i <= n).
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 ... ]
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
52 * when decay is close to 1.0, the samples can begin clipping and the output
56 * 1 / out-gain < gain-in ( 1 + decay-1 + ... + decay-n )
61 * libSoX chorus effect file.
66 #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
70 #define MOD_TRIANGLE 1
75 int modulation
[MAX_CHORUS
];
77 long phase
[MAX_CHORUS
];
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
];
86 unsigned int fade_out
;
92 static int sox_chorus_getopts(sox_effect_t
* effp
, int argc
, char **argv
)
94 priv_t
* chorus
= (priv_t
*) effp
->priv
;
98 chorus
->num_chorus
= 0;
101 if ( ( argc
< 7 ) || (( argc
- 2 ) % 5 ) )
102 return lsx_usage(effp
);
104 sscanf(argv
[i
++], "%f", &chorus
->in_gain
);
105 sscanf(argv
[i
++], "%f", &chorus
->out_gain
);
107 if ( chorus
->num_chorus
> MAX_CHORUS
)
109 lsx_fail("chorus: to many delays, use less than %i delays", MAX_CHORUS
);
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
;
121 return lsx_usage(effp
);
123 chorus
->num_chorus
++;
125 return (SOX_SUCCESS
);
129 * Prepare for processing.
131 static int sox_chorus_start(sox_effect_t
* effp
)
133 priv_t
* chorus
= (priv_t
*) effp
->priv
;
137 chorus
->maxsamples
= 0;
139 if ( chorus
->in_gain
< 0.0 )
141 lsx_fail("chorus: gain-in must be positive!");
144 if ( chorus
->in_gain
> 1.0 )
146 lsx_fail("chorus: gain-in must be less than 1.0!");
149 if ( chorus
->out_gain
< 0.0 )
151 lsx_fail("chorus: gain-out must be positive!");
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);
160 if ( chorus
->delay
[i
] < 20.0 )
162 lsx_fail("chorus: delay must be more than 20.0 msec!");
165 if ( chorus
->delay
[i
] > 100.0 )
167 lsx_fail("chorus: delay must be less than 100.0 msec!");
170 if ( chorus
->speed
[i
] < 0.1 )
172 lsx_fail("chorus: speed must be more than 0.1 Hz!");
175 if ( chorus
->speed
[i
] > 5.0 )
177 lsx_fail("chorus: speed must be less than 5.0 Hz!");
180 if ( chorus
->depth
[i
] < 0.0 )
182 lsx_fail("chorus: delay must be more positive!");
185 if ( chorus
->depth
[i
] > 10.0 )
187 lsx_fail("chorus: delay must be less than 10.0 msec!");
190 if ( chorus
->decay
[i
] < 0.0 )
192 lsx_fail("chorus: decay must be positive!" );
195 if ( chorus
->decay
[i
] > 1.0 )
197 lsx_fail("chorus: decay must be less that 1.0!" );
200 chorus
->length
[i
] = effp
->in_signal
.rate
/ chorus
->speed
[i
];
201 chorus
->lookup_tab
[i
] = lsx_malloc(sizeof (int) * chorus
->length
[i
]);
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.);
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;
213 if ( chorus
->samples
[i
] > chorus
->maxsamples
)
214 chorus
->maxsamples
= chorus
->samples
[i
];
217 /* Be nice and check the hint with warning, if... */
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 <<<");
225 chorus
->chorusbuf
= lsx_malloc(sizeof (float) * chorus
->maxsamples
);
226 for ( i
= 0; i
< chorus
->maxsamples
; i
++ )
227 chorus
->chorusbuf
[i
] = 0.0;
230 chorus
->fade_out
= chorus
->maxsamples
;
232 effp
->out_signal
.length
= SOX_UNKNOWN_LEN
; /* TODO: calculate actual length */
234 return (SOX_SUCCESS
);
238 * Processed signed long samples from ibuf to obuf.
239 * Return number of samples processed.
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
)
244 priv_t
* chorus
= (priv_t
*) effp
->priv
;
248 size_t len
= min(*isamp
, *osamp
);
249 *isamp
= *osamp
= 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
);
264 /* Mix decay of delay and input */
265 chorus
->chorusbuf
[chorus
->counter
] = d_in
;
267 ( chorus
->counter
+ 1 ) % chorus
->maxsamples
;
268 for ( i
= 0; i
< chorus
->num_chorus
; i
++ )
270 ( chorus
->phase
[i
] + 1 ) % chorus
->length
[i
];
272 /* processed all samples */
273 return (SOX_SUCCESS
);
277 * Drain out reverb lines.
279 static int sox_chorus_drain(sox_effect_t
* effp
, sox_sample_t
*obuf
, size_t *osamp
)
281 priv_t
* chorus
= (priv_t
*) effp
->priv
;
289 while ( ( done
< *osamp
) && ( done
< chorus
->fade_out
) ) {
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
);
301 /* Mix decay of delay and input */
302 chorus
->chorusbuf
[chorus
->counter
] = d_in
;
304 ( chorus
->counter
+ 1 ) % chorus
->maxsamples
;
305 for ( i
= 0; i
< chorus
->num_chorus
; i
++ )
307 ( chorus
->phase
[i
] + 1 ) % chorus
->length
[i
];
311 /* samples played, it remains */
313 if (chorus
->fade_out
== 0)
320 * Clean up chorus effect.
322 static int sox_chorus_stop(sox_effect_t
* effp
)
324 priv_t
* chorus
= (priv_t
*) effp
->priv
;
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
;
333 return (SOX_SUCCESS
);
336 static sox_effect_handler_t sox_chorus_effect
= {
338 "gain-in gain-out delay decay speed depth [ -s | -t ]",
339 SOX_EFF_LENGTH
| SOX_EFF_GAIN
,
348 const sox_effect_handler_t
*lsx_chorus_effect_fn(void)
350 return &sox_chorus_effect
;