ref: 61a9fffb24f31fe524a6d4c5635b7e91dce6fe69
parent: 515acca506a03ca44da889aff6d3d3c29511b198
author: robs <robs>
date: Sat Oct 18 07:40:36 EDT 2008
tidy up bend effect
--- a/ChangeLog
+++ b/ChangeLog
@@ -52,7 +52,7 @@
o New `riaa' effect: RIAA vinyl playback EQ. (robs)
o New `loudness' effect: gain control with ISO 226 loudness
compensation. (robs)
- o New `bend' effect; pitch bending; W.I.P., subject to change. (robs)
+ o New `bend' effect; pitch bending. (robs)
o New -b option for the norm effect; can be used to fix stereo
imbalance. (robs)
o New --effects-file option to read effects and arguments from
--- a/sox.1
+++ b/sox.1
@@ -1140,10 +1140,27 @@
.SP
See also \fBequalizer\fR for a peaking equalisation effect.
.TP
-\fBbend\fR [\fB\-f \fIframe-rate\fR(25)] [\fB\-o \fIoversample\fR(16)] { \fIdelay\fB,\fIcents\fB,\fIduration\fR }
-Pitch bending. Work in progress\*msubject to change.
+\fBbend\fR [\fB\-f \fIframe-rate\fR(25)] [\fB\-o \fIover-sample\fR(16)] { \fIdelay\fB,\fIcents\fB,\fIduration\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.
.SP
-For example:
+The pitch-bending algorithm utilises the Discrete Fourier Transform (DTF)
+at a particular frame rate and over-sampling rate.
+The
+.B \-f
+and
+.B \-o
+parameters may be used to adjust these parameters and thus control the
+smoothness of the changes in pitch.
+.SP
+For example, an initial tone is generated, then bent three times, yeilding
+four different notes in total:
.EX
play -n synth 2.5 sin 667 gain 1 \\
bend .35,180,.25 .15,740,.53 0,-520,.3
@@ -1152,7 +1169,7 @@
to remove it, use
.B gain\ \-5
in place of
-.BR gain\ \1 .
+.BR gain\ 1 .
.TP
\fBchorus \fIgain-in gain-out\fR <\fIdelay decay speed depth \fB\-s\fR\^|\^\fB\-t\fR>
Add a chorus effect to the audio. This can make a single vocal sound
--- a/src/bend.c
+++ b/src/bend.c
@@ -28,76 +28,14 @@
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
*/
+#ifdef NDEBUG /* Enable assert always. */
+#undef NDEBUG /* Must undef above assert.h or other that might include it. */
+#endif
+
#include "sox_i.h"
#include "getopt.h"
+#include <assert.h>
-static void smbFft(float *fftBuffer, long fftFrameSize, long sign)
-/*
- * FFT routine, (C)1996 S.M.Bernsee. Sign = -1 is FFT, 1 is iFFT (inverse)
- * Fills fftBuffer[0...2*fftFrameSize-1] with the Fourier transform of the
- * time domain data in fftBuffer[0...2*fftFrameSize-1]. The FFT array takes
- * and returns the cosine and sine parts in an interleaved manner, ie.
- * fftBuffer[0] = cosPart[0], fftBuffer[1] = sinPart[0], asf. fftFrameSize
- * must be a power of 2. It expects a complex input signal (see footnote 2),
- * ie. when working with 'common' audio signals our input signal has to be
- * passed as {in[0],0.,in[1],0.,in[2],0.,...} asf. In that case, the transform
- * of the frequencies of interest is in fftBuffer[0...fftFrameSize].
- */
-{
- float wr, wi, arg, *p1, *p2, temp;
- float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
- long i, bitm, j, le, le2, k;
-
- for (i = 2; i < 2 * fftFrameSize - 2; i += 2) {
- for (bitm = 2, j = 0; bitm < 2 * fftFrameSize; bitm <<= 1) {
- if (i & bitm)
- j++;
- j <<= 1;
- }
- if (i < j) {
- p1 = fftBuffer + i;
- p2 = fftBuffer + j;
- temp = *p1;
- *(p1++) = *p2;
- *(p2++) = temp;
- temp = *p1;
- *p1 = *p2;
- *p2 = temp;
- }
- }
- for (k = 0, le = 2; k < (long) (log((double) fftFrameSize) / log(2.) + .5);
- k++) {
- le <<= 1;
- le2 = le >> 1;
- ur = 1.0;
- ui = 0.0;
- arg = M_PI / (le2 >> 1);
- wr = cos(arg);
- wi = sign * sin(arg);
- for (j = 0; j < le2; j += 2) {
- p1r = fftBuffer + j;
- p1i = p1r + 1;
- p2r = p1r + le2;
- p2i = p2r + 1;
- for (i = j; i < 2 * fftFrameSize; i += le) {
- tr = *p2r * ur - *p2i * ui;
- ti = *p2r * ui + *p2i * ur;
- *p2r = *p1r - tr;
- *p2i = *p1i - ti;
- *p1r += tr;
- *p1i += ti;
- p1r += le;
- p1i += le;
- p2r += le;
- p2i += le;
- }
- tr = ur * wr - ui * wi;
- ui = ur * wi + ui * wr;
- ur = tr;
- }
- }
-}
-
#define MAX_FRAME_LENGTH 8192
typedef struct {
@@ -117,7 +55,7 @@
float gInFIFO[MAX_FRAME_LENGTH];
float gOutFIFO[MAX_FRAME_LENGTH];
- float gFFTworksp[2 * MAX_FRAME_LENGTH];
+ double gFFTworksp[2 * MAX_FRAME_LENGTH];
float gLastPhase[MAX_FRAME_LENGTH / 2 + 1];
float gSumPhase[MAX_FRAME_LENGTH / 2 + 1];
float gOutputAccum[2 * MAX_FRAME_LENGTH];
@@ -181,6 +119,7 @@
int n = effp->in_signal.rate / p->frame_rate + .5;
for (p->fftFrameSize = 2; n > 2; p->fftFrameSize <<= 1, n >>= 1);
+ assert(p->fftFrameSize <= MAX_FRAME_LENGTH);
p->shift = 1;
parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */
p->in_pos = p->bends_pos = 0;
@@ -244,13 +183,13 @@
}
/* ***************** ANALYSIS ******************* */
- smbFft(p->gFFTworksp, p->fftFrameSize, -1);
+ lsx_safe_cdft(2 * p->fftFrameSize, 1, p->gFFTworksp);
/* this is the analysis step */
for (k = 0; k <= fftFrameSize2; k++) {
/* de-interlace FFT buffer */
real = p->gFFTworksp[2 * k];
- imag = p->gFFTworksp[2 * k + 1];
+ imag = - p->gFFTworksp[2 * k + 1];
/* compute magnitude and phase */
magn = 2. * sqrt(real * real + imag * imag);
@@ -303,13 +242,13 @@
phase = p->gSumPhase[k];
/* get real and imag part and re-interleave */
p->gFFTworksp[2 * k] = magn * cos(phase);
- p->gFFTworksp[2 * k + 1] = magn * sin(phase);
+ p->gFFTworksp[2 * k + 1] = - magn * sin(phase);
}
for (k = p->fftFrameSize + 2; k < 2 * p->fftFrameSize; k++)
p->gFFTworksp[k] = 0.; /* zero negative frequencies */
- smbFft(p->gFFTworksp, p->fftFrameSize, 1); /* do inverse transform */
+ lsx_safe_cdft(2 * p->fftFrameSize, -1, p->gFFTworksp);
/* do windowing and add to output accumulator */
for (k = 0; k < p->fftFrameSize; k++) {
@@ -355,7 +294,7 @@
sox_effect_handler_t const *sox_bend_effect_fn(void)
{
static sox_effect_handler_t handler = {
- "bend", "{delay,cents,duration}", SOX_EFF_GETOPT,
+ "bend", "[-f frame-rate(25)] [-o over-sample(16)] {delay,cents,duration}", SOX_EFF_GETOPT,
create, start, flow, 0, stop, kill, sizeof(priv_t)
};
return &handler;