1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
2
3 /* less_trivial_synth.c
4
5 DSSI Soft Synth Interface
6 Constructed by Chris Cannam, Steve Harris and Sean Bolton
7
8 This is an example DSSI synth plugin written by Steve Harris.
9
10 This example file is in the public domain.
11 */
12
13 #ifdef HAVE_CONFIG_H
14 #include <config.h>
15 #endif
16
17 #include <stdlib.h>
18 #include <limits.h>
19 #include <string.h>
20 #include <stdint.h>
21
22 #include <math.h>
23 #include <stdio.h>
24
25 #include "dssi.h"
26 #include "ladspa.h"
27 #include "saw.h"
28
29 #define LTS_OUTPUT 0
30 #define LTS_FREQ 1
31 #define LTS_ATTACK 2
32 #define LTS_DECAY 3
33 #define LTS_SUSTAIN 4
34 #define LTS_RELEASE 5
35 #define LTS_TIMBRE 6
36 #define LTS_COUNT 7 /* must be 1 + highest value above */
37
38 #define POLYPHONY 74
39 #define MIDI_NOTES 128
40 #define STEP_SIZE 16
41
42 #define GLOBAL_GAIN 0.25f
43
44 #define TABLE_MODULUS 1024
45 #define TABLE_SIZE (TABLE_MODULUS + 1)
46 #define TABLE_MASK (TABLE_MODULUS - 1)
47
48 #define FP_IN(x) (x.part.in & TABLE_MASK)
49 #define FP_FR(x) ((float)x.part.fr * 0.0000152587890625f)
50 #define FP_OMEGA(w) ((double)TABLE_MODULUS * 65536.0 * (w));
51
52 #define LERP(f,a,b) ((a) + (f) * ((b) - (a)))
53
54 long int lrintf (float x);
55
56 static LADSPA_Descriptor *ltsLDescriptor = NULL;
57 static DSSI_Descriptor *ltsDDescriptor = NULL;
58
59 static float *table[2];
60
61 typedef enum {
62 inactive = 0,
63 attack,
64 decay,
65 sustain,
66 release
67 } state_t;
68
69 typedef union {
70 uint32_t all;
71 struct {
72 #ifdef WORDS_BIGENDIAN
73 uint16_t in;
74 uint16_t fr;
75 #else
76 uint16_t fr;
77 uint16_t in;
78 #endif
79 } part;
80 } fixp;
81
82 typedef struct {
83 state_t state;
84 int note;
85 float amp;
86 float env;
87 float env_d;
88 fixp phase;
89 int counter;
90 int next_event;
91 } voice_data;
92
93 typedef struct {
94 LADSPA_Data tune;
95 LADSPA_Data attack;
96 LADSPA_Data decay;
97 LADSPA_Data sustain;
98 LADSPA_Data release;
99 LADSPA_Data timbre;
100 LADSPA_Data pitch;
101 } synth_vals;
102
103 typedef struct {
104 LADSPA_Data *output;
105 LADSPA_Data *tune;
106 LADSPA_Data *attack;
107 LADSPA_Data *decay;
108 LADSPA_Data *sustain;
109 LADSPA_Data *release;
110 LADSPA_Data *timbre;
111 LADSPA_Data pitch;
112 voice_data data[POLYPHONY];
113 int note2voice[MIDI_NOTES];
114 fixp omega[MIDI_NOTES];
115 float fs;
116 LADSPA_Data previous_timbre;
117 } LTS;
118
119 static void runLTS(LADSPA_Handle instance, unsigned long sample_count,
120 snd_seq_event_t * events, unsigned long EventCount);
121
122 static void run_voice(LTS *p, synth_vals *vals, voice_data *d,
123 LADSPA_Data *out, unsigned int count);
124
125 int pick_voice(const voice_data *data);
126
ladspa_descriptor(unsigned long index)127 const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
128 {
129 switch (index) {
130 case 0:
131 return ltsLDescriptor;
132 default:
133 return NULL;
134 }
135 }
136
dssi_descriptor(unsigned long index)137 const DSSI_Descriptor *dssi_descriptor(unsigned long index)
138 {
139 switch (index) {
140 case 0:
141 return ltsDDescriptor;
142 default:
143 return NULL;
144 }
145 }
146
cleanupLTS(LADSPA_Handle instance)147 static void cleanupLTS(LADSPA_Handle instance)
148 {
149 free(instance);
150 }
151
connectPortLTS(LADSPA_Handle instance,unsigned long port,LADSPA_Data * data)152 static void connectPortLTS(LADSPA_Handle instance, unsigned long port,
153 LADSPA_Data * data)
154 {
155 LTS *plugin;
156
157 plugin = (LTS *) instance;
158 switch (port) {
159 case LTS_OUTPUT:
160 plugin->output = data;
161 break;
162 case LTS_FREQ:
163 plugin->tune = data;
164 break;
165 case LTS_ATTACK:
166 plugin->attack = data;
167 break;
168 case LTS_DECAY:
169 plugin->decay = data;
170 break;
171 case LTS_SUSTAIN:
172 plugin->sustain = data;
173 break;
174 case LTS_RELEASE:
175 plugin->release = data;
176 break;
177 case LTS_TIMBRE:
178 plugin->timbre = data;
179 break;
180 }
181 }
182
instantiateLTS(const LADSPA_Descriptor * descriptor,unsigned long s_rate)183 static LADSPA_Handle instantiateLTS(const LADSPA_Descriptor * descriptor,
184 unsigned long s_rate)
185 {
186 unsigned int i;
187
188 LTS *plugin_data = (LTS *) malloc(sizeof(LTS));
189
190 plugin_data->fs = s_rate;
191 plugin_data->previous_timbre = 0.5f;
192
193 for (i=0; i<MIDI_NOTES; i++) {
194 plugin_data->omega[i].all =
195 FP_OMEGA(pow(2.0, (i-69.0) / 12.0) / (double)s_rate);
196 }
197
198 return (LADSPA_Handle) plugin_data;
199 }
200
activateLTS(LADSPA_Handle instance)201 static void activateLTS(LADSPA_Handle instance)
202 {
203 LTS *plugin_data = (LTS *) instance;
204 unsigned int i;
205
206 for (i=0; i<POLYPHONY; i++) {
207 plugin_data->data[i].state = inactive;
208 }
209 for (i=0; i<MIDI_NOTES; i++) {
210 plugin_data->note2voice[i] = 0;
211 }
212 plugin_data->pitch = 1.0f;
213 }
214
runLTSWrapper(LADSPA_Handle instance,unsigned long sample_count)215 static void runLTSWrapper(LADSPA_Handle instance,
216 unsigned long sample_count)
217 {
218 runLTS(instance, sample_count, NULL, 0);
219 }
220
runLTS(LADSPA_Handle instance,unsigned long sample_count,snd_seq_event_t * events,unsigned long event_count)221 static void runLTS(LADSPA_Handle instance, unsigned long sample_count,
222 snd_seq_event_t *events, unsigned long event_count)
223 {
224 LTS *plugin_data = (LTS *) instance;
225 LADSPA_Data *const output = plugin_data->output;
226 synth_vals vals;
227 voice_data *data = plugin_data->data;
228 unsigned long i;
229 unsigned long pos;
230 unsigned long count;
231 unsigned long event_pos;
232 unsigned long voice;
233
234 vals.tune = *(plugin_data->tune);
235 vals.attack = *(plugin_data->attack) * plugin_data->fs;
236 vals.decay = *(plugin_data->decay) * plugin_data->fs;
237 vals.sustain = *(plugin_data->sustain) * 0.01f;
238 vals.release = *(plugin_data->release) * plugin_data->fs;
239 vals.timbre = plugin_data->previous_timbre;
240 vals.pitch = plugin_data->pitch;
241
242 for (pos = 0, event_pos = 0; pos < sample_count; pos += STEP_SIZE) {
243 vals.timbre = LERP(0.99f, vals.timbre, *(plugin_data->timbre));
244 while (event_pos < event_count
245 && pos >= events[event_pos].time.tick) {
246 if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
247 snd_seq_ev_note_t n = events[event_pos].data.note;
248
249 if (n.velocity > 0) {
250 const int voice = pick_voice(data);
251
252 plugin_data->note2voice[n.note] = voice;
253 data[voice].note = n.note;
254 data[voice].amp = sqrtf(n.velocity * .0078740157f) *
255 GLOBAL_GAIN;
256 data[voice].state = attack;
257 data[voice].env = 0.0;
258 data[voice].env_d = 1.0f / vals.attack;
259 data[voice].phase.all = 0;
260 data[voice].counter = 0;
261 data[voice].next_event = vals.attack;
262 } else {
263 const int voice = plugin_data->note2voice[n.note];
264
265 data[voice].state = release;
266 data[voice].env_d = -vals.sustain / vals.release;
267 data[voice].counter = 0;
268 data[voice].next_event = vals.release;
269 }
270 } else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF) {
271 snd_seq_ev_note_t n = events[event_pos].data.note;
272 const int voice = plugin_data->note2voice[n.note];
273
274 if (data[voice].state != inactive) {
275 data[voice].state = release;
276 data[voice].env_d = -data[voice].env / vals.release;
277 data[voice].counter = 0;
278 data[voice].next_event = vals.release;
279 }
280 } else if (events[event_pos].type == SND_SEQ_EVENT_PITCHBEND) {
281 vals.pitch =
282 powf(2.0f, (float)(events[event_pos].data.control.value)
283 * 0.0001220703125f * 0.166666666f);
284 plugin_data->pitch = vals.pitch;
285 }
286 event_pos++;
287 }
288
289 count = (sample_count - pos) > STEP_SIZE ? STEP_SIZE :
290 sample_count - pos;
291 for (i=0; i<count; i++) {
292 output[pos + i] = 0.0f;
293 }
294 for (voice = 0; voice < POLYPHONY; voice++) {
295 if (data[voice].state != inactive) {
296 run_voice(plugin_data, &vals, &data[voice], output + pos,
297 count);
298 }
299 }
300 }
301 plugin_data->previous_timbre = vals.timbre;
302 }
303
run_voice(LTS * p,synth_vals * vals,voice_data * d,LADSPA_Data * out,unsigned int count)304 static void run_voice(LTS *p, synth_vals *vals, voice_data *d, LADSPA_Data *out, unsigned int count)
305 {
306 unsigned int i;
307
308 for (i=0; i<count; i++) {
309 d->phase.all += lrintf((float)p->omega[d->note].all * vals->tune *
310 vals->pitch);
311 d->env += d->env_d;
312 out[i] += LERP(vals->timbre,
313 LERP(FP_FR(d->phase), table[0][FP_IN(d->phase)],
314 table[0][FP_IN(d->phase) + 1]),
315 LERP(FP_FR(d->phase), table[1][FP_IN(d->phase)],
316 table[1][FP_IN(d->phase) + 1])) *
317 d->amp * d->env;
318 }
319
320 d->counter += count;
321 if (d->counter >= d->next_event) {
322 switch (d->state) {
323 case inactive:
324 break;
325
326 case attack:
327 d->state = decay;
328 d->env_d = (vals->sustain - 1.0f) / vals->decay;
329 d->counter = 0;
330 d->next_event = vals->decay;
331 break;
332
333 case decay:
334 d->state = sustain;
335 d->env_d = 0.0f;
336 d->counter = 0;
337 d->next_event = INT_MAX;
338 break;
339
340 case sustain:
341 d->counter = 0;
342 break;
343
344 case release:
345 d->state = inactive;
346 break;
347
348 default:
349 d->state = inactive;
350 break;
351 }
352 }
353 }
354
getControllerLTS(LADSPA_Handle instance,unsigned long port)355 int getControllerLTS(LADSPA_Handle instance, unsigned long port)
356 {
357 switch (port) {
358 case LTS_ATTACK:
359 return DSSI_CC(0x49);
360 case LTS_DECAY:
361 return DSSI_CC(0x4b);
362 case LTS_SUSTAIN:
363 return DSSI_CC(0x4f);
364 case LTS_RELEASE:
365 return DSSI_CC(0x48);
366 case LTS_TIMBRE:
367 return DSSI_CC(0x01);
368 }
369
370 return DSSI_NONE;
371 }
372
373 /* find the voice that is least relevant (low note priority)*/
374
pick_voice(const voice_data * data)375 int pick_voice(const voice_data *data)
376 {
377 unsigned int i;
378 int highest_note = 0;
379 int highest_note_voice = 0;
380
381 /* Look for an inactive voice */
382 for (i=0; i<POLYPHONY; i++) {
383 if (data[i].state == inactive) {
384 return i;
385 }
386 }
387
388 /* otherwise find for the highest note and replace that */
389 for (i=0; i<POLYPHONY; i++) {
390 if (data[i].note > highest_note) {
391 highest_note = data[i].note;
392 highest_note_voice = i;
393 }
394 }
395
396 return highest_note_voice;
397 }
398
399 #ifdef __GNUC__
init()400 __attribute__((constructor)) void init()
401 #else
402 void _init()
403 #endif
404 {
405 unsigned int i;
406 char **port_names;
407 float *sin_table;
408 LADSPA_PortDescriptor *port_descriptors;
409 LADSPA_PortRangeHint *port_range_hints;
410
411 sin_table = malloc(sizeof(float) * TABLE_SIZE);
412 for (i=0; i<TABLE_SIZE; i++) {
413 sin_table[i] = sin(2.0 * M_PI * (double)i / (double)TABLE_MODULUS);
414 }
415 table[0] = sin_table;
416 table[1] = saw_table;
417
418 ltsLDescriptor =
419 (LADSPA_Descriptor *) malloc(sizeof(LADSPA_Descriptor));
420 if (ltsLDescriptor) {
421 ltsLDescriptor->UniqueID = 24;
422 ltsLDescriptor->Label = "LTS";
423 ltsLDescriptor->Properties = 0;
424 ltsLDescriptor->Name = "Less Trivial synth";
425 ltsLDescriptor->Maker = "Steve Harris <steve@plugin.org.uk>";
426 ltsLDescriptor->Copyright = "Public Domain";
427 ltsLDescriptor->PortCount = LTS_COUNT;
428
429 port_descriptors = (LADSPA_PortDescriptor *)
430 calloc(ltsLDescriptor->PortCount, sizeof
431 (LADSPA_PortDescriptor));
432 ltsLDescriptor->PortDescriptors =
433 (const LADSPA_PortDescriptor *) port_descriptors;
434
435 port_range_hints = (LADSPA_PortRangeHint *)
436 calloc(ltsLDescriptor->PortCount, sizeof
437 (LADSPA_PortRangeHint));
438 ltsLDescriptor->PortRangeHints =
439 (const LADSPA_PortRangeHint *) port_range_hints;
440
441 port_names = (char **) calloc(ltsLDescriptor->PortCount, sizeof(char *));
442 ltsLDescriptor->PortNames = (const char **) port_names;
443
444 /* Parameters for output */
445 port_descriptors[LTS_OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
446 port_names[LTS_OUTPUT] = "Output";
447 port_range_hints[LTS_OUTPUT].HintDescriptor = 0;
448
449 /* Parameters for tune */
450 port_descriptors[LTS_FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
451 port_names[LTS_FREQ] = "A tuning (Hz)";
452 port_range_hints[LTS_FREQ].HintDescriptor = LADSPA_HINT_DEFAULT_440 |
453 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
454 port_range_hints[LTS_FREQ].LowerBound = 410;
455 port_range_hints[LTS_FREQ].UpperBound = 460;
456
457 /* Parameters for attack */
458 port_descriptors[LTS_ATTACK] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
459 port_names[LTS_ATTACK] = "Attack time (s)";
460 port_range_hints[LTS_ATTACK].HintDescriptor =
461 LADSPA_HINT_DEFAULT_LOW |
462 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
463 port_range_hints[LTS_ATTACK].LowerBound = 0.01f;
464 port_range_hints[LTS_ATTACK].UpperBound = 1.0f;
465
466 /* Parameters for decay */
467 port_descriptors[LTS_DECAY] = port_descriptors[LTS_ATTACK];
468 port_names[LTS_DECAY] = "Decay time (s)";
469 port_range_hints[LTS_DECAY].HintDescriptor =
470 port_range_hints[LTS_ATTACK].HintDescriptor;
471 port_range_hints[LTS_DECAY].LowerBound =
472 port_range_hints[LTS_ATTACK].LowerBound;
473 port_range_hints[LTS_DECAY].UpperBound =
474 port_range_hints[LTS_ATTACK].UpperBound;
475
476 /* Parameters for sustain */
477 port_descriptors[LTS_SUSTAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
478 port_names[LTS_SUSTAIN] = "Sustain level (%)";
479 port_range_hints[LTS_SUSTAIN].HintDescriptor =
480 LADSPA_HINT_DEFAULT_HIGH |
481 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
482 port_range_hints[LTS_SUSTAIN].LowerBound = 0.0f;
483 port_range_hints[LTS_SUSTAIN].UpperBound = 100.0f;
484
485 /* Parameters for release */
486 port_descriptors[LTS_RELEASE] = port_descriptors[LTS_ATTACK];
487 port_names[LTS_RELEASE] = "Release time (s)";
488 port_range_hints[LTS_RELEASE].HintDescriptor =
489 LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_LOGARITHMIC |
490 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
491 port_range_hints[LTS_RELEASE].LowerBound =
492 port_range_hints[LTS_ATTACK].LowerBound;
493 port_range_hints[LTS_RELEASE].UpperBound =
494 port_range_hints[LTS_ATTACK].UpperBound * 4.0f;
495
496 /* Parameters for timbre */
497 port_descriptors[LTS_TIMBRE] = port_descriptors[LTS_ATTACK];
498 port_names[LTS_TIMBRE] = "Timbre";
499 port_range_hints[LTS_TIMBRE].HintDescriptor =
500 LADSPA_HINT_DEFAULT_MIDDLE |
501 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
502 port_range_hints[LTS_TIMBRE].LowerBound = 0.0f;
503 port_range_hints[LTS_TIMBRE].UpperBound = 1.0f;
504
505 ltsLDescriptor->activate = activateLTS;
506 ltsLDescriptor->cleanup = cleanupLTS;
507 ltsLDescriptor->connect_port = connectPortLTS;
508 ltsLDescriptor->deactivate = NULL;
509 ltsLDescriptor->instantiate = instantiateLTS;
510 ltsLDescriptor->run = runLTSWrapper;
511 ltsLDescriptor->run_adding = NULL;
512 ltsLDescriptor->set_run_adding_gain = NULL;
513 }
514
515 ltsDDescriptor = (DSSI_Descriptor *) malloc(sizeof(DSSI_Descriptor));
516 if (ltsDDescriptor) {
517 ltsDDescriptor->DSSI_API_Version = 1;
518 ltsDDescriptor->LADSPA_Plugin = ltsLDescriptor;
519 ltsDDescriptor->configure = NULL;
520 ltsDDescriptor->get_program = NULL;
521 ltsDDescriptor->get_midi_controller_for_port = getControllerLTS;
522 ltsDDescriptor->select_program = NULL;
523 ltsDDescriptor->run_synth = runLTS;
524 ltsDDescriptor->run_synth_adding = NULL;
525 ltsDDescriptor->run_multiple_synths = NULL;
526 ltsDDescriptor->run_multiple_synths_adding = NULL;
527 }
528 }
529
530 #ifdef __GNUC__
fini()531 __attribute__((destructor)) void fini()
532 #else
533 void _fini()
534 #endif
535 {
536 if (ltsLDescriptor) {
537 free((LADSPA_PortDescriptor *) ltsLDescriptor->PortDescriptors);
538 free((char **) ltsLDescriptor->PortNames);
539 free((LADSPA_PortRangeHint *) ltsLDescriptor->PortRangeHints);
540 free(ltsLDescriptor);
541 }
542 if (ltsDDescriptor) {
543 free(ltsDDescriptor);
544 }
545 }
546