From 43f8d2503c88041feacd1c718a6a95ba091249f4 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 12 Jul 2016 16:42:29 +0200 Subject: a-reverb prototype (based on setBfree b_reverb) --- libs/plugins/a-comp.lv2/a-comp.ttl.in | 2 +- libs/plugins/a-reverb.lv2/a-reverb.c | 323 ++++++++++++++++++++++++++++++ libs/plugins/a-reverb.lv2/a-reverb.ttl.in | 61 ++++++ libs/plugins/a-reverb.lv2/manifest.ttl.in | 7 + libs/plugins/a-reverb.lv2/wscript | 51 +++++ wscript | 1 + 6 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 libs/plugins/a-reverb.lv2/a-reverb.c create mode 100644 libs/plugins/a-reverb.lv2/a-reverb.ttl.in create mode 100644 libs/plugins/a-reverb.lv2/manifest.ttl.in create mode 100644 libs/plugins/a-reverb.lv2/wscript diff --git a/libs/plugins/a-comp.lv2/a-comp.ttl.in b/libs/plugins/a-comp.lv2/a-comp.ttl.in index f89c60e29e..312d0b222f 100644 --- a/libs/plugins/a-comp.lv2/a-comp.ttl.in +++ b/libs/plugins/a-comp.lv2/a-comp.ttl.in @@ -137,7 +137,7 @@ A powerful mono compressor. """ ; doap:name "a-Compressor" ; - doap:license "GPL v2+" ; + doap:license ; doap:maintainer # ui: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 index 0000000000..ed3b80fb66 --- /dev/null +++ b/libs/plugins/a-reverb.lv2/a-reverb.c @@ -0,0 +1,323 @@ +/* a-reverb -- based on b_reverb (setBfree) + * + * Copyright (C) 2003-2004 Fredrik Kilander + * Copyright (C) 2008-2016 Robin Gareus + * Copyright (C) 2012 Will Panther + * + * 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 . + */ + +#include +#include +#include +#include +#include + +#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 index 0000000000..9ff6801d15 --- /dev/null +++ b/libs/plugins/a-reverb.lv2/a-reverb.ttl.in @@ -0,0 +1,61 @@ +@prefix doap: . +@prefix foaf: . +@prefix lv2: . +@prefix mod: . +@prefix rdf: . +@prefix rdfs: . + + + a foaf:Person ; + foaf:name "Ardour Team" ; + foaf:homepage . + + + a doap:Project, lv2:Plugin, lv2:SpatialPlugin ; + + doap:name "A-Reverb"; + rdfs:comment "A Schroeder Reverberator" + + doap:maintainer + doap:license ; + + 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 index 0000000000..c685139932 --- /dev/null +++ b/libs/plugins/a-reverb.lv2/manifest.ttl.in @@ -0,0 +1,7 @@ +@prefix lv2: . +@prefix rdfs: . + + + a lv2:Plugin ; + lv2:binary ; + rdfs:seeAlso . diff --git a/libs/plugins/a-reverb.lv2/wscript b/libs/plugins/a-reverb.lv2/wscript new file mode 100644 index 0000000000..35601f2179 --- /dev/null +++ b/libs/plugins/a-reverb.lv2/wscript @@ -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 5678609811..fce1359b04 100644 --- 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', -- cgit v1.2.3