shithub: sox

Download patch

ref: 2469faa09760cccf9ac360872613fca7a42836aa
parent: 851a8d152c004310afd5bdf0a300c1c74e979855
author: Ulrich Klauer <ulrich@chirlu.de>
date: Thu Jan 31 12:46:04 EST 2013

bend: use lsx_parseposition

Use the new lsx_parseposition function for the bend effect and update
the documentation accordingly.

--- a/sox.1
+++ b/sox.1
@@ -1627,16 +1627,13 @@
 .SP
 See also \fBequalizer\fR for a peaking equalisation effect.
 .TP
-\fBbend\fR [\fB\-f \fIframe-rate\fR(25)] [\fB\-o \fIover-sample\fR(16)] { \fIdelay\fB,\fIcents\fB,\fIduration\fR }
+\fBbend\fR [\fB\-f \fIframe-rate\fR(25)] [\fB\-o \fIover-sample\fR(16)] { \fIstart-position(+)\fB,\fIcents\fB,\fIend-position(+)\fR }
 Changes pitch by specified amounts at specified times.
-Each given triple: \fIdelay\fB,\fIcents\fB,\fIduration\fR specifies one bend.
-.I delay
-is the amount of time after the start of the audio stream, or the end of the previous bend, at which to start bending the pitch;
-.I cents
-is the number of cents (100 cents = 1 semitone) by which to bend the pitch, and
-.I duration
-the length of time over which the pitch will be bent.  For \fIdelay\fR and
-\fIduration\fR, any time specification may be used.
+Each given triple: \fIstart-position\fB,\fIcents\fB,\fIend-position\fR
+specifies one bend.
+\fIcents\fR is the number of cents (100 cents = 1 semitone) by which to
+bend the pitch. The other values specify the points in time at which to start
+and end bending the pitch, respectively.
 .SP
 The pitch-bending algorithm utilises the Discrete Fourier Transform (DFT)
 at a particular frame rate and over-sampling rate.
@@ -1654,6 +1651,8 @@
    play \-n synth 2.5 sin 667 gain 1 \\
 	bend .35,180,.25  .15,740,.53  0,\-520,.3
 .EE
+Here, the first bend runs from 0.35 to 0.6, and the second one from 0.75
+to 1.28 seconds.
 Note that the clipping that is produced in this example is deliberate;
 to remove it, use
 .B gain\ \-5
--- a/src/bend.c
+++ b/src/bend.c
@@ -70,23 +70,43 @@
 {
   priv_t *p = (priv_t *) effp->priv;
   size_t i;
-  uint64_t time = 0, delay;
   char const *next;
+  uint64_t last_seen = 0;
+  const uint64_t in_length = argv ? 0 :
+    (effp->in_signal.length != SOX_UNKNOWN_LEN ?
+     effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN);
 
   for (i = 0; i < p->nbends; ++i) {
     if (argv)   /* 1st parse only */
       p->bends[i].str = lsx_strdup(argv[i]);
-    next = lsx_parsesamples(rate, p->bends[i].str, &delay, 't');
+
+    next = lsx_parseposition(rate, p->bends[i].str,
+             argv ? NULL : &p->bends[i].start, last_seen, in_length, '+');
+    last_seen = p->bends[i].start;
     if (next == NULL || *next != ',')
       break;
-    p->bends[i].start = time += delay;
+
     p->bends[i].cents = strtod(next + 1, (char **)&next);
     if (p->bends[i].cents == 0 || *next != ',')
       break;
-    next = lsx_parsesamples(rate, next + 1, &p->bends[i].duration, 't');
+
+    next = lsx_parseposition(rate, next + 1,
+             argv ? NULL : &p->bends[i].duration, last_seen, in_length, '+');
+    last_seen = p->bends[i].duration;
     if (next == NULL || *next != '\0')
       break;
-    time += p->bends[i].duration;
+
+    /* sanity checks */
+    if (!argv && p->bends[i].duration < p->bends[i].start) {
+      lsx_fail("Bend %" PRIuPTR " has negative width", i+1);
+      break;
+    }
+    if (!argv && i && p->bends[i].start < p->bends[i-1].start) {
+      lsx_fail("Bend %" PRIuPTR " overlaps with previous one", i+1);
+      break;
+    }
+
+    p->bends[i].duration -= p->bends[i].start;
   }
   if (i < p->nbends)
     return lsx_usage(effp);
@@ -298,7 +318,7 @@
 sox_effect_handler_t const *lsx_bend_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "bend", "[-f frame-rate(25)] [-o over-sample(16)] {delay,cents,duration}",
+    "bend", "[-f frame-rate(25)] [-o over-sample(16)] {start,cents,end}",
     0, create, start, flow, 0, stop, lsx_kill, sizeof(priv_t)
   };
   return &handler;