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