a-reverb prototype (based on setBfree b_reverb)
authorRobin Gareus <robin@gareus.org>
Tue, 12 Jul 2016 14:42:29 +0000 (16:42 +0200)
committerRobin Gareus <robin@gareus.org>
Tue, 12 Jul 2016 14:43:10 +0000 (16:43 +0200)
libs/plugins/a-comp.lv2/a-comp.ttl.in
libs/plugins/a-reverb.lv2/a-reverb.c [new file with mode: 0644]
libs/plugins/a-reverb.lv2/a-reverb.ttl.in [new file with mode: 0644]
libs/plugins/a-reverb.lv2/manifest.ttl.in [new file with mode: 0644]
libs/plugins/a-reverb.lv2/wscript [new file with mode: 0644]
wscript

index f89c60e29e036a9cd9a5a715b9db2c6ae95eb287..312d0b222f63c7fd3b35bbe4f6ce593751381f07 100644 (file)
@@ -137,7 +137,7 @@ A powerful mono compressor.
 """ ;
 
     doap:name "a-Compressor" ;
-    doap:license "GPL v2+" ;
+               doap:license <http://usefulinc.com/doap/licenses/gpl> ;
     doap:maintainer <http://ardour.org/credits.html>
 
 #   ui:ui <urn:ardour:a-comp#ui>;
diff --git a/libs/plugins/a-reverb.lv2/a-reverb.c b/libs/plugins/a-reverb.lv2/a-reverb.c
new file mode 100644 (file)
index 0000000..ed3b80f
--- /dev/null
@@ -0,0 +1,323 @@
+/* a-reverb -- based on b_reverb (setBfree)
+ *
+ * Copyright (C) 2003-2004 Fredrik Kilander <fk@dsv.su.se>
+ * Copyright (C) 2008-2016 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2012 Will Panther <pantherb@setbfree.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+
+#define RV_NZ 7
+#define DENORMAL_PROTECT (1e-14)
+
+typedef struct {
+       float* delays[RV_NZ]; /**< delay line buffer */
+
+       float* idx0[RV_NZ];     /**< Reset pointer ref delays[]*/
+       float* idxp[RV_NZ];     /**< Index pointer ref delays[]*/
+       float* endp[RV_NZ];     /**< End pointer   ref delays[]*/
+
+       float gain[RV_NZ]; /**< feedback gains */
+       float yy1; /**< Previous output sample */
+       float y_1; /**< Feedback sample */
+
+       int end[RV_NZ];
+
+       float inputGain;        /**< Input gain value */
+       float fbk;      /**< Feedback gain */
+       float wet;      /**< Output dry gain */
+       float dry;      /**< Output wet gain */
+} b_reverb;
+
+static int
+setReverbPointers (b_reverb *r, int i, const double rate)
+{
+       int e = (r->end[i] * rate / 25000.0);
+       e = e | 1;
+       r->delays[i] = (float*)realloc ((void*)r->delays[i], (e + 2) * sizeof (float));
+       if (!r->delays[i]) {
+               return -1;
+       } else {
+               memset (r->delays[i], 0 , (e + 2) * sizeof (float));
+       }
+       r->endp[i] = r->delays[i] + e + 1;
+       r->idx0[i] = r->idxp[i] = &(r->delays[i][0]);
+
+       return 0;
+}
+
+static int
+initReverb (b_reverb *r, const double rate)
+{
+       int err = 0;
+       r->inputGain = 0.1; /* Input gain value */
+       r->fbk = -0.015; /* Feedback gain */
+       r->wet = 0.1; /* Output dry gain */
+       r->dry = 0.9; /* Output wet gain */
+
+       /* feedback combfilter */
+       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[4] = sqrtf (0.5);
+       r->gain[5] = sqrtf (0.5);
+       r->gain[6] = sqrtf (0.5);
+
+       /* delay lines */
+       r->end[0] = 1687;
+       r->end[1] = 1601;
+       r->end[2] = 2053;
+       r->end[3] = 2251;
+
+       /* all pass filters */
+       r->end[4] = 347;
+       r->end[5] = 113;
+       r->end[6] = 37;
+
+       for (int i = 0; i < RV_NZ; ++i) {
+               r->delays[i]= NULL;
+       }
+
+       r->yy1 = 0.0;
+       r->y_1 = 0.0;
+
+       for (int i = 0; i < RV_NZ; i++) {
+               err |= setReverbPointers (r, i, rate);
+       }
+       return err;
+}
+
+static void
+reverb (b_reverb* r,
+        const float* inbuf,
+        float* outbuf,
+        size_t n_samples)
+{
+       float** const idxp = r->idxp;
+       float* const* const endp = r->endp;
+       float* const* const idx0 = r->idx0;
+       const float* const gain = r->gain;
+       const float inputGain = r->inputGain;
+       const float fbk = r->fbk;
+       const float wet = r->wet;
+       const float dry = r->dry;
+
+       const float* xp = inbuf;
+       float* yp = outbuf;
+
+       float y_1 = r->y_1;
+       float yy1 = r->yy1;
+
+       for (size_t i = 0; i < n_samples; ++i) {
+               int j;
+               float y;
+               const float xo = *xp++;
+               const float x = y_1 + (inputGain * xo);
+               float xa = 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 < 4; ++j) {
+                       y = *idxp[j];
+                       *idxp[j] = x + (gain[j] * y);
+                       if (endp[j] <= ++(idxp[j])) {
+                               idxp[j] = idx0[j];
+                       }
+                       xa += y;
+               }
+
+               for (; j < 7; ++j) {
+                       y = *idxp[j];
+                       *idxp[j] = gain[j] * (xa + y);
+                       if (endp[j] <= ++(idxp[j])) {
+                               idxp[j] = idx0[j];
+                       }
+                       xa = y - xa;
+               }
+
+               y = 0.5f * (xa + yy1);
+               yy1 = y;
+               y_1 = fbk * xa;
+
+               *yp++ = ((wet * y) + (dry * xo));
+       }
+
+       r->y_1 = y_1 + DENORMAL_PROTECT;
+       r->yy1 = yy1 + DENORMAL_PROTECT;
+}
+
+/******************************************************************************
+ * LV2 wrapper
+ */
+
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+
+typedef enum {
+       AR_INPUT      = 0,
+       AR_OUTPUT     = 1,
+       AR_MIX        = 2,
+       AR_GAIN_IN    = 3,
+       AR_GAIN_OUT   = 4,
+} PortIndex;
+
+typedef struct {
+       float* input;
+       float* output;
+
+       float* mix;
+       float* gain_in;
+       float* gain_out; // unused
+
+       float v_mix;
+       float v_gain_in;
+
+       b_reverb r;
+} AReverb;
+
+static LV2_Handle
+instantiate (const LV2_Descriptor*     descriptor,
+             double                    rate,
+             const char*               bundle_path,
+             const LV2_Feature* const* features)
+{
+       AReverb* self = (AReverb*)calloc (1, sizeof (AReverb));
+       if (!self) {
+               return NULL;
+       }
+       if (initReverb (&self->r, rate)) {
+               return NULL;
+       }
+
+       // these are set in initReverb()
+       self->v_gain_in = -40; // [dB]
+       self->v_mix = 0.1;
+
+       return (LV2_Handle)self;
+}
+
+static void
+connect_port (LV2_Handle instance,
+              uint32_t   port,
+              void*      data)
+{
+       AReverb* self = (AReverb*)instance;
+
+       switch ((PortIndex)port) {
+               case AR_INPUT:
+                       self->input = (float*)data;
+                       break;
+               case AR_OUTPUT:
+                       self->output = (float*)data;
+                       break;
+               case AR_MIX:
+                       self->mix = (float*)data;
+                       break;
+               case AR_GAIN_IN:
+                       self->gain_in = (float*)data;
+                       break;
+               case AR_GAIN_OUT:
+                       self->gain_out = (float*)data;
+                       break;
+       }
+}
+
+static void
+run (LV2_Handle instance, uint32_t n_samples)
+{
+       AReverb* self = (AReverb*)instance;
+
+       const float* const input  = self->input;
+       float* const       output = self->output;
+
+       // 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);
+       }
+       if (*self->gain_in != self->v_gain_in) {
+               self->v_gain_in = *self->gain_in;
+               self->r.inputGain = powf (10.0, .05 * self->v_gain_in);
+       }
+       if (self->gain_out) { // unused
+               const float g = *self->gain_out;
+               const float u = self->r.wet + self->r.dry;
+               self->r.wet = g * (self->r.wet / u);
+               self->r.dry = g * (self->r.dry / u);
+       }
+
+       reverb (&self->r, input, output, n_samples);
+}
+
+static void
+activate (LV2_Handle instance)
+{
+       AReverb* self = (AReverb*)instance;
+       self->r.y_1 = 0;
+       self->r.yy1 = 0;
+}
+
+static void
+deactivate (LV2_Handle instance)
+{
+}
+
+static void
+cleanup (LV2_Handle instance)
+{
+       AReverb* self = (AReverb*)instance;
+       for (int i = 0; i < RV_NZ; ++i) {
+               free (self->r.delays[i]);
+       }
+       free (instance);
+}
+
+static const void*
+extension_data (const char* uri)
+{
+       return NULL;
+}
+
+static const LV2_Descriptor descriptor = {
+       "urn:ardour:a-reverb",
+       instantiate,
+       connect_port,
+       activate,
+       run,
+       deactivate,
+       cleanup,
+       extension_data
+};
+
+LV2_SYMBOL_EXPORT
+const LV2_Descriptor*
+lv2_descriptor (uint32_t index)
+{
+       switch (index) {
+               case 0:
+                       return &descriptor;
+               default:
+                       return NULL;
+       }
+}
diff --git a/libs/plugins/a-reverb.lv2/a-reverb.ttl.in b/libs/plugins/a-reverb.lv2/a-reverb.ttl.in
new file mode 100644 (file)
index 0000000..9ff6801
--- /dev/null
@@ -0,0 +1,61 @@
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix mod: <http://moddevices.com/ns/mod#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<http://ardour.org/credits.html>
+       a foaf:Person ;
+       foaf:name "Ardour Team" ;
+       foaf:homepage <http://ardour.org/> .
+
+<urn:ardour:a-reverb>
+       a doap:Project, lv2:Plugin, lv2:SpatialPlugin ;
+
+       doap:name "A-Reverb";
+       rdfs:comment "A Schroeder Reverberator"
+
+       doap:maintainer <http://ardour.org/credits.html>
+       doap:license <http://usefulinc.com/doap/licenses/gpl> ;
+
+       lv2:microVersion 0 ; lv2:minorVersion 1 ;
+       lv2:optionalFeature lv2:hardRTCapable ;
+
+       lv2:port
+       [
+               a lv2:AudioPort ,
+                       lv2:InputPort ;
+               lv2:index 0 ;
+               lv2:symbol "in" ;
+               lv2:name "In"
+       ],
+       [
+               a lv2:AudioPort ,
+                       lv2:OutputPort ;
+               lv2:index 1 ;
+               lv2:symbol "out" ;
+               lv2:name "Out"
+       ],
+       [
+               a lv2:InputPort ,
+                       lv2:ControlPort ;
+               lv2:index 3 ;
+               lv2:symbol "gain_in" ;
+               lv2:name "Input Gain";
+               lv2:default -30;
+               lv2:minimum -80;
+               lv2:maximum  -3;
+               unit:unit unit:db ;
+       ],
+       [
+               a lv2:InputPort ,
+                       lv2:ControlPort ;
+               lv2:index 2 ;
+               lv2:symbol "mix" ;
+               lv2:name "Dry/Wet";
+               lv2:default 0.3;
+               lv2:minimum 0.0 ;
+               lv2:maximum 1.0 ;
+       ] ;
+       .
diff --git a/libs/plugins/a-reverb.lv2/manifest.ttl.in b/libs/plugins/a-reverb.lv2/manifest.ttl.in
new file mode 100644 (file)
index 0000000..c685139
--- /dev/null
@@ -0,0 +1,7 @@
+@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<urn:ardour:a-reverb>
+       a lv2:Plugin ;
+       lv2:binary <a-reverb@LIB_EXT@>  ;
+       rdfs:seeAlso <a-reverb.ttl> .
diff --git a/libs/plugins/a-reverb.lv2/wscript b/libs/plugins/a-reverb.lv2/wscript
new file mode 100644 (file)
index 0000000..35601f2
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+import os
+import re
+import shutil
+import waflib.extras.autowaf as autowaf
+import waflib.Options as Options, waflib.Utils as Utils
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+    autowaf.set_options(opt)
+
+def configure(conf):
+    conf.load('compiler_c')
+    autowaf.configure(conf)
+    if Options.options.lv2:
+        autowaf.check_pkg(conf, 'lv2', atleast_version='1.0.0',
+                uselib_store='LV2_1_0_0')
+
+def build(bld):
+    bundle = 'a-reverb.lv2'
+    module_pat = re.sub('^lib', '', bld.env.cshlib_PATTERN)
+    module_ext = module_pat[module_pat.rfind('.'):]
+
+    if bld.is_defined ('HAVE_LV2'):
+        # Build RDF files
+        for i in ['manifest.ttl', 'a-reverb.ttl']:
+            bld(features     = 'subst',
+                source       = i + '.in',
+                target       = '../../LV2/%s/%s' % (bundle, i),
+                install_path = '${LV2DIR}/%s' % bundle,
+                chmod        = Utils.O644,
+                LIB_EXT      = module_ext)
+
+        # Build plugin library
+        obj = bld(features     = 'c cshlib',
+                  source       = 'a-reverb.c',
+                  name         = 'a-reverb',
+                  cflags       = [ '-fPIC',  bld.env['compiler_flags_dict']['c99'] ],
+                  includes     = [ '../../ardour' ],
+                  target       = '../../LV2/%s/a-reverb' % bundle,
+                  install_path = '${LV2DIR}/%s' % bundle,
+                  uselib       = 'CAIRO',
+                  use          = 'LV2_1_0_0'
+                  )
+        obj.env.cshlib_PATTERN = module_pat
+        obj.env.cxxshlib_PATTERN = module_pat
+
+# vi:set ts=4 sw=4 et:
diff --git a/wscript b/wscript
index 56786098114b367be47eedae4d79d8adbec3079b..fce1359b043dbe70e515eea17734c55298b9e2b3 100644 (file)
--- a/wscript
+++ b/wscript
@@ -222,6 +222,7 @@ children = [
         'libs/plugins/a-comp.lv2',
         'libs/plugins/a-delay.lv2',
         'libs/plugins/a-eq.lv2',
+        'libs/plugins/a-reverb.lv2',
         'gtk2_ardour',
         'export',
         'midi_maps',