ref: 1aa427de3cbb0e963e652608e12f0034c910e176
parent: 21ae07faf06daee0ced8e6f8f9b8ae8dba006b96
author: robs <robs>
date: Sun Jul 22 10:35:14 EDT 2007
tidying up
--- a/ChangeLog
+++ b/ChangeLog
@@ -37,6 +37,7 @@
o mixer can now mixdown to mono any number of channels. (robs)
o All effects that could only work on mono or stereo audio, now
work with any number of channels. (robs)
+ o Added WSOLA-based key and tempo effects. (robs)
Other new features:
--- a/soxeffect.7
+++ b/soxeffect.7
@@ -412,12 +412,11 @@
.SP
See also \fBfilter\fR for filters with a steeper roll-off.
.TP
-\fBkey \fR[\fB\-q\fR] \fIshift\fR [\fIwindow\fR [\fIseek\fR [\fIoverlap\fR]]]
-Change the audio key (i.e. pitch but not tempo) using a WSOLA algorithm similar
-to that used by SoundTouch [8].
+\fBkey \fR[\fB\-q\fR] \fIshift\fR [\fIsegment\fR [\fIsearch\fR [\fIoverlap\fR]]]
+Change the audio key (i.e. pitch but not tempo) using a WSOLA algorithm.
.SP
.I shift
-is the key shift in positive or negative `cents' (i.e. 100ths of a
+gives the key shift as positive or negative `cents' (i.e. 100ths of a
semitone). See the
.B tempo
effect for a description of the other parameters.
@@ -611,21 +610,6 @@
(\fB\-t\fR). The decay should be less than 0\*d5 to avoid
feedback. Gain-out is the volume of the output.
.TP
-\fBpitch \fIshift\fR [\fIwidth interpolate fade\fR]
-Change the pitch of file without affecting its duration by cross-fading
-shifted samples.
-.I shift
-is given in cents. Use a positive value to shift to treble, negative value to shift to bass.
-Default shift is 0.
-.I width
-of window is in ms. Default width is 20ms. Try 30ms to lower pitch,
-and 10ms to raise pitch.
-.I interpolate
-option, can be \fBcubic\fR or \fBlinear\fR. Default is \fBcubic\fR. The
-.I fade
-option, can be \fBcos\fR, \fBhamming\fR, \fBlinear\fR or
-\fBtrapezoid\fR; the default is \fBcos\fR.
-.TP
\fBpolyphase\fR [\fB\-w nut\fR\^|\^\fBham\fR] [\fB\-width \fIn\fR] [\fB\-cutoff \fIc\fR]
Change the sampling rate using `polyphase interpolation', a DSP algorithm.
This method is relatively slow and memory intensive.
@@ -924,22 +908,6 @@
This is mainly only of use in tracking down endian problems that
creep in to SoX on cross-platform versions.
.TP
-\fBstretch \fIfactor\fR [\fIwindow fade shift fading\fR]
-Time stretch the audio by the given factor. Changes duration without affecting the pitch.
-.I factor
-of stretching: >1 lengthen, <1 shorten duration.
-.I window
-size is in ms. Default is 20ms. The
-.I fade
-option, can be `lin'.
-.I shift
-ratio, in [0 1]. Default depends on stretch factor. 1
-to shorten, 0\*d8 to lengthen. The
-.I fading
-ratio, in [0 0\*d5]. The amount of a fade's default depends on
-.I factor
-and \fIshift\fR.
-.TP
\fBswap\fR [\fI1 2\fR | \fI1 2 3 4\fR]
Swap channels in multi-channel audio files. Optionally, you may
specify the channel order you would like the output in. This defaults
@@ -1048,48 +1016,38 @@
\fIp3\fR (trapezium): the percentage through each cycle at which `falling'
ends; default=60.
.TP
-\fBtempo \fR[\fB\-q\fR] \fIfactor\fR [\fIwindow\fR [\fIseek\fR [\fIoverlap\fR]]]
-Change the audio tempo (but not its pitch) using a WSOLA algorithm similar
-to that used by SoundTouch [8].
+\fBtempo \fR[\fB\-q\fR] \fIfactor\fR [\fIsegment\fR [\fIsearch\fR [\fIoverlap\fR]]]
+Change the audio tempo (but not its pitch) using a `WSOLA' algorithm.
+The audio is chopped up into segments which are then shifted in the time
+domain and overlapped (cross-faded) at points where their waveforms are
+most similar (as determined by measurement of `least squares').
.SP
-The optional
+By default, linear searches are used to find the best overlapping
+points; if the optional
.B \-q
-parameter selects a quicker but less accurate version of the algorithm.
+parameter is given, tree searches are used instead, giving a quicker,
+but possibly lower quality, result.
.SP
.I factor
gives the ratio of new tempo to the old tempo.
.SP
The optional
-.I window
-parameter gives the length in milliseconds of each chunk (or window) of
-audio processed by the algorithm. The default value is 82\ ms and is
-typically suitable for making small changes to the tempo of music. For
-larger tempo changes (e.g. a factor of 2), 50\ ms may be better; for
-speech, 30\ ms may be better.
+.I segment
+parameter selects the algorithm's segment size in milliseconds. The
+default value is 82 and is typically suited to making small changes to
+the tempo of music; for larger changes (e.g. a factor of 2), 50\ ms may
+give a better result. When changing the tempo of speech, a segment size
+of around 30\ ms often works well.
.SP
The optional
-.I seek
-parameter gives the seeking window length in milliseconds (default 14)
-for the algorithm to find the best possible overlapping location. This
-determines from how wide window the algorithm may look for an optimal
-joining location when mixing the sound sequences back together. The
-bigger this window setting is, the higher the possibility to find a
-better mixing position will become, but at the same time large values
-may cause a `drifting' artifact because consequent sequences will be
-taken at more uneven intervals. If there's a disturbing artifact that
-sounds as if a constant frequency was drifting around, try reducing this
-setting. Increasing this value increases computational burden & vice
-versa.
+.I search
+parameter gives the audio length in milliseconds (default 14) over which
+the algorithm will search for overlapping points. Larger values use
+more processing time and do not necessarily produce better results.
.SP
The optional
.I overlap
-parameter gives the overlap length in milliseconds (default 12). When
-the chopped sound sequences are mixed back together, to form a
-continuous sound stream, this parameter defines over how long period the
-two consecutive sequences are let to overlap each other. This shouldn't
-be that critical parameter. If you reduce the \fIwindow\fR setting by a
-large amount, you might wish to try a smaller value on this. Increasing
-this value increases computational burden & vice versa.
+parameter gives the segment overlap length in milliseconds (default 12).
.SP
See also
.B stretch
@@ -1230,10 +1188,55 @@
.B mixer
effect and is retained for backwards compatibility only.
.TP
+\fBpitch \fIshift\fR [\fIwidth interpolate fade\fR]
+Change the audio pitch (but not its duration).
+This effect is equivalent to the
+.B key
+effect with
+.I search
+set to zero, so its results are comparitively poor;
+it is retained for backwards compatibility only.
+.SP
+Change by cross-fading shifted samples.
+.I shift
+is given in cents. Use a positive value to shift to treble, negative value to shift to bass.
+Default shift is 0.
+.I width
+of window is in ms. Default width is 20ms. Try 30ms to lower pitch,
+and 10ms to raise pitch.
+.I interpolate
+option, can be \fBcubic\fR or \fBlinear\fR. Default is \fBcubic\fR. The
+.I fade
+option, can be \fBcos\fR, \fBhamming\fR, \fBlinear\fR or
+\fBtrapezoid\fR; the default is \fBcos\fR.
+.TP
\fBrate\fR
Does the same as \fBresample\fR with no parameters; it exists for
backwards compatibility.
.TP
+\fBstretch \fIfactor\fR [\fIwindow fade shift fading\fR]
+Change the audio duration (but not its pitch).
+This effect is equivalent to the
+.B tempo
+effect with (\fIfactor\fR inverted and)
+.I search
+set to zero, so its results are comparitively poor;
+it is retained for backwards compatibility only.
+.SP
+.I factor
+of stretching: >1 lengthen, <1 shorten duration.
+.I window
+size is in ms. Default is 20ms. The
+.I fade
+option, can be `lin'.
+.I shift
+ratio, in [0 1]. Default depends on stretch factor. 1
+to shorten, 0\*d8 to lengthen. The
+.I fading
+ratio, in [0 0\*d5]. The amount of a fade's default depends on
+.I factor
+and \fIshift\fR.
+.TP
\fBvibro \fIspeed\fR [\fIdepth\fR]
This is a deprecated alias for the
.B tremolo
@@ -1282,11 +1285,6 @@
Steve Harris,
.IR "LADSPA plugins" ,
http://plugin.org.uk
-.TP
-[8]
-Olli Parviainen,
-.IR "SoundTouch Audio Processing Library" ,
-http://www.surina.net/soundtouch
.SH AUTHORS
Chris Bagwell (cbagwell@users.sourceforge.net).
Other authors and contributors are listed in the AUTHORS file that
--- a/src/key.c
+++ b/src/key.c
@@ -47,7 +47,8 @@
static sox_effect_handler_t handler;
handler = *sox_tempo_effect_fn();
handler.name = "key";
- handler.usage = "[-q] shift-in-cents [window-ms [seek-ms [overlap-ms]]]",
+ handler.usage = "[-q] shift-in-cents [segment-ms [search-ms [overlap-ms]]]",
handler.getopts = getopts;
+ handler.flags &= ~SOX_EFF_LENGTH;
return &handler;
}
--- a/src/pitch.c
+++ b/src/pitch.c
@@ -550,7 +550,7 @@
"shift width interpole fade\n"
" (in cents, in ms, cub/lin, cos/ham/lin/trap)"
" (defaults: 0 20 c c)",
- SOX_EFF_LENGTH,
+ SOX_EFF_LENGTH | SOX_EFF_DEPRECATED,
sox_pitch_getopts,
sox_pitch_start,
sox_pitch_flow,
--- a/src/stretch.c
+++ b/src/stretch.c
@@ -338,7 +338,7 @@
"factor [window fade shift fading]\n"
" (expansion, frame in ms, lin/..., unit<1.0, unit<0.5)\n"
" (defaults: 1.0 20 lin ...)",
- SOX_EFF_LENGTH,
+ SOX_EFF_LENGTH | SOX_EFF_DEPRECATED,
sox_stretch_getopts,
sox_stretch_start,
sox_stretch_flow,
--- a/src/tempo.c
+++ b/src/tempo.c
@@ -1,7 +1,7 @@
/*
- * Effect: change the audio tempo (but not key)
- *
+ * Effect: change tempo (alter duration, maintain pitch) with a WSOLA method.
* Copyright (c) 2007 robs@users.sourceforge.net
+ * Based on ideas from Olli Parviainen's SoundTouch Library.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
@@ -24,7 +24,7 @@
#include <string.h>
#include <assert.h>
-/* Addressible FIFO buffer */
+/*------------------------- Addressible FIFO buffer --------------------------*/
typedef struct {
char * data;
@@ -112,32 +112,35 @@
fifo_clear(f);
}
-/*
- * Change tempo (alter duration, maintain pitch) using a WSOLA algorithm.
- * Based on ideas from Olli Parviainen's SoundTouch Library.
- */
+/*---------------------------- WSOLA Tempo Change ----------------------------*/
typedef struct {
+ /* Configuration parameters: */
+ size_t channels;
+ sox_bool quick_search; /* Whether to quick search or linear search */
+ double factor; /* 1 for no change, < 1 for slower, > 1 for faster. */
+ size_t search; /* Wide samples to search for best overlap position */
+ size_t segment; /* Processing segment length in wide samples */
+ size_t overlap; /* In wide samples */
+
+ size_t process_size; /* # input wide samples needed to process 1 segment */
+
+ /* Buffers: */
+ fifo_t input_fifo;
+ float * overlap_buf;
+ fifo_t output_fifo;
+
+ /* Counters: */
size_t samples_in;
size_t samples_out;
- double factor;
- size_t channels;
- size_t process_size;
- float * prev_win_end;
- size_t overlap;
- size_t seek;
- size_t window;
- size_t windows_total;
+ size_t segments_total;
size_t skip_total;
- fifo_t output_fifo;
- fifo_t input_fifo;
- sox_bool quick_seek;
-} Stretch;
+} tempo_t;
-/* For the Wave Similarity bit of WSOLA */
-static double difference(const float * a, const float * b, size_t length)
+/* For the Waveform Similarity part of WSOLA */
+static float difference(const float * a, const float * b, size_t length)
{
- double diff = 0;
+ float diff = 0;
size_t i = 0;
#define _ diff += sqr(a[i] - b[i]), ++i; /* Loop optimisation */
@@ -146,28 +149,28 @@
return diff;
}
-/* Find where the two windows are most alike over the overlap period. */
-static size_t stretch_best_overlap_position(Stretch * p, float const * new_win)
+/* Find where the two segments are most alike over the overlap period. */
+static size_t tempo_best_overlap_position(tempo_t * t, float const * new_win)
{
- float * f = p->prev_win_end;
- size_t j, best_pos, prev_best_pos = (p->seek + 1) >> 1, step = 64;
- size_t i = best_pos = p->quick_seek? prev_best_pos : 0;
- double diff, least_diff = difference(new_win + p->channels * i, f, p->channels * p->overlap);
+ float * f = t->overlap_buf;
+ size_t j, best_pos, prev_best_pos = (t->search + 1) >> 1, step = 64;
+ size_t i = best_pos = t->quick_search? prev_best_pos : 0;
+ float diff, least_diff = difference(new_win + t->channels * i, f, t->channels * t->overlap);
int k = 0;
- if (p->quick_seek) do { /* hierarchical search */
+ if (t->quick_search) do { /* hierarchical search */
for (k = -1; k <= 1; k += 2) for (j = 1; j < 4 || step == 64; ++j) {
i = prev_best_pos + k * j * step;
- if ((int)i < 0 || i >= p->seek)
+ if ((int)i < 0 || i >= t->search)
break;
- diff = difference(new_win + p->channels * i, f, p->channels * p->overlap);
+ diff = difference(new_win + t->channels * i, f, t->channels * t->overlap);
if (diff < least_diff)
least_diff = diff, best_pos = i;
}
prev_best_pos = best_pos;
} while (step >>= 2);
- else for (i = 1; i < p->seek; i++) { /* linear search */
- diff = difference(new_win + p->channels * i, f, p->channels * p->overlap);
+ else for (i = 1; i < t->search; i++) { /* linear search */
+ diff = difference(new_win + t->channels * i, f, t->channels * t->overlap);
if (diff < least_diff)
least_diff = diff, best_pos = i;
}
@@ -174,134 +177,125 @@
return best_pos;
}
-/* For the Over-Lap bit of WSOLA */
-static void stretch_overlap(Stretch * p, const float * in1, const float * in2, float * output)
+/* For the Over-Lap part of WSOLA */
+static void tempo_overlap(
+ tempo_t * t, const float * in1, const float * in2, float * output)
{
size_t i, j, k = 0;
- float fade_step = 1.0f / (float) p->overlap;
+ float fade_step = 1.0f / (float) t->overlap;
- for (i = 0; i < p->overlap; ++i) {
+ for (i = 0; i < t->overlap; ++i) {
float fade_in = fade_step * (float) i;
float fade_out = 1.0f - fade_in;
- for (j = 0; j < p->channels; ++j, ++k)
+ for (j = 0; j < t->channels; ++j, ++k)
output[k] = in1[k] * fade_out + in2[k] * fade_in;
}
}
-static void stretch_process_windows(Stretch * p)
+static void tempo_process(tempo_t * t)
{
- while (fifo_occupancy(&p->input_fifo) >= p->process_size) {
+ while (fifo_occupancy(&t->input_fifo) >= t->process_size) {
size_t skip, offset = 0;
/* Copy or overlap the first bit to the output */
- if (!p->windows_total)
- fifo_write(&p->output_fifo, p->overlap, fifo_read_ptr(&p->input_fifo));
+ if (!t->segments_total)
+ fifo_write(&t->output_fifo, t->overlap, fifo_read_ptr(&t->input_fifo));
else {
- offset = stretch_best_overlap_position(p, fifo_read_ptr(&p->input_fifo));
- stretch_overlap(p, p->prev_win_end,
- (float *) fifo_read_ptr(&p->input_fifo) + p->channels * offset,
- fifo_write(&p->output_fifo, p->overlap, NULL));
+ offset = tempo_best_overlap_position(t, fifo_read_ptr(&t->input_fifo));
+ tempo_overlap(t, t->overlap_buf,
+ (float *) fifo_read_ptr(&t->input_fifo) + t->channels * offset,
+ fifo_write(&t->output_fifo, t->overlap, NULL));
}
/* Copy the middle bit to the output */
- if (p->window > 2 * p->overlap)
- fifo_write(&p->output_fifo, p->window - 2 * p->overlap,
- (float *) fifo_read_ptr(&p->input_fifo) +
- p->channels * (offset + p->overlap));
+ if (t->segment > 2 * t->overlap)
+ fifo_write(&t->output_fifo, t->segment - 2 * t->overlap,
+ (float *) fifo_read_ptr(&t->input_fifo) +
+ t->channels * (offset + t->overlap));
- /* Copy the end bit to prev_win_end ready to be mixed with
- * the beginning of the next window. */
- assert(offset + p->window <= fifo_occupancy(&p->input_fifo));
- memcpy(p->prev_win_end,
- (float *) fifo_read_ptr(&p->input_fifo) +
- p->channels * (offset + p->window - p->overlap),
- p->channels * p->overlap * sizeof(*(p->prev_win_end)));
+ /* Copy the end bit to overlap_buf ready to be mixed with
+ * the beginning of the next segment. */
+ memcpy(t->overlap_buf,
+ (float *) fifo_read_ptr(&t->input_fifo) +
+ t->channels * (offset + t->segment - t->overlap),
+ t->channels * t->overlap * sizeof(*(t->overlap_buf)));
- /* The Advance bit of WSOLA */
- skip = p->factor * (++p->windows_total * (p->window - p->overlap)) + 0.5;
- skip -= (p->seek + 1) >> 1; /* So seek straddles the nominal skip point. */
- p->skip_total += skip -= p->skip_total;
- fifo_read(&p->input_fifo, skip, NULL);
-
- sox_debug("%3u %u", offset, skip);
+ /* The Advance part of WSOLA */
+ skip = t->factor * (++t->segments_total * (t->segment - t->overlap)) + 0.5;
+ skip -= (t->search + 1) >> 1; /* So search straddles nominal skip point. */
+ t->skip_total += skip -= t->skip_total;
+ fifo_read(&t->input_fifo, skip, NULL);
}
}
-static void stretch_setup(Stretch * p,
- double sample_rate,
- double factor, /* 1 for no change, < 1 for slower, > 1 for faster. */
- double window_ms, /* Processing window length in milliseconds. */
- double seek_ms, /* Milliseconds to seek for the best overlap position. */
- double overlap_ms, /* Overlap length in milliseconds. */
- sox_bool quick_seek)/* Whether to quick seek for the best overlap position.*/
+static float * tempo_input(tempo_t * t, float const * samples, size_t n)
{
- size_t max_skip;
-
- p->factor = factor;
- p->window = sample_rate * window_ms / 1000 + .5;
- p->seek = sample_rate * seek_ms / 1000 + .5;
- p->overlap = max(sample_rate * overlap_ms / 1000 + 4.5, 16);
- p->overlap &= ~7; /* must be divisible by 8 */
- p->prev_win_end = xmalloc(p->overlap * p->channels * sizeof(*p->prev_win_end));
- p->quick_seek = quick_seek;
-
- /* # of samples needed in input fifo to process a window */
- max_skip = ceil(factor * (p->window - p->overlap));
- p->process_size = max(max_skip + p->overlap, p->window) + p->seek;
+ t->samples_in += n;
+ return fifo_write(&t->input_fifo, n, samples);
}
-static float * stretch_input(Stretch * p, float const *samples, size_t n)
+static float const * tempo_output(tempo_t * t, float * samples, size_t * n)
{
- p->samples_in += n;
- return fifo_write(&p->input_fifo, n, samples);
+ t->samples_out += *n = min(*n, fifo_occupancy(&t->output_fifo));
+ return fifo_read(&t->output_fifo, *n, samples);
}
-static float const * stretch_output(
- Stretch * p, float * samples, size_t * n)
+/* Flush samples remaining in overlap_buf & input_fifo to the output. */
+static void tempo_flush(tempo_t * t)
{
- p->samples_out += *n = min(*n, fifo_occupancy(&p->output_fifo));
- return fifo_read(&p->output_fifo, *n, samples);
-}
+ size_t samples_out = t->samples_in / t->factor + .5;
+ size_t remaining = samples_out - t->samples_out;
+ float * buff = xcalloc(128 * t->channels, sizeof(*buff));
-/* Flush samples remaining in the processing pipeline to the output. */
-static void stretch_flush(Stretch * p)
-{
- size_t samples_out = p->samples_in / p->factor + .5;
-
- if (p->samples_out < samples_out) {
- size_t remaining = p->samples_in / p->factor + .5 - p->samples_out;
- float * buff = xcalloc(128 * p->channels, sizeof(*buff));
-
- while (fifo_occupancy(&p->output_fifo) < remaining) {
- stretch_input(p, buff, 128);
- stretch_process_windows(p);
+ if ((int)remaining > 0) {
+ while (fifo_occupancy(&t->output_fifo) < remaining) {
+ tempo_input(t, buff, 128);
+ tempo_process(t);
}
- free(buff);
- fifo_trim(&p->output_fifo, remaining);
- p->samples_in = 0;
+ fifo_trim(&t->output_fifo, remaining);
+ t->samples_in = 0;
}
+ free(buff);
}
-static void stretch_delete(Stretch * p)
+static void tempo_setup(tempo_t * t,
+ double sample_rate, sox_bool quick_search, double factor,
+ double segment_ms, double search_ms, double overlap_ms)
{
- free(p->prev_win_end);
- fifo_delete(&p->output_fifo);
- fifo_delete(&p->input_fifo);
- free(p);
+ size_t max_skip;
+ t->quick_search = quick_search;
+ t->factor = factor;
+ t->segment = sample_rate * segment_ms / 1000 + .5;
+ t->search = sample_rate * search_ms / 1000 + .5;
+ t->overlap = max(sample_rate * overlap_ms / 1000 + 4.5, 16);
+ t->overlap &= ~7; /* Make divisible by 8 for loop optimisation */
+ t->overlap_buf = xmalloc(t->overlap * t->channels * sizeof(*t->overlap_buf));
+ max_skip = ceil(factor * (t->segment - t->overlap));
+ t->process_size = max(max_skip + t->overlap, t->segment) + t->search;
}
-static Stretch * stretch_new(size_t channels)
+static void tempo_delete(tempo_t * t)
{
- Stretch * p = xcalloc(1, sizeof(*p));
- p->channels = channels;
- fifo_create(&p->input_fifo, p->channels * sizeof(float));
- fifo_create(&p->output_fifo, p->channels * sizeof(float));
- return p;
+ free(t->overlap_buf);
+ fifo_delete(&t->output_fifo);
+ fifo_delete(&t->input_fifo);
+ free(t);
}
+static tempo_t * tempo_create(size_t channels)
+{
+ tempo_t * t = xcalloc(1, sizeof(*t));
+ t->channels = channels;
+ fifo_create(&t->input_fifo, t->channels * sizeof(float));
+ fifo_create(&t->output_fifo, t->channels * sizeof(float));
+ return t;
+}
+
+/*------------------------------- SoX Wrapper --------------------------------*/
+
typedef struct tempo {
- Stretch * stretch;
- sox_bool quick_seek;
- double factor, window_ms, seek_ms, overlap_ms;
+ tempo_t * tempo;
+ sox_bool quick_search;
+ double factor, segment_ms, search_ms, overlap_ms;
} priv_t;
assert_static(sizeof(struct tempo) <= SOX_MAX_EFFECT_PRIVSIZE,
@@ -311,18 +305,19 @@
{
priv_t * p = (priv_t *) effp->priv;
- p->window_ms = 82; /* Set non-zero defaults: */
- p->seek_ms = 14;
- p->overlap_ms = 12;
+ p->segment_ms = 82; /* Set non-zero defaults: */
+ p->search_ms = 14;
+ p->overlap_ms = 12;
- p->quick_seek = argc && !strcmp(*argv, "-q") && (--argc, ++argv, sox_true);
+ p->quick_search = argc && !strcmp(*argv, "-q") && (--argc, ++argv, sox_true);
do { /* break-able block */
NUMERIC_PARAMETER(factor ,0.25, 4 )
- NUMERIC_PARAMETER(window_ms , 10 , 120)
- NUMERIC_PARAMETER(seek_ms , 3 , 28 )
- NUMERIC_PARAMETER(overlap_ms , 2 , 24 )
+ NUMERIC_PARAMETER(segment_ms , 10 , 120)
+ NUMERIC_PARAMETER(search_ms , 0 , 30 )
+ NUMERIC_PARAMETER(overlap_ms , 0 , 30 )
} while (0);
- return argc || !p->factor || p->overlap_ms + p->seek_ms >= p->window_ms ?
+
+ return argc || !p->factor || p->overlap_ms + p->search_ms >= p->segment_ms ?
sox_usage(effp) : SOX_SUCCESS;
}
@@ -332,9 +327,10 @@
if (p->factor == 1)
return SOX_EFF_NULL;
- p->stretch = stretch_new(effp->ininfo.channels);
- stretch_setup(p->stretch, effp->ininfo.rate, p->factor, p->window_ms,
- p->seek_ms, p->overlap_ms, p->quick_seek);
+
+ p->tempo = tempo_create(effp->ininfo.channels);
+ tempo_setup(p->tempo, effp->ininfo.rate, p->quick_search, p->factor,
+ p->segment_ms, p->search_ms, p->overlap_ms);
return SOX_SUCCESS;
}
@@ -342,18 +338,17 @@
sox_ssample_t * obuf, sox_size_t * isamp, sox_size_t * osamp)
{
priv_t * p = (priv_t *) effp->priv;
- sox_size_t i;
- sox_size_t odone = *osamp /= effp->ininfo.channels;
- float const * s = stretch_output(p->stretch, NULL, &odone);
+ sox_size_t i, odone = *osamp /= effp->ininfo.channels;
+ float const * s = tempo_output(p->tempo, NULL, &odone);
for (i = 0; i < odone * effp->ininfo.channels; ++i)
*obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(*s++, effp->clips);
if (*isamp && odone < *osamp) {
- float * t = stretch_input(p->stretch, NULL, *isamp / effp->ininfo.channels);
+ float * t = tempo_input(p->tempo, NULL, *isamp / effp->ininfo.channels);
for (i = *isamp; i; --i)
*t++ = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
- stretch_process_windows(p->stretch);
+ tempo_process(p->tempo);
}
else *isamp = 0;
@@ -364,13 +359,13 @@
static int drain(sox_effect_t * effp, sox_ssample_t * obuf, sox_size_t * osamp)
{
static sox_size_t isamp = 0;
- stretch_flush(((priv_t *)effp->priv)->stretch);
+ tempo_flush(((priv_t *)effp->priv)->tempo);
return flow(effp, 0, obuf, &isamp, osamp);
}
static int stop(sox_effect_t * effp)
{
- stretch_delete(((priv_t *)effp->priv)->stretch);
+ tempo_delete(((priv_t *)effp->priv)->tempo);
return SOX_SUCCESS;
}
@@ -377,9 +372,8 @@
sox_effect_handler_t const * sox_tempo_effect_fn(void)
{
static sox_effect_handler_t handler = {
- "tempo", "[-q] factor [window-ms [seek-ms [overlap-ms]]]",
- SOX_EFF_MCHAN | SOX_EFF_LENGTH,
- getopts, start, flow, drain, stop, NULL
+ "tempo", "[-q] factor [segment-ms [search-ms [overlap-ms]]]",
+ SOX_EFF_MCHAN | SOX_EFF_LENGTH, getopts, start, flow, drain, stop, NULL
};
return &handler;
}