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