ref: 044d22262482cd9636ad09c2f3183ffe4704cfc2
parent: 16513db1028ccb290fb73509675cf4cf92f4da70
author: robs <robs>
date: Fri Oct 26 15:30:44 EDT 2007
clean-up and optimisation
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -190,7 +190,7 @@
libsfx_la_SOURCES = band.h biquad.c biquad.h biquads.c chorus.c compand.c \
compandt.c compandt.h dcshift.c dither.c earwax.c echo.c echos.c \
- effects.c effects.h fade.c FFT.c FFT.h filter.c flanger.c key.c \
+ effects.c effects.h fade.c FFT.c FFT.h fifo.h filter.c flanger.c key.c \
ladspa.c mcompand.c mixer.c noiseprof.c noisered.c noisered.h pad.c \
pan.c phaser.c pitch.c polyphas.c rabbit.c rate.c repeat.c \
resample.c reverb.c reverse.c silence.c skeleff.c speed.c \
--- /dev/null
+++ b/src/fifo.h
@@ -1,0 +1,109 @@
+#ifndef fifo_included
+#define fifo_included
+/*
+ * Addressible FIFO buffer Copyright (c) 2007 robs@users.sourceforge.net
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
+ */
+
+#include <string.h>
+
+typedef struct {
+ char * data;
+ size_t allocation; /* Number of bytes allocated for data. */
+ size_t item_size; /* Size of each item in data */
+ size_t begin; /* Offset of the first byte to read. */
+ size_t end; /* 1 + Offset of the last byte byte to read. */
+} fifo_t;
+
+#define FIFO_MIN 0x4000
+
+static void fifo_clear(fifo_t * f)
+{
+ f->end = f->begin = 0;
+}
+
+static void * fifo_reserve(fifo_t * f, size_t n)
+{
+ n *= f->item_size;
+
+ if (f->begin == f->end)
+ fifo_clear(f);
+
+ while (1) {
+ if (f->end + n <= f->allocation) {
+ void *p = (char *) f->data + f->end;
+
+ f->end += n;
+ return p;
+ }
+ if (f->begin > FIFO_MIN) {
+ memmove(f->data, f->data + f->begin, f->end - f->begin);
+ f->end -= f->begin;
+ f->begin = 0;
+ continue;
+ }
+ f->allocation += n;
+ f->data = xrealloc(f->data, f->allocation);
+ }
+}
+
+static void * fifo_write(fifo_t * f, size_t n, void const * data)
+{
+ void * s = fifo_reserve(f, n);
+ if (data)
+ memcpy(s, data, n * f->item_size);
+ return s;
+}
+
+static void UNUSED fifo_trim(fifo_t * f, size_t n)
+{
+ n *= f->item_size;
+ f->end = f->begin + n;
+}
+
+static size_t UNUSED fifo_occupancy(fifo_t * f)
+{
+ return (f->end - f->begin) / f->item_size;
+}
+
+static void * fifo_read(fifo_t * f, size_t n, void * data)
+{
+ char * ret = f->data + f->begin;
+ n *= f->item_size;
+ if (n > f->end - f->begin)
+ return NULL;
+ if (data)
+ memcpy(data, ret, n);
+ f->begin += n;
+ return ret;
+}
+
+#define fifo_read_ptr(f) fifo_read(f, 0, NULL)
+
+static void fifo_delete(fifo_t * f)
+{
+ free(f->data);
+}
+
+static void fifo_create(fifo_t * f, size_t item_size)
+{
+ f->item_size = item_size;
+ f->allocation = FIFO_MIN;
+ f->data = xmalloc(f->allocation);
+ fifo_clear(f);
+}
+
+#endif
--- a/src/reverb.c
+++ b/src/reverb.c
@@ -1,6 +1,7 @@
/*
- * Effect: reverb Copyright (c) 2007 robs@users.sourceforge.net
- * Algorithm based on freeverb by Jezar @ Dreampoint.
+ * Effect: stereo reverberation
+ * Copyright (c) 2007 robs@users.sourceforge.net
+ * Filter design based on freeverb by Jezar at Dreampoint.
*
* 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
@@ -18,38 +19,37 @@
*/
#include "sox_i.h"
+#include "fifo.h"
#include "xmalloc.h"
#include <math.h>
-#include <string.h>
-#define FLOAT float
#define filter_create(p, n) (p)->ptr=Xcalloc((p)->buffer, (p)->size=(size_t)(n))
+#define filter_advance(p) if (--(p)->ptr < (p)->buffer) (p)->ptr += (p)->size
#define filter_delete(p) free((p)->buffer)
-#define ADVANCE_PTR(ptr) if (--p->ptr < p->buffer) p->ptr += p->size
typedef struct {
size_t size;
- FLOAT * buffer, * ptr;
- FLOAT store;
+ float * buffer, * ptr;
+ float store;
} filter_t;
-static FLOAT comb_process(filter_t * p, /* gcc -O2 will inline this */
- FLOAT input, FLOAT feedback, FLOAT hf_damping)
+static float comb_process(filter_t * p, /* gcc -O2 will inline this */
+ float const * input, float const * feedback, float const * hf_damping)
{
- FLOAT output = *p->ptr;
- p->store = output + (p->store - output) * hf_damping;
- *p->ptr = input + p->store * feedback;
- ADVANCE_PTR(ptr);
+ float output = *p->ptr;
+ p->store = output + (p->store - output) * *hf_damping;
+ *p->ptr = *input + p->store * *feedback;
+ filter_advance(p);
return output;
}
-static FLOAT allpass_process(filter_t * p, /* gcc -O2 will inline this */
- FLOAT input, FLOAT feedback)
+static float allpass_process(filter_t * p, /* gcc -O2 will inline this */
+ float const * input)
{
- FLOAT output = *p->ptr;
- *p->ptr = input + output * feedback;
- ADVANCE_PTR(ptr);
- return output - input;
+ float output = *p->ptr;
+ *p->ptr = *input + output * .5;
+ filter_advance(p);
+ return output - *input;
}
static const size_t /* Filter delay lengths in samples (44100Hz sample-rate) */
@@ -74,78 +74,80 @@
filter_create(&p->allpass[i], r * (allpass_lengths[i] + stereo_adjust * offset) + .5);
}
-static void filter_array_delete(filter_array_t * p)
-{
- size_t i;
-
- for (i = 0; i < array_length(allpass_lengths); ++i)
- filter_delete(&p->allpass[i]);
- for (i = 0; i < array_length(comb_lengths); ++i)
- filter_delete(&p->comb[i]);
-}
-
static void filter_array_process(filter_array_t * p,
- size_t length, FLOAT const * input, FLOAT * output,
- FLOAT feedback, FLOAT hf_damping, FLOAT gain)
+ size_t length, float const * input, float * output,
+ float const * feedback, float const * hf_damping, float const * gain)
{
while (length--) {
- FLOAT out = 0, in = *input++;
+ float out = 0, in = *input++;
size_t i = array_length(comb_lengths) - 1;
- do out += comb_process(p->comb + i, in, feedback, hf_damping);
+ do out += comb_process(p->comb + i, &in, feedback, hf_damping);
while (i--);
i = array_length(allpass_lengths) - 1;
- do out = allpass_process(p->allpass + i, out, .5f);
+ do out = allpass_process(p->allpass + i, &out);
while (i--);
- *output++ = out * gain;
+ *output++ = out * *gain;
}
}
-static const size_t block_size = 1024;
+static void filter_array_delete(filter_array_t * p)
+{
+ size_t i;
+ for (i = 0; i < array_length(allpass_lengths); ++i)
+ filter_delete(&p->allpass[i]);
+ for (i = 0; i < array_length(comb_lengths); ++i)
+ filter_delete(&p->comb[i]);
+}
+
typedef struct reverb {
- FLOAT feedback;
- FLOAT hf_damping;
- FLOAT gain;
- size_t delay, num_delay_blocks;
- FLOAT * * in, * out[2];
+ float feedback;
+ float hf_damping;
+ float gain;
+ fifo_t input_fifo;
filter_array_t chan[2];
+ float * out[2];
} reverb_t;
-static FLOAT * reverb_create(reverb_t * p, double sample_rate_Hz,
+static void reverb_create(reverb_t * p, double sample_rate_Hz,
double wet_gain_dB,
double room_scale, /* % */
double reverberance, /* % */
double hf_damping, /* % */
double pre_delay_ms,
- FLOAT * * out,
- double stereo_depth)
+ double stereo_depth,
+ size_t buffer_size,
+ float * * out)
{
- size_t i;
+ size_t i, delay = pre_delay_ms / 1000 * sample_rate_Hz + .5;
double scale = room_scale / 100 * .9 + .1;
double depth = stereo_depth / 100;
- double a, b;
+ double a = -1 / log(1 - /**/.3 /**/); /* Set minimum feedback */
+ double b = 100 / (log(1 - /**/.98/**/) * a + 1); /* Set maximum feedback */
memset(p, 0, sizeof(*p));
-
- b = -1 / log(1 - .5); a = 100 / (1 + log(1 - .98) * b); b *= a;
- p->feedback = 1 - exp((reverberance - a) / b);
+ p->feedback = 1 - exp((reverberance - b) / (a * b));
p->hf_damping = hf_damping / 100 * .3 + .2;
p->gain = exp(wet_gain_dB / 20 * log(10.)) * .015;
- p->delay = pre_delay_ms / 1000 * sample_rate_Hz + .5;
- p->num_delay_blocks = (p->delay + block_size - 1) / block_size;
- Xcalloc(p->in, 1 + p->num_delay_blocks);
- for (i = 0; i <= p->num_delay_blocks; ++i)
- Xcalloc(p->in[i], block_size);
+ fifo_create(&p->input_fifo, sizeof(float));
+ memset(fifo_write(&p->input_fifo, delay, 0), 0, delay * sizeof(float));
for (i = 0; i <= ceil(depth); ++i) {
filter_array_create(p->chan + i, sample_rate_Hz, scale, i * depth);
- out[i] = Xcalloc(p->out[i], block_size);
+ out[i] = Xcalloc(p->out[i], buffer_size);
}
- return p->in[0];
}
+static void reverb_process(reverb_t * p, size_t length)
+{
+ size_t i;
+ for (i = 0; i < 2 && p->out[i]; ++i)
+ filter_array_process(p->chan + i, length, (float *) fifo_read_ptr(&p->input_fifo), p->out[i], &p->feedback, &p->hf_damping, &p->gain);
+ fifo_read(&p->input_fifo, length, NULL);
+}
+
static void reverb_delete(reverb_t * p)
{
size_t i;
@@ -153,29 +155,9 @@
free(p->out[i]);
filter_array_delete(p->chan + i);
}
- for (i = 0; i <= p->num_delay_blocks; ++i)
- free(p->in[i]);
- free(p->in);
+ fifo_delete(&p->input_fifo);
}
-static FLOAT * reverb_process(reverb_t * p, size_t length)
-{
- FLOAT * oldest_in = p->in[p->num_delay_blocks];
- size_t len1 = p->delay % block_size;
- size_t len2 = length - len1, i;
-
- for (i = 0; i < 2 && p->out[i]; ++i) {
- FLOAT * * b = p->in + p->num_delay_blocks;
-
- if (len1)
- filter_array_process(p->chan + i, len1, *b-- + block_size - len1, p->out[i], p->feedback, p->hf_damping, p->gain);
- filter_array_process(p->chan + i, len2, *b, p->out[i] + len1, p->feedback, p->hf_damping, p->gain);
- }
- for (i = p->num_delay_blocks; i; --i)
- p->in[i] = p->in[i - 1];
- return p->in[i] = oldest_in;
-}
-
/*------------------------------- SoX Wrapper --------------------------------*/
typedef struct priv {
@@ -186,8 +168,8 @@
size_t ichannels, ochannels;
struct {
reverb_t reverb;
- FLOAT * dry, * dry1, * wet[2];
- } f[2];
+ float * dry, * wet[2];
+ } chan[2];
} priv_t;
assert_static(sizeof(struct priv) <= SOX_MAX_EFFECT_PRIVSIZE,
@@ -220,7 +202,6 @@
size_t i;
p->ichannels = p->ochannels = 1;
-
effp->outinfo.rate = effp->ininfo.rate;
if (effp->ininfo.channels > 2 && p->stereo_depth) {
sox_warn("stereo-depth not applicable with >2 channels");
@@ -232,11 +213,11 @@
if (effp->ininfo.channels == 2 && p->stereo_depth)
p->ichannels = p->ochannels = 2;
else effp->flows = effp->ininfo.channels;
- for (i = 0; i < p->ichannels; ++i)
- p->f[i].dry = reverb_create(&p->f[i].reverb, effp->ininfo.rate,
- p->wet_gain_dB, p->room_scale, p->reverberance, p->hf_damping,
- p->pre_delay_ms, p->f[i].wet, p->stereo_depth);
- return sox_effect_set_imin(effp, block_size);
+ for (i = 0; i < p->ichannels; ++i) reverb_create(
+ &p->chan[i].reverb, effp->ininfo.rate, p->wet_gain_dB, p->room_scale,
+ p->reverberance, p->hf_damping, p->pre_delay_ms, p->stereo_depth,
+ effp->global_info->global_info->bufsiz / p->ochannels, p->chan[i].wet);
+ return SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, const sox_ssample_t * ibuf,
@@ -243,31 +224,24 @@
sox_ssample_t * obuf, sox_size_t * isamp, sox_size_t * osamp)
{
priv_t * p = (priv_t *) effp->priv;
- sox_size_t c, i, w;
+ sox_size_t c, i, w, len = min(*isamp / p->ichannels, *osamp / p->ochannels);
- if (*isamp < block_size || *osamp < block_size * p->ochannels / p->ichannels)
- *isamp = *osamp = 0;
- else {
- *osamp = (*isamp = block_size) * p->ochannels / p->ichannels;
-
- for (i = 0; i < *isamp; ++i) for (c = 0; c < p->ichannels; ++c)
- p->f[c].dry[i] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
- for (c = 0; c < p->ichannels; ++c) {
- p->f[c].dry1 = p->f[c].dry;
- p->f[c].dry = reverb_process(&p->f[c].reverb, *isamp / p->ichannels);
- }
- if (p->ichannels == 2)
- for (i = 0; i < *isamp; ++i) for (w = 0; w < 2; ++w) {
- FLOAT x = (1 - p->wet_only) * p->f[w].dry1[i] + .5 *
- (p->f[0].wet[w][i] + p->f[1].wet[w][i]);
- *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(x, effp->clips);
- }
- else
- for (i = 0; i < *isamp; ++i) for (w = 0; w < min(2, p->ochannels); ++w) {
- FLOAT x = (1 - p->wet_only) * p->f[0].dry1[i] + p->f[0].wet[w][i];
- *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(x, effp->clips);
- }
+ *isamp = len * p->ichannels, *osamp = len * p->ochannels;
+ for (c = 0; c < p->ichannels; ++c)
+ p->chan[c].dry = fifo_write(&p->chan[c].reverb.input_fifo, len, 0);
+ for (i = 0; i < len; ++i) for (c = 0; c < p->ichannels; ++c)
+ p->chan[c].dry[i] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
+ for (c = 0; c < p->ichannels; ++c)
+ reverb_process(&p->chan[c].reverb, len);
+ if (p->ichannels == 2) for (i = 0; i < len; ++i) for (w = 0; w < 2; ++w) {
+ float out = (1 - p->wet_only) * p->chan[w].dry[i] +
+ .5 * (p->chan[0].wet[w][i] + p->chan[1].wet[w][i]);
+ *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(out, effp->clips);
}
+ else for (i = 0; i < len; ++i) for (w = 0; w < p->ochannels; ++w) {
+ float out = (1 - p->wet_only) * p->chan[0].dry[i] + p->chan[0].wet[w][i];
+ *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(out, effp->clips);
+ }
return SOX_SUCCESS;
}
@@ -276,7 +250,7 @@
priv_t * p = (priv_t *) effp->priv;
size_t i;
for (i = 0; i < p->ichannels; ++i)
- reverb_delete(&p->f[i].reverb);
+ reverb_delete(&p->chan[i].reverb);
return SOX_SUCCESS;
}
--- a/src/tempo.c
+++ b/src/tempo.c
@@ -19,100 +19,9 @@
*/
#include "sox_i.h"
+#include "fifo.h"
#include "xmalloc.h"
#include <math.h>
-#include <string.h>
-#include <assert.h>
-
-/*------------------------- Addressible FIFO buffer --------------------------*/
-
-typedef struct {
- char * data;
- size_t allocation; /* Number of bytes allocated for data. */
- size_t item_size; /* Size of each item in data */
- size_t begin; /* Offset of the first byte to read. */
- size_t end; /* 1 + Offset of the last byte byte to read. */
-} fifo_t;
-
-#define FIFO_MIN 0x4000
-
-static void fifo_clear(fifo_t * f)
-{
- f->end = f->begin = 0;
-}
-
-static void * fifo_reserve(fifo_t * f, size_t n)
-{
- n *= f->item_size;
-
- if (f->begin == f->end)
- fifo_clear(f);
-
- while (1) {
- if (f->end + n <= f->allocation) {
- void *p = (char *) f->data + f->end;
-
- f->end += n;
- return p;
- }
- if (f->begin > FIFO_MIN) {
- memmove(f->data, f->data + f->begin, f->end - f->begin);
- f->end -= f->begin;
- f->begin = 0;
- continue;
- }
- f->allocation += n;
- f->data = xrealloc(f->data, f->allocation);
- }
-}
-
-static void * fifo_write(fifo_t * f, size_t n, void const * data)
-{
- void * s = fifo_reserve(f, n);
- if (data)
- memcpy(s, data, n * f->item_size);
- return s;
-}
-
-static void fifo_trim(fifo_t * f, size_t n)
-{
- n *= f->item_size;
- f->end = f->begin + n;
-}
-
-static size_t fifo_occupancy(fifo_t * f)
-{
- return (f->end - f->begin) / f->item_size;
-}
-
-static void * fifo_read(fifo_t * f, size_t n, void * data)
-{
- char * ret = f->data + f->begin;
- n *= f->item_size;
- if (n > f->end - f->begin)
- return NULL;
- if (data)
- memcpy(data, ret, n);
- f->begin += n;
- return ret;
-}
-
-#define fifo_read_ptr(f) fifo_read(f, 0, NULL)
-
-static void fifo_delete(fifo_t * f)
-{
- free(f->data);
-}
-
-static void fifo_create(fifo_t * f, size_t item_size)
-{
- f->item_size = item_size;
- f->allocation = FIFO_MIN;
- f->data = xmalloc(f->allocation);
- fifo_clear(f);
-}
-
-/*---------------------------- WSOLA Tempo Change ----------------------------*/
typedef struct {
/* Configuration parameters: */