ref: a2cf03b1cefb3d62e7da22caddf969a29005efe4
parent: 9f37c16370f1d2c856be3820dd69a8387ad99bef
author: cbagwell <cbagwell>
date: Sat Sep 10 16:49:53 EDT 2005
Fix bug running -c and -r together would drop audio data making shorter files that skipped.
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,12 @@
incorrectly computed based on bytes and not samples. Jukka
o Changed noisered effect to just warn during clipping instead
of aborting. Ian Turner
+ o Fixed bug were pieces of audio were lost every buffer read
+ when running both -c and -r options together on mono audio.
+ Users probably percieved it as shorter audio files that
+ played with a sped up tempo.
+ Bugfix will also apply to other times when multiple effects
+ are ran on the command line.
sox-12.17.8
-----------
--- a/src/resample.c
+++ b/src/resample.c
@@ -383,7 +383,7 @@
st_sample_t *Obuf;
int rc;
- /* fprintf(stderr,"Xoff %d, Xt %d <--- DRAIN\n",r->Xoff, r->Xt); */
+ /* fprintf(stderr,"Xoff %d <--- DRAIN\n",r->Xoff); */
/* stuff end with Xoff zeros */
isamp_res = r->Xoff;
@@ -396,8 +396,8 @@
rc = st_resample_flow(effp, NULL, Obuf, (st_size_t *)&Isamp, (st_size_t *)&Osamp);
if (rc)
return rc;
- /* fprintf(stderr,"DRAIN isamp,osamp (%d,%d) -> (%d,%d)\n",
- isamp_res,osamp_res,Isamp,Osamp); */
+ /* fprintf(stderr,"DRAIN isamp,osamp (%d,%d) -> (%d,%d)\n",
+ isamp_res,osamp_res,Isamp,Osamp); */
Obuf += Osamp;
osamp_res -= Osamp;
isamp_res -= Isamp;
@@ -406,7 +406,7 @@
/* fprintf(stderr,"DRAIN osamp %d\n", *osamp); */
if (isamp_res)
st_warn("drain overran obuf by %d\n", isamp_res); fflush(stderr);
- return (ST_SUCCESS);
+ return (ST_EOF);
}
/*
--- a/src/sox.c
+++ b/src/sox.c
@@ -102,6 +102,7 @@
static void checkeffect(void);
static int flow_effect_out(void);
static int flow_effect(int);
+static int drain_effect_out(void);
static int drain_effect(int);
#define MAX_INPUT_FILES 32
@@ -143,6 +144,7 @@
static struct st_effect efftab[MAX_EFF]; /* left/mono channel effects */
static struct st_effect efftabR[MAX_EFF];/* right channel effects */
static int neffects; /* # of effects to run on data */
+static int input_eff; /* last input effect with data */
static struct st_effect user_efftab[MAX_USER_EFF];
static int nuser_effects;
@@ -706,6 +708,8 @@
current_input = 0;
#endif
+ input_eff = 0;
+
/* Run input data through effects and get more until olen == 0
* (or ST_EOF).
*/
@@ -835,6 +839,9 @@
} while (1);
+ /* This will drain the effects */
+ drain_effect_out();
+
#ifdef SOXMIX
/* Free input buffers now that they are not used */
for (f = 0; f < MAX_INPUT_FILES; f++)
@@ -843,33 +850,6 @@
}
#endif
- /* Drain the effects out first to last,
- * pushing residue through subsequent effects */
- /* oh, what a tangled web we weave */
- for(f = 1; f < neffects; f++)
- {
- while (1) {
-
- if (drain_effect(f) == 0)
- break; /* out of while (1) */
-
- /* Change the volume of this output data if needed. */
- if (writing && file_opts[file_count-1]->volume != 1.0)
- clipped += volumechange(efftab[neffects-1].obuf,
- efftab[neffects-1].olen,
- file_opts[file_count-1]->volume);
-
- /* FIXME: Need to look at return code and abort on failure */
- if (writing && efftab[neffects-1].olen > 0)
- (*file_desc[file_count-1]->h->write)(file_desc[file_count-1],
- efftab[neffects-1].obuf,
- (st_ssize_t)efftab[neffects-1].olen);
-
- if (efftab[f].olen != ST_BUFSIZ)
- break;
- }
- }
-
/* Free output buffers now that they won't be used */
for(e = 0; e < neffects; e++)
{
@@ -916,12 +896,11 @@
static int flow_effect_out(void)
{
int e, havedata, flowstatus = 0;
- int input_eff = 0;
do {
/* run entire chain BACKWARDS: pull, don't push.*/
/* this is because buffering system isn't a nice queueing system */
- for(e = neffects - 1; e > input_eff; e--)
+ for(e = neffects - 1; e >= input_eff; e--)
{
/* flow_effect returns ST_EOF when it will not process
* any more samples. This is used to bail out early.
@@ -931,7 +910,22 @@
*/
flowstatus = flow_effect(e);
if (flowstatus == ST_EOF)
- input_eff = e;
+ input_eff = e+1;
+
+ /* If this buffer contains more input data then break out
+ * of this loop now. This will allow us to loop back around
+ * and reprocess the rest of this input buffer.
+ * I suppose this could be an issue with some effects
+ * if they crash when given small input buffers.
+ * But I was more concerned that we would need to do
+ * some type of garbage collection otherwise. By this I
+ * mean that if we went ahead and processed an effect
+ * lower in the chain, it might only have like 2 bytes
+ * left at the end of this buffer to place its data in.
+ * Software is more likely to refuse to handle that.
+ */
+ if (efftab[e].odone < efftab[e].olen)
+ break;
}
/* If outputing and output data was generated then write it */
@@ -950,7 +944,11 @@
(*file_desc[file_count-1]->h->write)(file_desc[file_count-1],
efftab[neffects-1].obuf,
(st_ssize_t)efftab[neffects-1].olen);
- efftab[neffects-1].odone = efftab[neffects-1].olen;
+ /* FIXME: Goes with above. Should look at # of bytes writen. */
+ /* Currently, assuming all bytes were written and resetting
+ * buffer pointers accordingly.
+ */
+ efftab[neffects-1].odone = efftab[neffects-1].olen = 0;
if (file_desc[file_count-1]->st_errno)
{
@@ -958,6 +956,9 @@
break;
}
}
+ else
+ /* Make it look like everything was consumed */
+ efftab[neffects-1].odone = efftab[neffects-1].olen = 0;
/* if stuff still in pipeline, set up to flow effects again */
/* When all effects have reported ST_EOF then this check will
@@ -964,11 +965,37 @@
* show no more data.
*/
havedata = 0;
- for(e = neffects - 2; e >= input_eff; e--)
+ for(e = neffects - 1; e >= input_eff; e--)
+ {
if (efftab[e].odone < efftab[e].olen) {
havedata = 1;
break;
}
+ }
+
+ if (!havedata && input_eff > 0)
+ {
+ /* If the input file is not returning data then
+ * we must prime the pump using the drain effect.
+ * After its primed, the loop will suck the data
+ * threw. Once an input_eff stop reporting samples,
+ * we will continue to the next until all are drained.
+ */
+ while (input_eff < neffects)
+ {
+ int rc;
+
+ rc = drain_effect(input_eff);
+
+ if (rc == ST_EOF || efftab[input_eff].olen == 0)
+ input_eff++;
+ else
+ {
+ havedata = 1;
+ break;
+ }
+ }
+ }
} while (havedata);
/* If input_eff isn't pointing at fake first entry then there
@@ -996,14 +1023,16 @@
* run effect over entire buffer.
*/
idone = efftab[e-1].olen - efftab[e-1].odone;
- odone = ST_BUFSIZ;
+ odone = ST_BUFSIZ - efftab[e].olen;
effstatus = (* efftab[e].h->flow)(&efftab[e],
&efftab[e-1].obuf[efftab[e-1].odone],
- efftab[e].obuf, (st_size_t *)&idone,
+ &efftab[e].obuf[efftab[e].olen],
+ (st_size_t *)&idone,
(st_size_t *)&odone);
efftab[e-1].odone += idone;
- efftab[e].odone = 0;
- efftab[e].olen = odone;
+ /* Leave efftab[e].odone were it was since we didn't consume data */
+ /*efftab[e].odone = 0;*/
+ efftab[e].olen += odone;
done = idone + odone;
} else {
@@ -1011,7 +1040,8 @@
* on each of them.
*/
idone = efftab[e-1].olen - efftab[e-1].odone;
- odone = ST_BUFSIZ;
+ odone = ST_BUFSIZ - efftab[e].olen;
+
ibuf = &efftab[e-1].obuf[efftab[e-1].odone];
for(i = 0; i < idone; i += 2) {
ibufl[i/2] = *ibuf++;
@@ -1033,7 +1063,7 @@
ibufr, obufr, (st_size_t *)&idoner,
(st_size_t *)&odoner);
- obuf = efftab[e].obuf;
+ obuf = &efftab[e].obuf[efftab[e].olen];
/* This loop implies left and right effect will always output
* the same amount of data.
*/
@@ -1042,41 +1072,76 @@
*obuf++ = obufr[i];
}
efftab[e-1].odone += idonel + idoner;
- efftab[e].odone = 0;
- efftab[e].olen = odonel + odoner;
+ /* Don't clear since nothng has been consumed yet */
+ /*efftab[e].odone = 0;*/
+ efftab[e].olen += odonel + odoner;
done = idonel + idoner + odonel + odoner;
}
if (effstatus == ST_EOF)
+ {
return ST_EOF;
+ }
if (done == 0)
st_fail("Effect took & gave no samples!");
return ST_SUCCESS;
}
+static int drain_effect_out(void)
+{
+ /* Skip past input effect since we know thats not needed */
+ if (input_eff == 0)
+ input_eff = 1;
+
+ /* Try to prime the pump with some data */
+ while (input_eff < neffects)
+ {
+ int rc;
+
+ rc = drain_effect(input_eff);
+
+ if (rc == ST_EOF || efftab[input_eff].olen == 0)
+ input_eff++;
+ else
+ break;
+ }
+
+ /* Just do standard flow routines after the priming. */
+ return flow_effect_out();
+}
+
static int drain_effect(int e)
{
st_ssize_t i, olen, olenl, olenr;
st_sample_t *obuf;
+ int rc;
if (! efftabR[e].name) {
efftab[e].olen = ST_BUFSIZ;
- /* FIXME: Should look at return code and abort on ST_EOF */
- (* efftab[e].h->drain)(&efftab[e],efftab[e].obuf,
- &efftab[e].olen);
+ rc = (* efftab[e].h->drain)(&efftab[e],efftab[e].obuf,
+ &efftab[e].olen);
+ efftab[e].odone = 0;
}
else {
+ int rc_l, rc_r;
+
olen = ST_BUFSIZ;
/* left */
olenl = olen/2;
- /* FIXME: Should look at return code and abort on ST_EOF */
- (* efftab[e].h->drain)(&efftab[e], obufl, (st_size_t *)&olenl);
+ rc_l = (* efftab[e].h->drain)(&efftab[e], obufl,
+ (st_size_t *)&olenl);
/* right */
olenr = olen/2;
/* FIXME: Should look at return code and abort on ST_EOF */
- (* efftab[e].h->drain)(&efftabR[e], obufr, (st_size_t *)&olenr);
+ rc_r = (* efftab[e].h->drain)(&efftabR[e], obufr,
+ (st_size_t *)&olenr);
+ if (rc_l == ST_EOF || rc_r == ST_EOF)
+ rc = ST_EOF;
+ else
+ rc = ST_SUCCESS;
+
obuf = efftab[e].obuf;
/* This loop implies left and right effect will always output
* the same amount of data.
@@ -1086,10 +1151,11 @@
*obuf++ = obufr[i];
}
efftab[e].olen = olenl + olenr;
+ efftab[e].odone = 0;
}
- return(efftab[e].olen);
+ return rc;
}
-
+
/*
* If no effect given, decide what it should be.
* Smart ruleset for multiple effects in sequence.