Updating osxbuild to work with OS X 10.7+/XCode 4.x.
[sox.git] / src / effects.c
blob435412fa72c684bdafd4783080d1efe511bb8af7
1 /* SoX Effects chain (c) 2007 robs@users.sourceforge.net
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #define LSX_EFF_ALIAS
19 #include "sox_i.h"
20 #include <assert.h>
21 #include <string.h>
22 #ifdef HAVE_STRINGS_H
23 #include <strings.h>
24 #endif
26 #define DEBUG_EFFECTS_CHAIN 0
28 /* Default effect handler functions for do-nothing situations: */
30 static int default_function(sox_effect_t * effp UNUSED)
32 return SOX_SUCCESS;
35 /* Pass through samples verbatim */
36 int lsx_flow_copy(sox_effect_t * effp UNUSED, const sox_sample_t * ibuf,
37 sox_sample_t * obuf, size_t * isamp, size_t * osamp)
39 *isamp = *osamp = min(*isamp, *osamp);
40 memcpy(obuf, ibuf, *isamp * sizeof(*obuf));
41 return SOX_SUCCESS;
44 /* Inform no more samples to drain */
45 static int default_drain(sox_effect_t * effp UNUSED, sox_sample_t *obuf UNUSED, size_t *osamp)
47 *osamp = 0;
48 return SOX_EOF;
51 /* Check that no parameters have been given */
52 static int default_getopts(sox_effect_t * effp, int argc, char **argv UNUSED)
54 return --argc? lsx_usage(effp) : SOX_SUCCESS;
57 /* Partially initialise the effect structure; signal info will come later */
58 sox_effect_t * sox_create_effect(sox_effect_handler_t const * eh)
60 sox_effect_t * effp = lsx_calloc(1, sizeof(*effp));
61 effp->obuf = NULL;
63 effp->global_info = sox_get_effects_globals();
64 effp->handler = *eh;
65 if (!effp->handler.getopts) effp->handler.getopts = default_getopts;
66 if (!effp->handler.start ) effp->handler.start = default_function;
67 if (!effp->handler.flow ) effp->handler.flow = lsx_flow_copy;
68 if (!effp->handler.drain ) effp->handler.drain = default_drain;
69 if (!effp->handler.stop ) effp->handler.stop = default_function;
70 if (!effp->handler.kill ) effp->handler.kill = default_function;
72 effp->priv = lsx_calloc(1, effp->handler.priv_size);
74 return effp;
75 } /* sox_create_effect */
77 int sox_effect_options(sox_effect_t *effp, int argc, char * const argv[])
79 int result;
81 char * * argv2 = lsx_malloc((argc + 1) * sizeof(*argv2));
82 argv2[0] = (char *)effp->handler.name;
83 memcpy(argv2 + 1, argv, argc * sizeof(*argv2));
84 result = effp->handler.getopts(effp, argc + 1, argv2);
85 free(argv2);
86 return result;
87 } /* sox_effect_options */
89 /* Effects chain: */
91 sox_effects_chain_t * sox_create_effects_chain(
92 sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc)
94 sox_effects_chain_t * result = lsx_calloc(1, sizeof(sox_effects_chain_t));
95 result->global_info = *sox_get_effects_globals();
96 result->in_enc = in_enc;
97 result->out_enc = out_enc;
98 return result;
99 } /* sox_create_effects_chain */
101 void sox_delete_effects_chain(sox_effects_chain_t *ecp)
103 if (ecp && ecp->length)
104 sox_delete_effects(ecp);
105 free(ecp->effects);
106 free(ecp);
107 } /* sox_delete_effects_chain */
109 /* Effect can call in start() or flow() to set minimum input size to flow() */
110 int lsx_effect_set_imin(sox_effect_t * effp, size_t imin)
112 if (imin > sox_globals.bufsiz / effp->flows) {
113 lsx_fail("sox_bufsiz not big enough");
114 return SOX_EOF;
117 effp->imin = imin;
118 return SOX_SUCCESS;
121 /* Effects table to be extended in steps of EFF_TABLE_STEP */
122 #define EFF_TABLE_STEP 8
124 /* Add an effect to the chain. *in is the input signal for this effect. *out is
125 * a suggestion as to what the output signal should be, but depending on its
126 * given options and *in, the effect can choose to do differently. Whatever
127 * output rate and channels the effect does produce are written back to *in,
128 * ready for the next effect in the chain.
130 int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out)
132 int ret, (*start)(sox_effect_t * effp) = effp->handler.start;
133 unsigned f;
134 sox_effect_t eff0; /* Copy of effect for flow 0 before calling start */
136 effp->global_info = &chain->global_info;
137 effp->in_signal = *in;
138 effp->out_signal = *out;
139 effp->in_encoding = chain->in_enc;
140 effp->out_encoding = chain->out_enc;
141 if (!(effp->handler.flags & SOX_EFF_CHAN))
142 effp->out_signal.channels = in->channels;
143 if (!(effp->handler.flags & SOX_EFF_RATE))
144 effp->out_signal.rate = in->rate;
145 if (!(effp->handler.flags & SOX_EFF_PREC))
146 effp->out_signal.precision = (effp->handler.flags & SOX_EFF_MODIFY)?
147 in->precision : SOX_SAMPLE_PRECISION;
148 if (!(effp->handler.flags & SOX_EFF_GAIN))
149 effp->out_signal.mult = in->mult;
151 effp->flows =
152 (effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->in_signal.channels;
153 effp->clips = 0;
154 effp->imin = 0;
155 eff0 = *effp, eff0.priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
156 eff0.in_signal.mult = NULL; /* Only used in channel 0 */
157 ret = start(effp);
158 if (ret == SOX_EFF_NULL) {
159 lsx_report("has no effect in this configuration");
160 free(eff0.priv);
161 free(effp->priv);
162 effp->priv = NULL;
163 return SOX_SUCCESS;
165 if (ret != SOX_SUCCESS) {
166 free(eff0.priv);
167 return SOX_EOF;
169 if (in->mult)
170 lsx_debug("mult=%g", *in->mult);
172 if (!(effp->handler.flags & SOX_EFF_LENGTH)) {
173 effp->out_signal.length = in->length;
174 if (effp->out_signal.length != SOX_UNKNOWN_LEN) {
175 if (effp->handler.flags & SOX_EFF_CHAN)
176 effp->out_signal.length =
177 effp->out_signal.length / in->channels * effp->out_signal.channels;
178 if (effp->handler.flags & SOX_EFF_RATE)
179 effp->out_signal.length =
180 effp->out_signal.length / in->rate * effp->out_signal.rate + .5;
184 *in = effp->out_signal;
186 if (chain->length == chain->table_size) {
187 chain->table_size += EFF_TABLE_STEP;
188 lsx_debug_more("sox_add_effect: extending effects table, "
189 "new size = %lu", (unsigned long)chain->table_size);
190 lsx_revalloc(chain->effects, chain->table_size);
193 chain->effects[chain->length] =
194 lsx_calloc(effp->flows, sizeof(chain->effects[chain->length][0]));
195 chain->effects[chain->length][0] = *effp;
197 for (f = 1; f < effp->flows; ++f) {
198 chain->effects[chain->length][f] = eff0;
199 chain->effects[chain->length][f].flow = f;
200 chain->effects[chain->length][f].priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
201 if (start(&chain->effects[chain->length][f]) != SOX_SUCCESS) {
202 free(eff0.priv);
203 return SOX_EOF;
207 ++chain->length;
208 free(eff0.priv);
209 return SOX_SUCCESS;
212 static int flow_effect(sox_effects_chain_t * chain, size_t n)
214 sox_effect_t * effp1 = &chain->effects[n - 1][0];
215 sox_effect_t * effp = &chain->effects[n][0];
216 int effstatus = SOX_SUCCESS, f = 0;
217 size_t i;
218 const sox_sample_t *ibuf;
219 size_t idone = effp1->oend - effp1->obeg;
220 size_t obeg = sox_globals.bufsiz - effp->oend;
221 #if DEBUG_EFFECTS_CHAIN
222 size_t pre_idone = idone;
223 size_t pre_odone = obeg;
224 #endif
226 if (effp->flows == 1) { /* Run effect on all channels at once */
227 idone -= idone % effp->in_signal.channels;
228 effstatus = effp->handler.flow(effp, &effp1->obuf[effp1->obeg],
229 &effp->obuf[effp->oend], &idone, &obeg);
230 if (obeg % effp->out_signal.channels != 0) {
231 lsx_fail("multi-channel effect flowed asymmetrically!");
232 effstatus = SOX_EOF;
234 } else { /* Run effect on each channel individually */
235 sox_sample_t *obuf = &effp->obuf[effp->oend];
236 size_t idone_last = 0, odone_last = 0; /* Initialised to prevent warning */
238 ibuf = &effp1->obuf[effp1->obeg];
239 for (i = 0; i < idone; i += effp->flows)
240 for (f = 0; f < (int)effp->flows; ++f)
241 chain->ibufc[f][i / effp->flows] = *ibuf++;
243 #ifdef HAVE_OPENMP
244 if (sox_globals.use_threads && effp->flows > 1)
246 #pragma omp parallel for
247 for (f = 0; f < (int)effp->flows; ++f) {
248 size_t idonec = idone / effp->flows;
249 size_t odonec = obeg / effp->flows;
250 int eff_status_c = effp->handler.flow(&chain->effects[n][f],
251 chain->ibufc[f], chain->obufc[f], &idonec, &odonec);
252 if (!f) {
253 idone_last = idonec;
254 odone_last = odonec;
257 if (eff_status_c != SOX_SUCCESS)
258 effstatus = SOX_EOF;
261 else /* sox_globals.use_threads */
262 #endif
264 for (f = 0; f < (int)effp->flows; ++f) {
265 size_t idonec = idone / effp->flows;
266 size_t odonec = obeg / effp->flows;
267 int eff_status_c = effp->handler.flow(&chain->effects[n][f],
268 chain->ibufc[f], chain->obufc[f], &idonec, &odonec);
269 if (f && (idonec != idone_last || odonec != odone_last)) {
270 lsx_fail("flowed asymmetrically!");
271 effstatus = SOX_EOF;
273 idone_last = idonec;
274 odone_last = odonec;
276 if (eff_status_c != SOX_SUCCESS)
277 effstatus = SOX_EOF;
281 for (i = 0; i < odone_last; ++i)
282 for (f = 0; f < (int)effp->flows; ++f)
283 *obuf++ = chain->obufc[f][i];
285 idone = effp->flows * idone_last;
286 obeg = effp->flows * odone_last;
288 #if DEBUG_EFFECTS_CHAIN
289 lsx_report("flow: %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR,
290 pre_idone, pre_odone, idone, obeg);
291 #endif
292 effp1->obeg += idone;
293 if (effp1->obeg == effp1->oend)
294 effp1->obeg = effp1->oend = 0;
295 else if (effp1->oend - effp1->obeg < effp->imin ) { /* Need to refill? */
296 memmove(effp1->obuf, &effp1->obuf[effp1->obeg], (effp1->oend - effp1->obeg) * sizeof(*effp1->obuf));
297 effp1->oend -= effp1->obeg;
298 effp1->obeg = 0;
301 effp->oend += obeg;
303 return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
306 /* The same as flow_effect but with no input */
307 static int drain_effect(sox_effects_chain_t * chain, size_t n)
309 sox_effect_t * effp = &chain->effects[n][0];
310 int effstatus = SOX_SUCCESS;
311 size_t i, f;
312 size_t obeg = sox_globals.bufsiz - effp->oend;
313 #if DEBUG_EFFECTS_CHAIN
314 size_t pre_odone = obeg;
315 #endif
317 if (effp->flows == 1) { /* Run effect on all channels at once */
318 effstatus = effp->handler.drain(effp, &effp->obuf[effp->oend], &obeg);
319 if (obeg % effp->out_signal.channels != 0) {
320 lsx_fail("multi-channel effect drained asymmetrically!");
321 effstatus = SOX_EOF;
323 } else { /* Run effect on each channel individually */
324 sox_sample_t *obuf = &effp->obuf[effp->oend];
325 size_t odone_last = 0; /* Initialised to prevent warning */
327 for (f = 0; f < effp->flows; ++f) {
328 size_t odonec = obeg / effp->flows;
329 int eff_status_c = effp->handler.drain(&chain->effects[n][f], chain->obufc[f], &odonec);
330 if (f && (odonec != odone_last)) {
331 lsx_fail("drained asymmetrically!");
332 effstatus = SOX_EOF;
334 odone_last = odonec;
336 if (eff_status_c != SOX_SUCCESS)
337 effstatus = SOX_EOF;
340 for (i = 0; i < odone_last; ++i)
341 for (f = 0; f < effp->flows; ++f)
342 *obuf++ = chain->obufc[f][i];
343 obeg = f * odone_last;
345 #if DEBUG_EFFECTS_CHAIN
346 lsx_report("drain: %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR,
347 (size_t)0, pre_odone, (size_t)0, obeg);
348 #endif
349 if (!obeg) /* This is the only thing that drain has and flow hasn't */
350 effstatus = SOX_EOF;
352 effp->oend += obeg;
354 return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
357 /* Flow data through the effects chain until an effect or callback gives EOF */
358 int sox_flow_effects(sox_effects_chain_t * chain, int (* callback)(sox_bool all_done, void * client_data), void * client_data)
360 int flow_status = SOX_SUCCESS;
361 size_t e, source_e = 0; /* effect indices */
362 size_t f, max_flows = 0;
363 sox_bool draining = sox_true;
365 for (e = 0; e < chain->length; ++e) {
366 chain->effects[e][0].obuf = lsx_realloc(chain->effects[e][0].obuf,
367 sox_globals.bufsiz * sizeof(chain->effects[e][0].obuf[0]));
368 /* Possibly there is already a buffer, if this is a used effect;
369 it may still contain samples in that case. */
370 /* Memory will be freed by sox_delete_effect() later. */
371 max_flows = max(max_flows, chain->effects[e][0].flows);
373 if (max_flows == 1) /* don't need interleave buffers */
374 max_flows = 0;
375 chain->ibufc = lsx_calloc(max_flows, sizeof(*chain->ibufc));
376 chain->obufc = lsx_calloc(max_flows, sizeof(*chain->obufc));
377 for (f = 0; f < max_flows; ++f) {
378 chain->ibufc[f] = lsx_calloc(sox_globals.bufsiz / 2, sizeof(chain->ibufc[f][0]));
379 chain->obufc[f] = lsx_calloc(sox_globals.bufsiz / 2, sizeof(chain->obufc[f][0]));
382 e = chain->length - 1;
383 while (source_e < chain->length) {
384 #define have_imin (e > 0 && e < chain->length && chain->effects[e - 1][0].oend - chain->effects[e - 1][0].obeg >= chain->effects[e][0].imin)
385 size_t osize = chain->effects[e][0].oend - chain->effects[e][0].obeg;
386 if (e == source_e && (draining || !have_imin)) {
387 if (drain_effect(chain, e) == SOX_EOF) {
388 ++source_e;
389 draining = sox_false;
391 } else if (have_imin && flow_effect(chain, e) == SOX_EOF) {
392 flow_status = SOX_EOF;
393 if (e == chain->length - 1)
394 break;
395 source_e = e;
396 draining = sox_true;
398 if (e < chain->length && chain->effects[e][0].oend - chain->effects[e][0].obeg > osize) /* False for output */
399 ++e;
400 else if (e == source_e)
401 draining = sox_true;
402 else if ((int)--e < (int)source_e)
403 e = source_e;
405 if (callback && callback(source_e == chain->length, client_data) != SOX_SUCCESS) {
406 flow_status = SOX_EOF; /* Client has requested to stop the flow. */
407 break;
411 for (f = 0; f < max_flows; ++f) {
412 free(chain->ibufc[f]);
413 free(chain->obufc[f]);
415 free(chain->obufc);
416 free(chain->ibufc);
418 return flow_status;
421 sox_uint64_t sox_effects_clips(sox_effects_chain_t * chain)
423 unsigned i, f;
424 uint64_t clips = 0;
425 for (i = 1; i < chain->length - 1; ++i)
426 for (f = 0; f < chain->effects[i][0].flows; ++f)
427 clips += chain->effects[i][f].clips;
428 return clips;
431 sox_uint64_t sox_stop_effect(sox_effect_t *effp)
433 unsigned f;
434 uint64_t clips = 0;
436 for (f = 0; f < effp->flows; ++f) {
437 effp[f].handler.stop(&effp[f]);
438 clips += effp[f].clips;
440 return clips;
443 void sox_push_effect_last(sox_effects_chain_t *chain, sox_effect_t *effp)
445 if (chain->length == chain->table_size) {
446 chain->table_size += EFF_TABLE_STEP;
447 lsx_debug_more("sox_push_effect_last: extending effects table, "
448 "new size = %lu", (unsigned long)chain->table_size);
449 lsx_revalloc(chain->effects, chain->table_size);
452 chain->effects[chain->length++] = effp;
453 } /* sox_push_effect_last */
455 sox_effect_t *sox_pop_effect_last(sox_effects_chain_t *chain)
457 if (chain->length > 0)
459 sox_effect_t *effp;
460 chain->length--;
461 effp = chain->effects[chain->length];
462 chain->effects[chain->length] = NULL;
463 return effp;
465 else
466 return NULL;
467 } /* sox_pop_effect_last */
469 /* Free resources related to effect.
470 * Note: This currently closes down the effect which might
471 * not be obvious from name.
473 void sox_delete_effect(sox_effect_t *effp)
475 uint64_t clips;
476 unsigned f;
478 if ((clips = sox_stop_effect(effp)) != 0)
479 lsx_warn("%s clipped %" PRIu64 " samples; decrease volume?",
480 effp->handler.name, clips);
481 if (effp->obeg != effp->oend)
482 lsx_debug("output buffer still held %" PRIuPTR " samples; dropped.",
483 (effp->oend - effp->obeg)/effp->out_signal.channels);
484 /* May or may not indicate a problem; it is normal if the user aborted
485 processing, or if an effect like "trim" stopped early. */
486 effp->handler.kill(effp); /* N.B. only one kill; not one per flow */
487 for (f = 0; f < effp->flows; ++f)
488 free(effp[f].priv);
489 free(effp->obuf);
490 free(effp);
493 void sox_delete_effect_last(sox_effects_chain_t *chain)
495 if (chain->length > 0)
497 chain->length--;
498 sox_delete_effect(chain->effects[chain->length]);
499 chain->effects[chain->length] = NULL;
501 } /* sox_delete_effect_last */
503 /* Remove all effects from the chain.
504 * Note: This currently closes down the effect which might
505 * not be obvious from name.
507 void sox_delete_effects(sox_effects_chain_t * chain)
509 size_t e;
511 for (e = 0; e < chain->length; ++e) {
512 sox_delete_effect(chain->effects[e]);
513 chain->effects[e] = NULL;
515 chain->length = 0;
518 /*----------------------------- Effects library ------------------------------*/
520 static sox_effect_fn_t s_sox_effect_fns[] = {
521 #define EFFECT(f) lsx_##f##_effect_fn,
522 #include "effects.h"
523 #undef EFFECT
524 NULL
527 const sox_effect_fn_t*
528 sox_get_effect_fns(void)
530 return s_sox_effect_fns;
533 /* Find a named effect in the effects library */
534 sox_effect_handler_t const * sox_find_effect(char const * name)
536 int e;
537 sox_effect_fn_t const * fns = sox_get_effect_fns();
538 for (e = 0; fns[e]; ++e) {
539 const sox_effect_handler_t *eh = fns[e] ();
540 if (eh && eh->name && strcasecmp(eh->name, name) == 0)
541 return eh; /* Found it. */
543 return NULL;