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