Lua add an Empty/Nil shared-pointer constructor
[ardour.git] / libs / plugins / a-reverb.lv2 / a-reverb.c
index ef7ace0ae60e8120bafac5b7f5d2a2a559b2387b..40811bdf9116537756eda1e73be5a8a0561b2f0b 100644 (file)
  * 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>
 #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 */
@@ -107,9 +117,9 @@ initReverb (b_reverb *r, const double rate)
        r->end[1][3] = 2251 + stereowidth;
 
        /* all pass filters right */
-       r->end[0][4] = 347 + stereowidth;
-       r->end[0][5] = 113 + stereowidth;
-       r->end[0][6] = 37 + stereowidth;
+       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;
@@ -161,10 +171,15 @@ reverb (b_reverb* r,
        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,
@@ -217,6 +232,11 @@ reverb (b_reverb* r,
                *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;
@@ -236,6 +256,7 @@ typedef enum {
        AR_OUTPUT1    = 3,
        AR_MIX        = 4,
        AR_ROOMSZ     = 5,
+       AR_ENABLE     = 6,
 } PortIndex;
 
 typedef struct {
@@ -246,9 +267,12 @@ typedef struct {
 
        float* mix;
        float* roomsz;
+       float* enable;
 
        float v_mix;
        float v_roomsz;
+       float srate;
+       float tau;
 
        b_reverb r;
 } AReverb;
@@ -270,6 +294,8 @@ instantiate (const LV2_Descriptor*     descriptor,
        // 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;
 }
@@ -300,6 +326,9 @@ connect_port (LV2_Handle instance,
                case AR_ROOMSZ:
                        self->roomsz = (float*)data;
                        break;
+               case AR_ENABLE:
+                       self->enable = (float*)data;
+                       break;
        }
 }
 
@@ -313,22 +342,52 @@ run (LV2_Handle instance, uint32_t n_samples)
        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] = 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;
+       } 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