shithub: sox

Download patch

ref: 4efd7465a94b4a10cc3a283ed32668e228b62f95
parent: bc8d4ef63433f5649e5ce30ec34d58dd43394623
author: Ulrich Klauer <ulrich@chirlu.de>
date: Sun Jan 1 18:54:01 EST 2012

Let some effects calculate expected output length

For certain effects (see below) that change audio length
(SOX_EFF_LENGTH), calculate the expected output length for propagation
down the effects chain. This makes it possible, e.g., to use a
fade-out later without specifying an explicit end position.

This commit takes care of the following effects: delay, fade, pad,
repeat, speed, synth, trim. It would probably be possible to do the
same for more effects: chorus, echo, echos, noisered, phaser, stretch,
tempo. For these three effects, however, calculating the output length
beforehand is impossible as it depends on the input audio: silence,
splice, vad.

--- a/src/delay.c
+++ b/src/delay.c
@@ -84,8 +84,11 @@
     p->buffer_size = temp;
   }
   lsx_parsesamples(effp->in_signal.rate, p->max_arg, &max_delay, 't');
-  if (effp->flow == 0)
+  if (effp->flow == 0) {
+    effp->out_signal.length = effp->in_signal.length ?
+       effp->in_signal.length + max_delay * effp->in_signal.channels : 0;
     lsx_debug("extending audio by %" PRIu64 " samples", max_delay);
+  }
   p->buffer_index = p->delay = p->pre_pad = 0;
   p->pad = max_delay - p->buffer_size;
   p->buffer = lsx_malloc(p->buffer_size * sizeof(*p->buffer));
--- a/src/fade.c
+++ b/src/fade.c
@@ -187,6 +187,9 @@
         fade->out_start == fade->out_stop)
       return SOX_EFF_NULL;
 
+    effp->out_signal.length = truncate ?
+        fade->out_stop * effp->in_signal.channels : effp->in_signal.length;
+
     return SOX_SUCCESS;
 }
 
--- a/src/pad.c
+++ b/src/pad.c
@@ -76,7 +76,29 @@
   priv_t * p = (priv_t *)effp->priv;
   unsigned i;
 
-  parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */
+  /* Re-parse now rate is known */
+  if (parse(effp, 0, effp->in_signal.rate) != SOX_SUCCESS)
+    return SOX_EOF;
+
+  if ((effp->out_signal.length = effp->in_signal.length) != 0) {
+    for (i = 0; i < p->npads; ++i)
+      effp->out_signal.length +=
+        p->pads[i].pad * effp->in_signal.channels;
+
+    /* Check that the last pad position (except for "at the end")
+       is within bounds. */
+    i = p->npads;
+    if (i > 0 && p->pads[i-1].start == UINT64_MAX)
+      i--;
+    if (i > 0 &&
+        p->pads[i-1].start * effp->in_signal.channels
+          > effp->in_signal.length)
+    {
+      lsx_fail("pad position after end of audio");
+      return SOX_EOF;
+    }
+  }
+
   p->in_pos = p->pad_pos = p->pads_pos = 0;
   for (i = 0; i < p->npads; ++i)
     if (p->pads[i].pad)
--- a/src/repeat.c
+++ b/src/repeat.c
@@ -45,6 +45,7 @@
   }
   p->num_samples = p->remaining_samples = 0;
   p->remaining_repeats = p->num_repeats;
+  effp->out_signal.length = effp->in_signal.length * (p->num_repeats + 1);
   return SOX_SUCCESS;
 }
 
--- a/src/speed.c
+++ b/src/speed.c
@@ -56,6 +56,10 @@
     return SOX_EFF_NULL;
 
   effp->out_signal.rate = effp->in_signal.rate * p->factor;
+
+  effp->out_signal.length = effp->in_signal.length;
+    /* audio length if measured in samples doesn't change */
+
   return SOX_SUCCESS;
 }
 
--- a/src/synth.c
+++ b/src/synth.c
@@ -415,9 +415,11 @@
 
   p->samples_done = 0;
 
-  if (p->length_str)
+  if (p->length_str) {
     if (lsx_parsesamples(effp->in_signal.rate, p->length_str, &p->samples_to_do, 't') == NULL)
       return lsx_usage(effp);
+  } else
+    p->samples_to_do = effp->in_signal.length / effp->in_signal.channels;
 
   p->number_of_channels = effp->in_signal.channels;
   p->channels = lsx_calloc(p->number_of_channels, sizeof(*p->channels));
@@ -523,6 +525,7 @@
   }
   p->gain = 1;
   effp->out_signal.mult = p->no_headroom? NULL : &p->gain;
+  effp->out_signal.length = p->samples_to_do * effp->out_signal.channels;
   return SOX_SUCCESS;
 }
 
--- a/src/trim.c
+++ b/src/trim.c
@@ -107,7 +107,20 @@
     trim->index = 0;
     trim->trimmed = 0;
 
+    if (effp->in_signal.length) {
+      if (trim->start >= effp->in_signal.length) {
+        lsx_fail("start position after end of file");
+        return SOX_EOF;
+      } else if (trim->start + trim->length >= effp->in_signal.length) {
+        lsx_fail("end position after end of file");
+        return SOX_EOF;
+      }
+    }
+
     effp->out_signal.length = trim->length;
+    if (!effp->out_signal.length && effp->in_signal.length > trim->start)
+        effp->out_signal.length = effp->in_signal.length - trim->start;
+
     return (SOX_SUCCESS);
 }