/* vcf303.cpp VCF 303 - TB-303 Resonant Filter Copyright (c) 1998 Andy Sloane Copyright (c) 1999, 2000 David A. Bartold Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) 2000 Richard W.E. Furse. The author may be contacted at richard@muse.demon.co.uk. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public Licence as published by the Free Software Foundation; either version 2 of the Licence, 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ /*****************************************************************************/ #include #include #include "cmt.h" #define PORT_IN 0 #define PORT_OUT 1 #define PORT_TRIGGER 2 #define PORT_CUTOFF 3 #define PORT_RESONANCE 4 #define PORT_ENV_MOD 5 #define PORT_DECAY 6 #define NUM_PORTS 7 #ifndef PI #define PI 3.14159265358979 #endif class Vcf303 : public CMT_PluginInstance { LADSPA_Data sample_rate; LADSPA_Data d1, d2, c0; int last_trigger; int envpos; public: Vcf303(const LADSPA_Descriptor *, unsigned long s_rate) : CMT_PluginInstance(NUM_PORTS), sample_rate(s_rate), d1(0.0), d2(0.0), c0(0.0), last_trigger(0), envpos(0) { } ~Vcf303() { } static void activate(LADSPA_Handle Instance) { Vcf303 *vcf303 = (Vcf303*) Instance; vcf303->d1 = 0.0; vcf303->d2 = 0.0; vcf303->c0 = 0.0; vcf303->last_trigger = 0; vcf303->envpos = 0; } static inline void recalc_a_b_c (Vcf303 *filter, LADSPA_Data e0, LADSPA_Data c0, LADSPA_Data resonance, LADSPA_Data *a, LADSPA_Data *b, LADSPA_Data *c) { LADSPA_Data whopping, k; whopping = e0 + c0; k = exp (-whopping / resonance); *a = 2.0 * cos (2.0 * whopping) * k; *b = -k * k; *c = (1.0 - *a - *b) * 0.2; } static void run(LADSPA_Handle Instance, unsigned long SampleCount) { Vcf303 *vcf303 = (Vcf303*) Instance; unsigned long i; LADSPA_Data e0, d, a, b, c; LADSPA_Data decay, resonance; LADSPA_Data **ports; int trigger; /* Update vars given envmod, cutoff, and reso. */ ports = vcf303->m_ppfPorts; e0 = exp (5.613 - 0.8 * *ports[PORT_ENV_MOD] + 2.1553 * *ports[PORT_CUTOFF] - 0.7696 * (1.0 - *ports[PORT_RESONANCE])); e0 *= PI / vcf303->sample_rate; trigger = (*ports[PORT_TRIGGER] > 0.0); if (trigger == 1 && vcf303->last_trigger == 0) { LADSPA_Data e1; e1 = exp (6.109 + 1.5876 * *ports[PORT_ENV_MOD] + 2.1553 * *ports[PORT_CUTOFF] - 1.2 * (1.0 - *ports[PORT_RESONANCE])); e1 *= PI / vcf303->sample_rate; vcf303->c0 = e1 - e0; } vcf303->last_trigger = trigger; /* Update decay given envdecay. */ d = 0.2 + (2.3 * *ports[PORT_DECAY]); d *= vcf303->sample_rate; d = pow (0.1, 1.0 / d); decay = pow (d, 64); /* Update resonance. */ resonance = exp (-1.20 + 3.455 * *ports[PORT_RESONANCE]); recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c); for (i = 0; i < SampleCount; i++) { LADSPA_Data sample; sample = a * vcf303->d1 + b * vcf303->d2 + c * ports[PORT_IN][i]; ports[PORT_OUT][i] = sample; vcf303->d2 = vcf303->d1; vcf303->d1 = sample; vcf303->envpos++; if (vcf303->envpos >= 64) { vcf303->envpos = 0; vcf303->c0 *= decay; recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c); } } } }; static LADSPA_PortDescriptor g_psPortDescriptors[] = { LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT }; static const char * const g_psPortNames[] = { "In", "Out", "Trigger", "Cutoff", "Resonance", "Envelope Modulation", "Decay" }; static LADSPA_PortRangeHint g_psPortRangeHints[] = { /* Hints, Lower bound, Upper bound */ { 0, 0.0, 0.0 }, { 0, 0.0, 0.0 }, { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 } }; void initialise_vcf303() { CMT_Descriptor * psDescriptor; psDescriptor = new CMT_Descriptor (1224, "vcf303", LADSPA_PROPERTY_HARD_RT_CAPABLE, "VCF 303", CMT_MAKER("David A. Bartold"), CMT_COPYRIGHT("1998-2000", "Andy Sloane, David A. Bartold"), NULL, CMT_Instantiate, Vcf303::activate, Vcf303::run, NULL, NULL, NULL); for (int i = 0; i < NUM_PORTS; i++) psDescriptor->addPort( g_psPortDescriptors[i], g_psPortNames[i], g_psPortRangeHints[i].HintDescriptor, g_psPortRangeHints[i].LowerBound, g_psPortRangeHints[i].UpperBound); registerNewPluginDescriptor(psDescriptor); }