1 /* vcf303.cpp
2 
3    VCF 303 - TB-303 Resonant Filter
4    Copyright (c) 1998 Andy Sloane
5    Copyright (c) 1999, 2000 David A. Bartold
6 
7    Computer Music Toolkit - a library of LADSPA plugins. Copyright (C)
8    2000 Richard W.E. Furse. The author may be contacted at
9    richard@muse.demon.co.uk.
10 
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public Licence as
13    published by the Free Software Foundation; either version 2 of the
14    Licence, or (at your option) any later version.
15 
16    This library is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this library; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24    02111-1307, USA. */
25 
26 /*****************************************************************************/
27 
28 
29 #include <stdlib.h>
30 #include <math.h>
31 #include "cmt.h"
32 
33 #define PORT_IN        0
34 #define PORT_OUT       1
35 #define PORT_TRIGGER   2
36 #define PORT_CUTOFF    3
37 #define PORT_RESONANCE 4
38 #define PORT_ENV_MOD   5
39 #define PORT_DECAY     6
40 
41 #define NUM_PORTS      7
42 
43 #ifndef PI
44 #define PI 3.14159265358979
45 #endif
46 
47 class Vcf303 : public CMT_PluginInstance {
48   LADSPA_Data sample_rate;
49 
50   LADSPA_Data d1, d2, c0;
51   int         last_trigger;
52   int         envpos;
53 
54 public:
Vcf303(const LADSPA_Descriptor *,unsigned long s_rate)55   Vcf303(const LADSPA_Descriptor *,
56          unsigned long s_rate)
57     : CMT_PluginInstance(NUM_PORTS),
58       sample_rate(s_rate),
59       d1(0.0), d2(0.0), c0(0.0),
60       last_trigger(0),
61       envpos(0) {
62   }
63 
~Vcf303()64   ~Vcf303() {
65   }
66 
67   static void
activate(LADSPA_Handle Instance)68   activate(LADSPA_Handle Instance) {
69     Vcf303 *vcf303 = (Vcf303*) Instance;
70 
71     vcf303->d1 = 0.0;
72     vcf303->d2 = 0.0;
73     vcf303->c0 = 0.0;
74     vcf303->last_trigger = 0;
75     vcf303->envpos = 0;
76   }
77 
78   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)79   recalc_a_b_c (Vcf303      *filter,
80                 LADSPA_Data  e0,
81                 LADSPA_Data  c0,
82                 LADSPA_Data  resonance,
83                 LADSPA_Data *a,
84                 LADSPA_Data *b,
85                 LADSPA_Data *c) {
86     LADSPA_Data whopping, k;
87 
88     whopping = e0 + c0;
89     k = exp (-whopping / resonance);
90 
91     *a = 2.0 * cos (2.0 * whopping) * k;
92     *b = -k * k;
93     *c = (1.0 - *a - *b) * 0.2;
94   }
95 
96   static void
run(LADSPA_Handle Instance,unsigned long SampleCount)97   run(LADSPA_Handle Instance,
98       unsigned long SampleCount) {
99     Vcf303 *vcf303 = (Vcf303*) Instance;
100     unsigned long i;
101     LADSPA_Data e0, d, a, b, c;
102     LADSPA_Data decay, resonance;
103     LADSPA_Data **ports;
104     int trigger;
105 
106     /* Update vars given envmod, cutoff, and reso. */
107     ports = vcf303->m_ppfPorts;
108     e0 = exp (5.613 - 0.8 * *ports[PORT_ENV_MOD] + 2.1553 *
109               *ports[PORT_CUTOFF] - 0.7696 * (1.0 - *ports[PORT_RESONANCE]));
110     e0 *= PI / vcf303->sample_rate;
111 
112     trigger = (*ports[PORT_TRIGGER] > 0.0);
113     if (trigger == 1 && vcf303->last_trigger == 0)
114       {
115         LADSPA_Data e1;
116 
117         e1 = exp (6.109 + 1.5876 * *ports[PORT_ENV_MOD] + 2.1553 *
118                   *ports[PORT_CUTOFF] - 1.2 * (1.0 - *ports[PORT_RESONANCE]));
119         e1 *= PI / vcf303->sample_rate;
120         vcf303->c0 = e1 - e0;
121       }
122     vcf303->last_trigger = trigger;
123 
124     /* Update decay given envdecay. */
125     d = 0.2 + (2.3 * *ports[PORT_DECAY]);
126     d *= vcf303->sample_rate;
127     d = pow (0.1, 1.0 / d);
128     decay = pow (d, 64);
129 
130     /* Update resonance. */
131     resonance = exp (-1.20 + 3.455 * *ports[PORT_RESONANCE]);
132 
133     recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c);
134 
135     for (i = 0; i < SampleCount; i++)
136       {
137         LADSPA_Data sample;
138 
139         sample = a * vcf303->d1 + b * vcf303->d2 + c * ports[PORT_IN][i];
140         ports[PORT_OUT][i] = sample;
141 
142         vcf303->d2 = vcf303->d1;
143         vcf303->d1 = sample;
144 
145         vcf303->envpos++;
146         if (vcf303->envpos >= 64)
147           {
148             vcf303->envpos = 0;
149             vcf303->c0 *= decay;
150             recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c);
151           }
152       }
153   }
154 };
155 
156 
157 static LADSPA_PortDescriptor g_psPortDescriptors[] =
158 {
159   LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT,
160   LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT,
161   LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
162   LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
163   LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
164   LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
165   LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT
166 };
167 
168 static const char * const g_psPortNames[] =
169 {
170   "In",
171   "Out",
172   "Trigger",
173   "Cutoff",
174   "Resonance",
175   "Envelope Modulation",
176   "Decay"
177 };
178 
179 static LADSPA_PortRangeHint g_psPortRangeHints[] =
180 {
181   /* Hints, Lower bound, Upper bound */
182   { 0, 0.0, 0.0 },
183   { 0, 0.0, 0.0 },
184   { LADSPA_HINT_TOGGLED, 0.0, 0.0 },
185   { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
186   { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
187   { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
188   { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }
189 };
190 
191 void
initialise_vcf303()192 initialise_vcf303() {
193   CMT_Descriptor * psDescriptor;
194 
195   psDescriptor = new CMT_Descriptor
196       (1224,
197        "vcf303",
198        LADSPA_PROPERTY_HARD_RT_CAPABLE,
199        "VCF 303",
200        CMT_MAKER("David A. Bartold"),
201        CMT_COPYRIGHT("1998-2000", "Andy Sloane, David A. Bartold"),
202        NULL,
203        CMT_Instantiate<Vcf303>,
204        Vcf303::activate,
205        Vcf303::run,
206        NULL,
207        NULL,
208        NULL);
209 
210   for (int i = 0; i < NUM_PORTS; i++)
211     psDescriptor->addPort(
212       g_psPortDescriptors[i],
213       g_psPortNames[i],
214       g_psPortRangeHints[i].HintDescriptor,
215       g_psPortRangeHints[i].LowerBound,
216       g_psPortRangeHints[i].UpperBound);
217 
218   registerNewPluginDescriptor(psDescriptor);
219 }
220