ref: 7d7087645e49a02c8cd3b3a45ab1d71451e26284
parent: a823e49837cabf1f3a21ec94c076cd4bfeda6697
author: Ulrich Klauer <ulrich@chirlu.de>
date: Mon Jan 23 03:31:36 EST 2012
Don't drop samples at effects chain transitions When using multiple/restarted effects chains, at each transition to or restart of an effects chain, a number of samples would be lost, even if the effect causing the transition was the first in its chain (as recommended in the man page). The exact number of affected samples would depend on buffer size, number of channels, flow behaviour of the effects/handlers involved etc. and was thus unpredictable. To correct this problem, this commit modifies sox_flow_effects() to not free effects' output buffers at the end of processing (this is left to sox_delete_effect() instead). Since the input combiner effect is reused in the new effects chain, this allows samples already processed by the combiner to remain in its buffer and be flowed down the new effects chain later. This should, a.o., make sure that after sox infile splitfiles trim 0 1:00 : newfile : restart sox splitfiles* recombined "infile" and "recombined" are identical (provided the encoding is lossless, of course). (Note that samples buffered by "normal" effects, i.e. those that are not reused, to the left of the effect terminating the chain will still be dropped. E.g., with sox infile outfile highpass 40 trim 0 10 : a number of samples already processed by the highpass effect but not consumed by trim will be lost. This behaviour is already documented in the man page.)
--- a/ChangeLog
+++ b/ChangeLog
@@ -88,6 +88,8 @@
o Complete rewrite of the trim effect with extended syntax (backwards
compatible) and capabilities. [FR 2941349] (Ulrich Klauer)
o Fix trim optimization unexpectedly seeking backwards. (Ulrich Klauer)
+ o Prevent samples from getting lost at effects chain transitions in
+ multiple effects chain/multiple output modes. (Ulrich Klauer)
Misc:
--- a/src/effects.c
+++ b/src/effects.c
@@ -58,6 +58,7 @@
sox_effect_t * sox_create_effect(sox_effect_handler_t const * eh)
{
sox_effect_t * effp = lsx_calloc(1, sizeof(*effp));
+ effp->obuf = NULL;
effp->global_info = sox_get_effects_globals();
effp->handler = *eh;
@@ -362,8 +363,11 @@
sox_bool draining = sox_true;
for (e = 0; e < chain->length; ++e) {
- chain->effects[e][0].obuf = lsx_malloc(sox_globals.bufsiz * sizeof(chain->effects[e][0].obuf[0]));
- chain->effects[e][0].obeg = chain->effects[e][0].oend = 0;
+ chain->effects[e][0].obuf = lsx_realloc(chain->effects[e][0].obuf,
+ sox_globals.bufsiz * sizeof(chain->effects[e][0].obuf[0]));
+ /* Possibly there is already a buffer, if this is a used effect;
+ it may still contain samples in that case. */
+ /* Memory will be freed by sox_delete_effect() later. */
max_flows = max(max_flows, chain->effects[e][0].flows);
}
@@ -410,9 +414,6 @@
free(chain->obufc);
free(chain->ibufc);
- for (e = 0; e < chain->length; ++e)
- free(chain->effects[e][0].obuf);
-
return flow_status;
}
@@ -476,9 +477,15 @@
if ((clips = sox_stop_effect(effp)) != 0)
lsx_warn("%s clipped %" PRIu64 " samples; decrease volume?",
effp->handler.name, clips);
+ if (effp->obeg != effp->oend)
+ lsx_debug("output buffer still held %" PRIu64 " samples; dropped.",
+ (effp->oend - effp->obeg)/effp->out_signal.channels);
+ /* May or may not indicate a problem; it is normal if the user aborted
+ processing, or if an effect like "trim" stopped early. */
effp->handler.kill(effp); /* N.B. only one kill; not one per flow */
for (f = 0; f < effp->flows; ++f)
free(effp[f].priv);
+ free(effp->obuf);
free(effp);
}
--- a/src/sox.c
+++ b/src/sox.c
@@ -1169,13 +1169,8 @@
if (reuse_output)
save_output_eff = sox_pop_effect_last(effects_chain);
- /* TODO: Warn user when an effect is deleted that still
- * had unprocessed samples.
- */
while (effects_chain->length > 1)
- {
sox_delete_effect_last(effects_chain);
- }
}
return SOX_SUCCESS;
} /* advance_eff_chain */