* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE // needed for M_PI
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
-#define RV_NZ (8+4)
+#define RV_NZ 7
#define DENORMAL_PROTECT (1e-14)
+#ifdef COMPILER_MSVC
+#include <float.h>
+#define isfinite_local(val) (bool)_finite((double)val)
+#else
+#define isfinite_local isfinite
+#endif
typedef struct {
float* delays[2][RV_NZ]; /**< delay line buffer */
static int
setReverbPointers (b_reverb *r, int i, int c, const double rate)
{
- int e = (r->end[c][i] * rate / 44100.0);
+ int e = (r->end[c][i] * rate / 25000.0);
e = e | 1;
r->delays[c][i] = (float*)realloc ((void*)r->delays[c][i], (e + 2) * sizeof (float));
if (!r->delays[c][i]) {
r->dry = 0.7;
/* feedback combfilter */
- r->gain[0] = 0.75;
- r->gain[1] = 0.75;
- r->gain[2] = 0.75;
- r->gain[3] = 0.75;
- r->gain[4] = 0.75;
- r->gain[5] = 0.75;
- r->gain[6] = 0.75;
- r->gain[7] = 0.75;
+ r->gain[0] = 0.773;
+ r->gain[1] = 0.802;
+ r->gain[2] = 0.753;
+ r->gain[3] = 0.733;
/* all-pass filter */
- r->gain[8] = 0.5;
- r->gain[9] = 0.5;
- r->gain[10] = 0.5;
- r->gain[11] = 0.5;
+ r->gain[4] = sqrtf (0.5);
+ r->gain[5] = sqrtf (0.5);
+ r->gain[6] = sqrtf (0.5);
/* delay lines left */
- r->end[0][0] = 1116;
- r->end[0][1] = 1188;
- r->end[0][2] = 1277;
- r->end[0][3] = 1356;
- r->end[0][4] = 1422;
- r->end[0][5] = 1491;
- r->end[0][6] = 1557;
- r->end[0][7] = 1617;
+ r->end[0][0] = 1687;
+ r->end[0][1] = 1601;
+ r->end[0][2] = 2053;
+ r->end[0][3] = 2251;
/* all pass filters left */
- r->end[0][8] = 556;
- r->end[0][9] = 441;
- r->end[0][10] = 341;
- r->end[0][11] = 225;
+ r->end[0][4] = 347;
+ r->end[0][5] = 113;
+ r->end[0][6] = 37;
/* delay lines right */
- r->end[1][0] = 1116 + stereowidth;
- r->end[1][1] = 1188 + stereowidth;
- r->end[1][2] = 1277 + stereowidth;
- r->end[1][3] = 1356 + stereowidth;
- r->end[1][4] = 1422 + stereowidth;
- r->end[1][5] = 1491 + stereowidth;
- r->end[1][6] = 1557 + stereowidth;
- r->end[1][7] = 1617 + stereowidth;
-
- /* all pass filters */
- r->end[1][8] = 556 + stereowidth;
- r->end[1][9] = 441 + stereowidth;
- r->end[1][10] = 341 + stereowidth;
- r->end[1][11] = 225 + stereowidth;
+ r->end[1][0] = 1687 + stereowidth;
+ r->end[1][1] = 1601 + stereowidth;
+ r->end[1][2] = 2053 + stereowidth;
+ r->end[1][3] = 2251 + stereowidth;
+
+ /* all pass filters right */
+ r->end[1][4] = 347 + stereowidth;
+ r->end[1][5] = 113 + stereowidth;
+ r->end[1][6] = 37 + stereowidth;
for (int i = 0; i < RV_NZ; ++i) {
r->delays[0][i] = NULL;
for (size_t i = 0; i < n_samples; ++i) {
int j;
float y;
- const float xo0 = *xp0++;
- const float xo1 = *xp1++;
+ float xo0 = *xp0++;
+ float xo1 = *xp1++;
+ if (!isfinite_local(xo0) || fabsf (xo0) > 10.f) { xo0 = 0; }
+ if (!isfinite_local(xo1) || fabsf (xo1) > 10.f) { xo1 = 0; }
+ xo0 += DENORMAL_PROTECT;
+ xo1 += DENORMAL_PROTECT;
const float x0 = y_1_0 + (inputGain * xo0);
const float x1 = y_1_1 + (inputGain * xo1);
+
float xa = 0.0;
float xb = 0.0;
/* First we do four feedback comb filters (ie parallel delay lines,
* each with a single tap at the end that feeds back at the start) */
- for (j = 0; j < 8; ++j) {
+ for (j = 0; j < 4; ++j) {
y = *idxp0[j];
*idxp0[j] = x0 + (gain[j] * y);
if (endp0[j] <= ++(idxp0[j])) {
}
xa += y;
}
- for (; j < 12; ++j) {
+ for (; j < 7; ++j) {
y = *idxp0[j];
*idxp0[j] = gain[j] * (xa + y);
if (endp0[j] <= ++(idxp0[j])) {
*yp0++ = ((wet * y) + (dry * xo0));
- for (j = 0; j < 8; ++j) {
+ for (j = 0; j < 4; ++j) {
y = *idxp1[j];
*idxp1[j] = x1 + (gain[j] * y);
if (endp1[j] <= ++(idxp1[j])) {
}
xb += y;
}
- for (; j < 12; ++j) {
+ for (; j < 7; ++j) {
y = *idxp1[j];
*idxp1[j] = gain[j] * (xb + y);
if (endp1[j] <= ++(idxp1[j])) {
*yp1++ = ((wet * y) + (dry * xo1));
}
+ if (!isfinite_local(y_1_0)) { y_1_0 = 0; }
+ if (!isfinite_local(yy1_1)) { yy1_0 = 0; }
+ if (!isfinite_local(y_1_1)) { y_1_1 = 0; }
+ if (!isfinite_local(yy1_1)) { yy1_1 = 0; }
+
r->y_1_0 = y_1_0 + DENORMAL_PROTECT;
r->yy1_0 = yy1_0 + DENORMAL_PROTECT;
r->y_1_1 = y_1_1 + DENORMAL_PROTECT;
AR_OUTPUT1 = 3,
AR_MIX = 4,
AR_ROOMSZ = 5,
+ AR_ENABLE = 6,
} PortIndex;
typedef struct {
float* mix;
float* roomsz;
+ float* enable;
float v_mix;
float v_roomsz;
+ float srate;
+ float tau;
b_reverb r;
} AReverb;
// these are set in initReverb()
self->v_roomsz = 0.75;
self->v_mix = 0.1;
+ self->srate = rate;
+ self->tau = 1.f - expf (-2.f * M_PI * 64.f * 15.f / self->srate); // 15Hz, 64fpp
return (LV2_Handle)self;
}
case AR_ROOMSZ:
self->roomsz = (float*)data;
break;
+ case AR_ENABLE:
+ self->enable = (float*)data;
+ break;
}
}
float* const output0 = self->output0;
float* const output1 = self->output1;
- // TODO interpolate
- if (*self->mix != self->v_mix) {
- self->v_mix = *self->mix;
- const float u = self->r.wet + self->r.dry;
- self->r.wet = self->v_mix * u;
- self->r.dry = u - (self->v_mix * u);
+ const float tau = self->tau;
+ const float mix = *self->enable <= 0 ? 0 : *self->mix;
+
+ uint32_t remain = n_samples;
+ uint32_t offset = 0;
+ uint32_t iterpolate = 0;
+
+ if (fabsf (mix - self->v_mix) < .01) { // 40dB
+ self->v_mix = mix;
+ } else {
+ iterpolate |= 1;
}
- if (*self->roomsz != self->v_roomsz) {
+
+ if (fabsf (*self->roomsz - self->v_roomsz) < .01) {
self->v_roomsz = *self->roomsz;
- self->r.gain[0] = self->v_roomsz;
- self->r.gain[1] = self->v_roomsz;
- self->r.gain[2] = self->v_roomsz;
- self->r.gain[3] = self->v_roomsz;
- self->r.gain[4] = self->v_roomsz;
- self->r.gain[5] = self->v_roomsz;
- self->r.gain[6] = self->v_roomsz;
- self->r.gain[7] = self->v_roomsz;
+ } else {
+ iterpolate |= 2;
}
- reverb (&self->r, input0, input1, output0, output1, n_samples);
+ while (remain > 0) {
+ uint32_t p_samples = remain;
+ if (iterpolate && p_samples > 64) {
+ p_samples = 64;
+ }
+
+ if (iterpolate & 1) {
+ self->v_mix += tau * (mix - self->v_mix);
+ self->r.wet = self->v_mix;
+ self->r.dry = 1.0 - self->v_mix;
+ }
+ if (iterpolate & 2) {
+ self->v_roomsz += tau * ( *self->roomsz - self->v_roomsz);
+ self->r.gain[0] = 0.773 * self->v_roomsz;
+ self->r.gain[1] = 0.802 * self->v_roomsz;
+ self->r.gain[2] = 0.753 * self->v_roomsz;
+ self->r.gain[3] = 0.733 * self->v_roomsz;
+ }
+
+ reverb (&self->r,
+ &input0[offset], &input1[offset],
+ &output0[offset], &output1[offset],
+ p_samples);
+
+ offset += p_samples;
+ remain -= p_samples;
+ }
}
static void