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;