1 /* analogue.cpp
2
3 Analogue Voice - Analog synthesizer voice
4 Copyright (c) 2000 David A. Bartold
5
6 Computer Music Toolkit - a library of LADSPA plugins. Copyright (C)
7 2000 Richard W.E. Furse. The author may be contacted at
8 richard@muse.demon.co.uk.
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public Licence as
12 published by the Free Software Foundation; either version 2 of the
13 Licence, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 02111-1307, USA. */
24
25 /*****************************************************************************/
26
27 #include <stdlib.h>
28 #include <math.h>
29 #include <stdlib.h>
30 #include "cmt.h"
31
32 #define PORT_OUT 0
33 #define PORT_GATE 1
34 #define PORT_VELOCITY 2
35 #define PORT_FREQ 3
36 #define PORT_DCO1_OCTAVE 4
37 #define PORT_DCO1_WAVEFORM 5
38 #define PORT_DCO1_FM 6
39 #define PORT_DCO1_PWM 7
40 #define PORT_DCO1_ATTACK 8
41 #define PORT_DCO1_DECAY 9
42 #define PORT_DCO1_SUSTAIN 10
43 #define PORT_DCO1_RELEASE 11
44 #define PORT_DCO2_OCTAVE 12
45 #define PORT_DCO2_WAVEFORM 13
46 #define PORT_DCO2_FM 14
47 #define PORT_DCO2_PWM 15
48 #define PORT_DCO2_ATTACK 16
49 #define PORT_DCO2_DECAY 17
50 #define PORT_DCO2_SUSTAIN 18
51 #define PORT_DCO2_RELEASE 19
52 #define PORT_LFO_FREQ 20
53 #define PORT_LFO_FADEIN 21
54 #define PORT_FILT_ENV_MOD 22
55 #define PORT_FILT_LFO_MOD 23
56 #define PORT_FILT_RES 24
57 #define PORT_FILT_ATTACK 25
58 #define PORT_FILT_DECAY 26
59 #define PORT_FILT_SUSTAIN 27
60 #define PORT_FILT_RELEASE 28
61
62 #define NUM_PORTS 29
63
64 #ifndef PI
65 #define PI 3.14159265358979F
66 #endif
67
68 typedef struct Envelope
69 {
70 int envelope_decay;
71 LADSPA_Data envelope;
72
EnvelopeEnvelope73 Envelope () : envelope_decay (0), envelope (0.0) {}
74 } Envelope;
75
76 class Analogue : public CMT_PluginInstance
77 {
78 LADSPA_Data sample_rate;
79
80 int trigger;
81 Envelope dco1_env;
82 Envelope dco2_env;
83 Envelope filt_env;
84 LADSPA_Data d1;
85 LADSPA_Data d2;
86
87 LADSPA_Data dco1_accum;
88 LADSPA_Data dco2_accum;
89 LADSPA_Data lfo_accum;
90
91 LADSPA_Data lfo_vol;
92
93 public:
Analogue(const LADSPA_Descriptor * Descriptor,unsigned long SampleRate)94 Analogue(const LADSPA_Descriptor * Descriptor,
95 unsigned long SampleRate)
96 : CMT_PluginInstance(NUM_PORTS),
97 sample_rate (SampleRate),
98 trigger (0),
99 d1 (0.0), d2 (0.0),
100 dco1_accum (0.0), dco2_accum (0.0), lfo_accum (0.0) {
101 }
102
~Analogue()103 ~Analogue () {
104 }
105
106 /* Third-order approximation of a sine wave. */
107 static inline LADSPA_Data
fast_sin(LADSPA_Data x)108 fast_sin(LADSPA_Data x) {
109 if (x > PI)
110 x = (x < PI * 1.5F) ? (PI - x) : (x - 2.0F * PI);
111 else if (x > PI * 0.5F)
112 x = PI - x;
113
114 return x * (1.05F - x * x * 0.175F);
115 }
116
117 static inline LADSPA_Data
tri(LADSPA_Data x)118 tri(LADSPA_Data x) {
119 if (x > 0.75F)
120 x = x - 1.0F;
121 else if (x > 0.25F)
122 x = 0.5F - x;
123
124 return x * 4.0F;
125 }
126
127 static inline LADSPA_Data
envelope(Envelope * env,int gate,LADSPA_Data attack,LADSPA_Data decay,LADSPA_Data sustain,LADSPA_Data release)128 envelope(Envelope *env,
129 int gate,
130 LADSPA_Data attack,
131 LADSPA_Data decay,
132 LADSPA_Data sustain,
133 LADSPA_Data release)
134 {
135 if (gate)
136 if (env->envelope_decay == 0)
137 {
138 env->envelope += (1.0F - env->envelope) * attack;
139 if (env->envelope >= 0.95F)
140 env->envelope_decay = 1;
141 }
142 else
143 env->envelope += (sustain - env->envelope) * decay;
144 else
145 env->envelope += -env->envelope * release;
146
147 return env->envelope;
148 }
149
150 static void
activate(LADSPA_Handle Instance)151 activate(LADSPA_Handle Instance) {
152 Analogue *analogue = (Analogue*) Instance;
153
154 analogue->trigger = 0;
155 analogue->dco1_env.envelope_decay = 0;
156 analogue->dco1_env.envelope = 0.0;
157 analogue->dco2_env.envelope_decay = 0;
158 analogue->dco2_env.envelope = 0.0;
159 analogue->filt_env.envelope_decay = 0;
160 analogue->filt_env.envelope = 0.0;
161 analogue->d1 = 0.0F;
162 analogue->d2 = 0.0F;
163
164 analogue->dco1_accum = 0.0F;
165 analogue->dco2_accum = 0.0F;
166 analogue->lfo_accum = 0.0F;
167 analogue->lfo_vol = 0.0F;
168 }
169
170 static inline LADSPA_Data
osc(int waveform,LADSPA_Data inc,LADSPA_Data width,LADSPA_Data * accum)171 osc(int waveform,
172 LADSPA_Data inc,
173 LADSPA_Data width,
174 LADSPA_Data *accum) {
175 *accum += inc;
176 while (*accum >= 1.0F)
177 *accum -= 1.0F;
178
179 /* 0 = Sine wave */
180 if (waveform == 0)
181 if (*accum < width)
182 return fast_sin (*accum / width * PI);
183 else
184 return fast_sin (PI + (*accum - width) / (1.0F - width) * PI);
185
186 /* 1 = Triangle wave */
187 else if (waveform == 1)
188 if (*accum < width)
189 return tri (*accum / width * 0.5);
190 else
191 return tri (0.5 + (*accum - width) * 0.5 / (1.0F - width));
192
193 /* 2 = Square wave */
194 else if (waveform == 2)
195 return (*accum > width) ? 1.0F : -1.0F;
196
197 /* 3 = Sawtooth wave */
198 else if (waveform == 3)
199 if (*accum < width)
200 return *accum / width * 2.0F - 1.0F;
201 else
202 return (*accum - width) / (1.0F - width) * 2.0F - 1.0F;
203
204 /* 4 = Fullwave Rectified Sine wave */
205 else if (waveform == 4)
206 if (*accum < width)
207 return fast_sin (*accum / width * PI);
208 else
209 return fast_sin ((*accum - width) / (1.0F - width) * PI);
210
211 /* 5 = Static */
212 else
213 return (rand () & 1) ? -1.0F : 1.0F;
214 }
215
216 static LADSPA_Data
inc(LADSPA_Data oct,LADSPA_Data freq,LADSPA_Data sample_rate)217 inc(LADSPA_Data oct,
218 LADSPA_Data freq,
219 LADSPA_Data sample_rate) {
220 return pow (2.0, oct) * freq / sample_rate;
221 }
222
223 static void
calc_a_b_c(Analogue * analogue,LADSPA_Data freq,LADSPA_Data * a,LADSPA_Data * b,LADSPA_Data * c)224 calc_a_b_c(Analogue *analogue,
225 LADSPA_Data freq,
226 LADSPA_Data *a,
227 LADSPA_Data *b,
228 LADSPA_Data *c) {
229 LADSPA_Data top_freq, k, res;
230
231 top_freq = freq;
232 top_freq *= PI / analogue->sample_rate;
233 res = exp (-1.20 + 3.455 * *analogue->m_ppfPorts[PORT_FILT_RES]);
234
235 k = exp (-top_freq / res);
236
237 *a = 2.0 * cos (2.0 * top_freq) * k;
238 *b = -k * k;
239 *c = (1.0 - *a - *b) * 0.2;
240 }
241
242 static inline LADSPA_Data
multiplier(Analogue * analogue,LADSPA_Data value)243 multiplier(Analogue *analogue,
244 LADSPA_Data value) {
245 return 1.0 - pow (0.05, 1.0 / (analogue->sample_rate * value));
246 }
247
248 static void
run(LADSPA_Handle Instance,unsigned long SampleCount)249 run(LADSPA_Handle Instance,
250 unsigned long SampleCount) {
251 Analogue *analogue = (Analogue*) Instance;
252 unsigned long i;
253 int waveform1, waveform2;
254 int gate;
255 LADSPA_Data lfo_inc, inc1, inc2;
256 LADSPA_Data attack1, decay1, release1;
257 LADSPA_Data attack2, decay2, release2;
258 LADSPA_Data filt_attack, filt_decay, filt_release;
259 LADSPA_Data lfo_fadein, a, b, c;
260 LADSPA_Data dco1_pwm, dco2_pwm;
261 LADSPA_Data dco1_fm, dco2_fm;
262 LADSPA_Data filt_lfo_mod;
263 LADSPA_Data **ports;
264
265 ports = analogue->m_ppfPorts;
266 gate = (*ports[PORT_GATE] > 0.0);
267 if (gate == 1 && analogue->trigger == 0)
268 {
269 analogue->lfo_vol = 0.0F;
270 analogue->dco1_env.envelope_decay = 0;
271 analogue->dco1_env.envelope = 0.0;
272 analogue->dco2_env.envelope_decay = 0;
273 analogue->dco2_env.envelope = 0.0;
274 analogue->filt_env.envelope_decay = 0;
275 analogue->filt_env.envelope = 0.0;
276 }
277
278 analogue->trigger = gate;
279
280 waveform1 = (int) *ports[PORT_DCO1_WAVEFORM];
281 waveform2 = (int) *ports[PORT_DCO2_WAVEFORM];
282
283 inc1 = inc (*ports[PORT_DCO1_OCTAVE],
284 *ports[PORT_FREQ],
285 analogue->sample_rate);
286 inc2 = inc (*ports[PORT_DCO2_OCTAVE],
287 *ports[PORT_FREQ],
288 analogue->sample_rate);
289 lfo_inc = 2.0F * PI * *ports[PORT_LFO_FREQ] / analogue->sample_rate;
290
291 attack1 = multiplier (analogue, *ports[PORT_DCO1_ATTACK]);
292 decay1 = multiplier (analogue, *ports[PORT_DCO1_DECAY]);
293 release1 = multiplier (analogue, *ports[PORT_DCO1_RELEASE]);
294
295 attack2 = multiplier (analogue, *ports[PORT_DCO2_ATTACK]);
296 decay2 = multiplier (analogue, *ports[PORT_DCO2_DECAY]);
297 release2 = multiplier (analogue, *ports[PORT_DCO2_RELEASE]);
298
299 filt_attack = multiplier (analogue, *ports[PORT_FILT_ATTACK]);
300 filt_decay = multiplier (analogue, *ports[PORT_FILT_DECAY]);
301 filt_release = multiplier (analogue, *ports[PORT_FILT_RELEASE]);
302
303 lfo_fadein = 1.0 / (*ports[PORT_LFO_FADEIN] * analogue->sample_rate);
304
305 dco1_pwm = *analogue->m_ppfPorts[PORT_DCO1_PWM] * 0.225F;
306 dco2_pwm = *analogue->m_ppfPorts[PORT_DCO2_PWM] * 0.225F;
307 dco1_fm = *analogue->m_ppfPorts[PORT_DCO1_FM] * inc1 * 0.45F;
308 dco2_fm = *analogue->m_ppfPorts[PORT_DCO2_FM] * inc2 * 0.45F;
309 filt_lfo_mod = *analogue->m_ppfPorts[PORT_FILT_LFO_MOD] * 0.45F;
310
311 for (i = 0; i < SampleCount; i++)
312 {
313 LADSPA_Data lfo, sample;
314
315 analogue->lfo_accum += lfo_inc;
316 while (analogue->lfo_accum >= 2.0F * PI)
317 analogue->lfo_accum -= 2.0F * PI;
318
319 lfo = fast_sin (analogue->lfo_accum) * analogue->lfo_vol;
320
321 analogue->lfo_vol += lfo_fadein;
322 if (analogue->lfo_vol >= 1.0F)
323 analogue->lfo_vol = 1.0F;
324
325 envelope (&analogue->filt_env,
326 gate, filt_attack, filt_decay,
327 *ports[PORT_FILT_SUSTAIN], filt_release);
328
329 if ((i & 0x000f) == 0)
330 calc_a_b_c (analogue,
331 *ports[PORT_FREQ] * 0.25F + (analogue->filt_env.envelope *
332 *ports[PORT_FILT_ENV_MOD] * *ports[PORT_VELOCITY] *
333 (1.5 + filt_lfo_mod * lfo)) * *ports[PORT_FREQ] * 10.0F, &a, &b, &c);
334
335 sample = osc (waveform1, inc1 * (1.0 + lfo * dco1_fm),
336 0.5F + lfo * dco1_pwm,
337 &analogue->dco1_accum)
338 * envelope (&analogue->dco1_env,
339 gate, attack1, decay1,
340 *ports[PORT_DCO1_SUSTAIN], release1)
341 + osc (waveform2, inc2 * (1.0 + lfo * dco2_fm),
342 0.5F + lfo * dco2_pwm,
343 &analogue->dco2_accum)
344 * envelope (&analogue->dco2_env,
345 gate, attack2, decay2,
346 *ports[PORT_DCO2_SUSTAIN], release2);
347
348 sample = a * analogue->d1 +
349 b * analogue->d2 +
350 c * *ports[PORT_VELOCITY] * sample;
351
352 analogue->d2 = analogue->d1;
353 analogue->d1 = sample;
354 ports[PORT_OUT][i] = sample;
355 }
356 }
357 };
358
359 static LADSPA_PortDescriptor g_psPortDescriptors[] =
360 {
361 LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT,
362 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
363 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
364 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
365 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
366 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
367 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
368 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
369 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
370 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
371 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
372 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
373 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
374 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
375 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
376 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
377 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
378 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
379 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
380 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
381 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
382 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
383 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
384 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
385 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
386 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
387 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
388 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
389 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT
390 };
391
392 static const char * const g_psPortNames[] =
393 {
394 "Out",
395 "Gate",
396 "Velocity",
397 "Frequency (Hz)",
398
399 "DCO1 Octave",
400 "DCO1 Waveform",
401 "DCO1 LFO Frequency Modulation",
402 "DCO1 LFO Pulse Width Modulation",
403
404 "DCO1 Attack",
405 "DCO1 Decay",
406 "DCO1 Sustain",
407 "DCO1 Release",
408
409 "DCO2 Octave",
410 "DCO2 Waveform",
411 "DCO2 LFO Frequency Modulation",
412 "DCO2 LFO Pulse Width Modulation",
413
414 "DCO2 Attack",
415 "DCO2 Decay",
416 "DCO2 Sustain",
417 "DCO2 Release",
418
419 "LFO Frequency (Hz)",
420 "LFO Fadein",
421
422 "Filter Envelope Modulation",
423 "Filter LFO Modulation",
424 "Filter Resonance",
425
426 "Filter Attack",
427 "Filter Decay",
428 "Filter Sustain",
429 "Filter Release"
430 };
431
432 static LADSPA_PortRangeHint g_psPortRangeHints[] =
433 {
434 /* Hints, Lower bound, Upper bound */
435 { 0, 0.0, 0.0 },
436 { LADSPA_HINT_TOGGLED, 0.0, 0.0 },
437 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
438 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 },
439 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.001, 1.0 },
440 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 10.0 },
441
442 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 },
443 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW |
444 LADSPA_HINT_INTEGER, -0.1, 5.1 },
445 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
446 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
447
448 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
449 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
450 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 },
451 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
452
453 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 },
454 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW |
455 LADSPA_HINT_INTEGER, -0.1, 5.1 },
456 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
457 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
458
459 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
460 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
461 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 },
462 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
463
464 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20.0 },
465 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
466
467 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
468 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
469 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 },
470
471 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
472 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 },
473 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 },
474 { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }
475 };
476
477 void
initialise_analogue()478 initialise_analogue() {
479 CMT_Descriptor * psDescriptor;
480
481 psDescriptor = new CMT_Descriptor
482 (1221,
483 "analogue",
484 LADSPA_PROPERTY_HARD_RT_CAPABLE,
485 "Analogue Voice",
486 CMT_MAKER("David A. Bartold"),
487 CMT_COPYRIGHT("2000", "David A. Bartold"),
488 NULL,
489 CMT_Instantiate<Analogue>,
490 Analogue::activate,
491 Analogue::run,
492 NULL,
493 NULL,
494 NULL);
495
496 for (int i = 0; i < NUM_PORTS; i++)
497 psDescriptor->addPort(
498 g_psPortDescriptors[i],
499 g_psPortNames[i],
500 g_psPortRangeHints[i].HintDescriptor,
501 g_psPortRangeHints[i].LowerBound,
502 g_psPortRangeHints[i].UpperBound);
503
504 registerNewPluginDescriptor(psDescriptor);
505 }
506