1 /* SoX Effects chain     (c) 2007 robs@users.sourceforge.net
2  *
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.
7  *
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.
12  *
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
16  */
17 
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
25 
26 #define DEBUG_EFFECTS_CHAIN 0
27 
28 /* Default effect handler functions for do-nothing situations: */
29 
default_function(sox_effect_t * effp UNUSED)30 static int default_function(sox_effect_t * effp UNUSED)
31 {
32   return SOX_SUCCESS;
33 }
34 
35 /* Pass through samples verbatim */
lsx_flow_copy(sox_effect_t * effp UNUSED,const sox_sample_t * ibuf,sox_sample_t * obuf,size_t * isamp,size_t * osamp)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)
38 {
39   *isamp = *osamp = min(*isamp, *osamp);
40   memcpy(obuf, ibuf, *isamp * sizeof(*obuf));
41   return SOX_SUCCESS;
42 }
43 
44 /* Inform no more samples to drain */
default_drain(sox_effect_t * effp UNUSED,sox_sample_t * obuf UNUSED,size_t * osamp)45 static int default_drain(sox_effect_t * effp UNUSED, sox_sample_t *obuf UNUSED, size_t *osamp)
46 {
47   *osamp = 0;
48   return SOX_EOF;
49 }
50 
51 /* Check that no parameters have been given */
default_getopts(sox_effect_t * effp,int argc,char ** argv UNUSED)52 static int default_getopts(sox_effect_t * effp, int argc, char **argv UNUSED)
53 {
54   return --argc? lsx_usage(effp) : SOX_SUCCESS;
55 }
56 
57 /* Partially initialise the effect structure; signal info will come later */
sox_create_effect(sox_effect_handler_t const * eh)58 sox_effect_t * sox_create_effect(sox_effect_handler_t const * eh)
59 {
60   sox_effect_t * effp = lsx_calloc(1, sizeof(*effp));
61   effp->obuf = NULL;
62 
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;
71 
72   effp->priv = lsx_calloc(1, effp->handler.priv_size);
73 
74   return effp;
75 } /* sox_create_effect */
76 
sox_effect_options(sox_effect_t * effp,int argc,char * const argv[])77 int sox_effect_options(sox_effect_t *effp, int argc, char * const argv[])
78 {
79   int result;
80 
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 */
88 
89 /* Effects chain: */
90 
sox_create_effects_chain(sox_encodinginfo_t const * in_enc,sox_encodinginfo_t const * out_enc)91 sox_effects_chain_t * sox_create_effects_chain(
92     sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc)
93 {
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 */
100 
sox_delete_effects_chain(sox_effects_chain_t * ecp)101 void sox_delete_effects_chain(sox_effects_chain_t *ecp)
102 {
103     if (ecp && ecp->length)
104         sox_delete_effects(ecp);
105     free(ecp->effects);
106     free(ecp);
107 } /* sox_delete_effects_chain */
108 
109 /* Effect can call in start() or flow() to set minimum input size to flow() */
lsx_effect_set_imin(sox_effect_t * effp,size_t imin)110 int lsx_effect_set_imin(sox_effect_t * effp, size_t imin)
111 {
112   if (imin > sox_globals.bufsiz / effp->flows) {
113     lsx_fail("sox_bufsiz not big enough");
114     return SOX_EOF;
115   }
116 
117   effp->imin = imin;
118   return SOX_SUCCESS;
119 }
120 
121 /* Effects table to be extended in steps of EFF_TABLE_STEP */
122 #define EFF_TABLE_STEP 8
123 
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.
129  */
sox_add_effect(sox_effects_chain_t * chain,sox_effect_t * effp,sox_signalinfo_t * in,sox_signalinfo_t const * out)130 int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out)
131 {
132   int ret, (*start)(sox_effect_t * effp) = effp->handler.start;
133   size_t f;
134   sox_effect_t eff0;  /* Copy of effect for flow 0 before calling start */
135 
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;
150 
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     effp->handler.kill(effp);
162     free(effp->priv);
163     effp->priv = NULL;
164     return SOX_SUCCESS;
165   }
166   if (ret != SOX_SUCCESS) {
167     free(eff0.priv);
168     return SOX_EOF;
169   }
170   if (in->mult)
171     lsx_debug("mult=%g", *in->mult);
172 
173   if (!(effp->handler.flags & SOX_EFF_LENGTH)) {
174     effp->out_signal.length = in->length;
175     if (effp->out_signal.length != SOX_UNKNOWN_LEN) {
176       if (effp->handler.flags & SOX_EFF_CHAN)
177         effp->out_signal.length =
178           effp->out_signal.length / in->channels * effp->out_signal.channels;
179       if (effp->handler.flags & SOX_EFF_RATE)
180         effp->out_signal.length =
181           effp->out_signal.length / in->rate * effp->out_signal.rate + .5;
182     }
183   }
184 
185   *in = effp->out_signal;
186 
187   if (chain->length == chain->table_size) {
188     chain->table_size += EFF_TABLE_STEP;
189     lsx_debug_more("sox_add_effect: extending effects table, "
190       "new size = %" PRIuPTR, chain->table_size);
191     lsx_revalloc(chain->effects, chain->table_size);
192   }
193 
194   chain->effects[chain->length] =
195     lsx_calloc(effp->flows, sizeof(chain->effects[chain->length][0]));
196   chain->effects[chain->length][0] = *effp;
197 
198   for (f = 1; f < effp->flows; ++f) {
199     chain->effects[chain->length][f] = eff0;
200     chain->effects[chain->length][f].flow = f;
201     chain->effects[chain->length][f].priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
202     if (start(&chain->effects[chain->length][f]) != SOX_SUCCESS) {
203       free(eff0.priv);
204       return SOX_EOF;
205     }
206   }
207 
208   ++chain->length;
209   free(eff0.priv);
210   return SOX_SUCCESS;
211 }
212 
213 /* An effect's output buffer (effp->obuf) generally has this layout:
214  *   |. . . A1A2A3B1B2B3C1C2C3. . . . . . . . . . . . . . . . . . |
215  *    ^0    ^obeg             ^oend                               ^bufsiz
216  * (where A1 is the first sample of channel 1, A2 the first sample of
217  * channel 2, etc.), i.e. the channels are interleaved.
218  * However, while sox_flow_effects() is running, output buffers are
219  * adapted to how the following effect expects its input, to avoid
220  * back-and-forth conversions.  If the following effect operates on
221  * each of several channels separately (flows > 1), the layout is
222  * changed to this uninterleaved form:
223  *   |. A1B1C1. . . . . . . A2B2C2. . . . . . . A3B3C3. . . . . . |
224  *    ^0    ^obeg             ^oend                               ^bufsiz
225  *    <--- channel 1 ----><--- channel 2 ----><--- channel 3 ---->
226  * The buffer is logically subdivided into channel buffers of size
227  * bufsiz/flows each, starting at offsets 0, bufsiz/flows,
228  * 2*(bufsiz/flows) etc.  Within the channel buffers, the data starts
229  * at position obeg/flows and ends before oend/flows.  In case bufsiz
230  * is not evenly divisible by flows, there will be an unused area at
231  * the very end of the output buffer.
232  * The interleave() and deinterleave() functions convert between these
233  * two representations.
234  */
235 static void interleave(size_t flows, size_t length, sox_sample_t *from,
236     size_t bufsiz, size_t offset, sox_sample_t *to);
237 static void deinterleave(size_t flows, size_t length, sox_sample_t *from,
238     sox_sample_t *to, size_t bufsiz, size_t offset);
239 
flow_effect(sox_effects_chain_t * chain,size_t n)240 static int flow_effect(sox_effects_chain_t * chain, size_t n)
241 {
242   sox_effect_t *effp1 = chain->effects[n - 1];
243   sox_effect_t *effp = chain->effects[n];
244   int effstatus = SOX_SUCCESS;
245   size_t f = 0;
246   size_t idone = effp1->oend - effp1->obeg;
247   size_t obeg = sox_globals.bufsiz - effp->oend;
248   sox_bool il_change = (effp->flows == 1) !=
249       (chain->length == n + 1 || chain->effects[n+1]->flows == 1);
250 #if DEBUG_EFFECTS_CHAIN
251   size_t pre_idone = idone;
252   size_t pre_odone = obeg;
253 #endif
254 
255   if (effp->flows == 1) {     /* Run effect on all channels at once */
256     idone -= idone % effp->in_signal.channels;
257     effstatus = effp->handler.flow(effp, effp1->obuf + effp1->obeg,
258                     il_change ? chain->il_buf : effp->obuf + effp->oend,
259                     &idone, &obeg);
260     if (obeg % effp->out_signal.channels != 0) {
261       lsx_fail("multi-channel effect flowed asymmetrically!");
262       effstatus = SOX_EOF;
263     }
264     if (il_change)
265       deinterleave(chain->effects[n+1]->flows, obeg, chain->il_buf,
266           effp->obuf, sox_globals.bufsiz, effp->oend);
267   } else {               /* Run effect on each channel individually */
268     sox_sample_t *obuf = il_change ? chain->il_buf : effp->obuf;
269     size_t flow_offs = sox_globals.bufsiz/effp->flows;
270     size_t idone_min = SOX_SIZE_MAX, idone_max = 0;
271     size_t odone_min = SOX_SIZE_MAX, odone_max = 0;
272 
273 #ifdef HAVE_OPENMP_3_1
274     #pragma omp parallel for \
275         if(sox_globals.use_threads) \
276         schedule(static) default(none) \
277         shared(effp,effp1,idone,obeg,obuf,flow_offs,chain,n,effstatus) \
278         reduction(min:idone_min,odone_min) reduction(max:idone_max,odone_max)
279 #elif defined HAVE_OPENMP
280     #pragma omp parallel for \
281         if(sox_globals.use_threads) \
282         schedule(static) default(none) \
283         shared(effp,effp1,idone,obeg,obuf,flow_offs,chain,n,effstatus) \
284         firstprivate(idone_min,odone_min,idone_max,odone_max) \
285         lastprivate(idone_min,odone_min,idone_max,odone_max)
286 #endif
287     for (f = 0; f < effp->flows; ++f) {
288       size_t idonec = idone / effp->flows;
289       size_t odonec = obeg / effp->flows;
290       int eff_status_c = effp->handler.flow(&chain->effects[n][f],
291           effp1->obuf + f*flow_offs + effp1->obeg/effp->flows,
292           obuf + f*flow_offs + effp->oend/effp->flows,
293           &idonec, &odonec);
294       idone_min = min(idonec, idone_min); idone_max = max(idonec, idone_max);
295       odone_min = min(odonec, odone_min); odone_max = max(odonec, odone_max);
296 
297       if (eff_status_c != SOX_SUCCESS)
298         effstatus = SOX_EOF;
299     }
300 
301     if (idone_min != idone_max || odone_min != odone_max) {
302       lsx_fail("flowed asymmetrically!");
303       effstatus = SOX_EOF;
304     }
305     idone = effp->flows * idone_max;
306     obeg = effp->flows * odone_max;
307 
308     if (il_change)
309       interleave(effp->flows, obeg, chain->il_buf, sox_globals.bufsiz,
310           effp->oend, effp->obuf + effp->oend);
311   }
312   effp1->obeg += idone;
313   if (effp1->obeg == effp1->oend)
314     effp1->obeg = effp1->oend = 0;
315   else if (effp1->oend - effp1->obeg < effp->imin) { /* Need to refill? */
316     size_t flow_offs = sox_globals.bufsiz/effp->flows;
317     for (f = 0; f < effp->flows; ++f)
318       memcpy(effp1->obuf + f * flow_offs,
319           effp1->obuf + f * flow_offs + effp1->obeg/effp->flows,
320           (effp1->oend - effp1->obeg)/effp->flows * sizeof(*effp1->obuf));
321     effp1->oend -= effp1->obeg;
322     effp1->obeg = 0;
323   }
324 
325   effp->oend += obeg;
326 
327 #if DEBUG_EFFECTS_CHAIN
328   lsx_report("\t" "flow:  %2" PRIuPTR " (%1" PRIuPTR ")  "
329       "%5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR "  "
330       "%5" PRIuPTR " [%" PRIuPTR "-%" PRIuPTR "]",
331       n, effp->flows, pre_idone, pre_odone, idone, obeg,
332       effp1->oend - effp1->obeg, effp1->obeg, effp1->oend);
333 #endif
334 
335   return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
336 }
337 
338 /* The same as flow_effect but with no input */
drain_effect(sox_effects_chain_t * chain,size_t n)339 static int drain_effect(sox_effects_chain_t * chain, size_t n)
340 {
341   sox_effect_t *effp = chain->effects[n];
342   int effstatus = SOX_SUCCESS;
343   size_t f = 0;
344   size_t obeg = sox_globals.bufsiz - effp->oend;
345   sox_bool il_change = (effp->flows == 1) !=
346       (chain->length == n + 1 || chain->effects[n+1]->flows == 1);
347 #if DEBUG_EFFECTS_CHAIN
348   size_t pre_odone = obeg;
349 #endif
350 
351   if (effp->flows == 1) { /* Run effect on all channels at once */
352     effstatus = effp->handler.drain(effp,
353                     il_change ? chain->il_buf : effp->obuf + effp->oend,
354                     &obeg);
355     if (obeg % effp->out_signal.channels != 0) {
356       lsx_fail("multi-channel effect drained asymmetrically!");
357       effstatus = SOX_EOF;
358     }
359     if (il_change)
360       deinterleave(chain->effects[n+1]->flows, obeg, chain->il_buf,
361           effp->obuf, sox_globals.bufsiz, effp->oend);
362   } else {                       /* Run effect on each channel individually */
363     sox_sample_t *obuf = il_change ? chain->il_buf : effp->obuf;
364     size_t flow_offs = sox_globals.bufsiz/effp->flows;
365     size_t odone_last = 0; /* Initialised to prevent warning */
366 
367     for (f = 0; f < effp->flows; ++f) {
368       size_t odonec = obeg / effp->flows;
369       int eff_status_c = effp->handler.drain(&chain->effects[n][f],
370           obuf + f*flow_offs + effp->oend/effp->flows,
371           &odonec);
372       if (f && (odonec != odone_last)) {
373         lsx_fail("drained asymmetrically!");
374         effstatus = SOX_EOF;
375       }
376       odone_last = odonec;
377 
378       if (eff_status_c != SOX_SUCCESS)
379         effstatus = SOX_EOF;
380     }
381 
382     obeg = effp->flows * odone_last;
383 
384     if (il_change)
385       interleave(effp->flows, obeg, chain->il_buf, sox_globals.bufsiz,
386           effp->oend, effp->obuf + effp->oend);
387   }
388   if (!obeg)   /* This is the only thing that drain has and flow hasn't */
389     effstatus = SOX_EOF;
390 
391   effp->oend += obeg;
392 
393 #if DEBUG_EFFECTS_CHAIN
394   lsx_report("\t" "drain: %2" PRIuPTR " (%1" PRIuPTR ")  "
395       "%5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR,
396       n, effp->flows, (size_t)0, pre_odone, (size_t)0, obeg);
397 #endif
398 
399   return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
400 }
401 
402 /* Flow data through the effects chain until an effect or callback gives EOF */
sox_flow_effects(sox_effects_chain_t * chain,int (* callback)(sox_bool all_done,void * client_data),void * client_data)403 int sox_flow_effects(sox_effects_chain_t * chain, int (* callback)(sox_bool all_done, void * client_data), void * client_data)
404 {
405   int flow_status = SOX_SUCCESS;
406   size_t e, source_e = 0;               /* effect indices */
407   size_t max_flows = 0;
408   sox_bool draining = sox_true;
409 
410   for (e = 0; e < chain->length; ++e) {
411     sox_effect_t *effp = chain->effects[e];
412     effp->obuf =
413         lsx_realloc(effp->obuf, sox_globals.bufsiz * sizeof(*effp->obuf));
414       /* Memory will be freed by sox_delete_effect() later. */
415       /* Possibly there was already a buffer, if this is a used effect;
416          it may still contain samples in that case. */
417       if (effp->oend > sox_globals.bufsiz) {
418         lsx_warn("buffer size insufficient; buffered samples were dropped");
419         /* can only happen if bufsize has been reduced since the last run */
420         effp->obeg = effp->oend = 0;
421       }
422     max_flows = max(max_flows, effp->flows);
423   }
424   if (max_flows > 1) /* might need interleave buffer */
425     chain->il_buf = lsx_malloc(sox_globals.bufsiz * sizeof(sox_sample_t));
426   else
427     chain->il_buf = NULL;
428 
429   /* Go through the effects, and if there are samples in one of the
430      buffers, deinterleave it (if necessary).  */
431   for (e = 0; e + 1 < chain->length; e++) {
432     sox_effect_t *effp = chain->effects[e];
433     if (effp->oend > effp->obeg && chain->effects[e+1]->flows > 1) {
434       sox_sample_t *sw = chain->il_buf; chain->il_buf = effp->obuf; effp->obuf = sw;
435       deinterleave(chain->effects[e+1]->flows, effp->oend - effp->obeg,
436           chain->il_buf, effp->obuf, sox_globals.bufsiz, effp->obeg);
437     }
438   }
439 
440   e = chain->length - 1;
441   while (source_e < chain->length) {
442 #define have_imin (e > 0 && e < chain->length && chain->effects[e - 1]->oend - chain->effects[e - 1]->obeg >= chain->effects[e]->imin)
443     size_t osize = chain->effects[e]->oend - chain->effects[e]->obeg;
444     if (e == source_e && (draining || !have_imin)) {
445       if (drain_effect(chain, e) == SOX_EOF) {
446         ++source_e;
447         draining = sox_false;
448       }
449     } else if (have_imin && flow_effect(chain, e) == SOX_EOF) {
450       flow_status = SOX_EOF;
451       if (e == chain->length - 1)
452         break;
453       source_e = e;
454       draining = sox_true;
455     }
456     if (e < chain->length && chain->effects[e]->oend - chain->effects[e]->obeg > osize) /* False for output */
457       ++e;
458     else if (e == source_e)
459       draining = sox_true;
460     else if (e < source_e)
461       e = source_e;
462     else
463       --e;
464 
465     if (callback && callback(source_e == chain->length, client_data) != SOX_SUCCESS) {
466       flow_status = SOX_EOF; /* Client has requested to stop the flow. */
467       break;
468     }
469   }
470 
471   /* If an effect's output buffer still has samples, and if it is
472      uninterleaved, then re-interleave it. Necessary since it might
473      be reused, and at that time possibly followed by an MCHAN effect. */
474   for (e = 0; e + 1 < chain->length; e++) {
475     sox_effect_t *effp = chain->effects[e];
476     if (effp->oend > effp->obeg && chain->effects[e+1]->flows > 1) {
477       sox_sample_t *sw = chain->il_buf; chain->il_buf = effp->obuf; effp->obuf = sw;
478       interleave(chain->effects[e+1]->flows, effp->oend - effp->obeg,
479           chain->il_buf, sox_globals.bufsiz, effp->obeg, effp->obuf);
480     }
481   }
482 
483   free(chain->il_buf);
484   return flow_status;
485 }
486 
sox_effects_clips(sox_effects_chain_t * chain)487 sox_uint64_t sox_effects_clips(sox_effects_chain_t * chain)
488 {
489   size_t i, f;
490   uint64_t clips = 0;
491   for (i = 1; i < chain->length - 1; ++i)
492     for (f = 0; f < chain->effects[i][0].flows; ++f)
493       clips += chain->effects[i][f].clips;
494   return clips;
495 }
496 
sox_stop_effect(sox_effect_t * effp)497 sox_uint64_t sox_stop_effect(sox_effect_t *effp)
498 {
499   size_t f;
500   uint64_t clips = 0;
501 
502   for (f = 0; f < effp->flows; ++f) {
503     effp[f].handler.stop(&effp[f]);
504     clips += effp[f].clips;
505   }
506   return clips;
507 }
508 
sox_push_effect_last(sox_effects_chain_t * chain,sox_effect_t * effp)509 void sox_push_effect_last(sox_effects_chain_t *chain, sox_effect_t *effp)
510 {
511   if (chain->length == chain->table_size) {
512     chain->table_size += EFF_TABLE_STEP;
513     lsx_debug_more("sox_push_effect_last: extending effects table, "
514         "new size = %" PRIuPTR, chain->table_size);
515     lsx_revalloc(chain->effects, chain->table_size);
516   }
517 
518   chain->effects[chain->length++] = effp;
519 } /* sox_push_effect_last */
520 
sox_pop_effect_last(sox_effects_chain_t * chain)521 sox_effect_t *sox_pop_effect_last(sox_effects_chain_t *chain)
522 {
523   if (chain->length > 0)
524   {
525     sox_effect_t *effp;
526     chain->length--;
527     effp = chain->effects[chain->length];
528     chain->effects[chain->length] = NULL;
529     return effp;
530   }
531   else
532     return NULL;
533 } /* sox_pop_effect_last */
534 
535 /* Free resources related to effect.
536  * Note: This currently closes down the effect which might
537  * not be obvious from name.
538  */
sox_delete_effect(sox_effect_t * effp)539 void sox_delete_effect(sox_effect_t *effp)
540 {
541   uint64_t clips;
542   size_t f;
543 
544   if ((clips = sox_stop_effect(effp)) != 0)
545     lsx_warn("%s clipped %" PRIu64 " samples; decrease volume?",
546         effp->handler.name, clips);
547   if (effp->obeg != effp->oend)
548     lsx_debug("output buffer still held %" PRIuPTR " samples; dropped.",
549         (effp->oend - effp->obeg)/effp->out_signal.channels);
550       /* May or may not indicate a problem; it is normal if the user aborted
551          processing, or if an effect like "trim" stopped early. */
552   effp->handler.kill(effp); /* N.B. only one kill; not one per flow */
553   for (f = 0; f < effp->flows; ++f)
554     free(effp[f].priv);
555   free(effp->obuf);
556   free(effp);
557 }
558 
sox_delete_effect_last(sox_effects_chain_t * chain)559 void sox_delete_effect_last(sox_effects_chain_t *chain)
560 {
561   if (chain->length > 0)
562   {
563     chain->length--;
564     sox_delete_effect(chain->effects[chain->length]);
565     chain->effects[chain->length] = NULL;
566   }
567 } /* sox_delete_effect_last */
568 
569 /* Remove all effects from the chain.
570  * Note: This currently closes down the effect which might
571  * not be obvious from name.
572  */
sox_delete_effects(sox_effects_chain_t * chain)573 void sox_delete_effects(sox_effects_chain_t * chain)
574 {
575   size_t e;
576 
577   for (e = 0; e < chain->length; ++e) {
578     sox_delete_effect(chain->effects[e]);
579     chain->effects[e] = NULL;
580   }
581   chain->length = 0;
582 }
583 
584 /*----------------------------- Effects library ------------------------------*/
585 
586 static sox_effect_fn_t s_sox_effect_fns[] = {
587 #define EFFECT(f) lsx_##f##_effect_fn,
588 #include "effects.h"
589 #undef EFFECT
590   NULL
591 };
592 
593 const sox_effect_fn_t*
sox_get_effect_fns(void)594 sox_get_effect_fns(void)
595 {
596     return s_sox_effect_fns;
597 }
598 
599 /* Find a named effect in the effects library */
sox_find_effect(char const * name)600 sox_effect_handler_t const * sox_find_effect(char const * name)
601 {
602   int e;
603   sox_effect_fn_t const * fns = sox_get_effect_fns();
604   for (e = 0; fns[e]; ++e) {
605     const sox_effect_handler_t *eh = fns[e] ();
606     if (eh && eh->name && strcasecmp(eh->name, name) == 0)
607       return eh;                 /* Found it. */
608   }
609   return NULL;
610 }
611 
612 
613 /*----------------------------- Helper functions -----------------------------*/
614 
615 /* interleave() parameters:
616  *   flows: number of samples per wide sample
617  *   length: number of samples to copy
618  *     [pertaining to the (non-interleaved) source buffer:]
619  *   from: start address
620  *   bufsiz: total size
621  *   offset: position at which to start reading
622  *     [pertaining to the (interleaved) destination buffer:]
623  *   to: start address
624  */
interleave(size_t flows,size_t length,sox_sample_t * from,size_t bufsiz,size_t offset,sox_sample_t * to)625 static void interleave(size_t flows, size_t length, sox_sample_t *from,
626     size_t bufsiz, size_t offset, sox_sample_t *to)
627 {
628   size_t i;
629   const size_t wide_samples = length/flows;
630   const size_t flow_offs = bufsiz/flows;
631   from += offset/flows;
632   for (i = 0; i < wide_samples; i++) {
633     sox_sample_t *inner_from = from + i;
634     sox_sample_t *inner_to = to + i * flows;
635     size_t f;
636     for (f = 0; f < flows; f++) {
637       *inner_to++ = *inner_from;
638       inner_from += flow_offs;
639     }
640   }
641 }
642 
643 /* deinterleave() parameters:
644  *   flows: number of samples per wide sample
645  *   length: number of samples to copy
646  *     [pertaining to the (interleaved) source buffer:]
647  *   from: start address
648  *     [pertaining to the (non-interleaved) destination buffer:]
649  *   to: start address
650  *   bufsiz: total size
651  *   offset: position at which to start writing
652  */
deinterleave(size_t flows,size_t length,sox_sample_t * from,sox_sample_t * to,size_t bufsiz,size_t offset)653 static void deinterleave(size_t flows, size_t length, sox_sample_t *from,
654     sox_sample_t *to, size_t bufsiz, size_t offset)
655 {
656   const size_t wide_samples = length/flows;
657   const size_t flow_offs = bufsiz/flows;
658   size_t f;
659   to += offset/flows;
660   for (f = 0; f < flows; f++) {
661     sox_sample_t *inner_to = to + f*flow_offs;
662     sox_sample_t *inner_from = from + f;
663     size_t i = wide_samples;
664     while (i--) {
665       *inner_to++ = *inner_from;
666       inner_from += flows;
667     }
668   }
669 }
670