1 /* -*- c-basic-offset: 4 -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /* trivial_sampler.c
4 
5    DSSI Soft Synth Interface
6    Constructed by Chris Cannam, Steve Harris and Sean Bolton
7 
8    A straightforward DSSI plugin sampler.
9 
10    This example file is in the public domain.
11 */
12 
13 #define _BSD_SOURCE    1
14 #define _SVID_SOURCE   1
15 #define _ISOC99_SOURCE 1
16 
17 #include <stdlib.h>
18 #include <limits.h>
19 #include <string.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <math.h>
23 
24 #include "dssi.h"
25 #include "ladspa.h"
26 
27 #include <sndfile.h>
28 #include <samplerate.h>
29 #include <pthread.h>
30 
31 #include "trivial_sampler.h"
32 
33 static LADSPA_Descriptor *samplerMonoLDescriptor = NULL;
34 static LADSPA_Descriptor *samplerStereoLDescriptor = NULL;
35 
36 static DSSI_Descriptor *samplerMonoDDescriptor = NULL;
37 static DSSI_Descriptor *samplerStereoDDescriptor = NULL;
38 
39 typedef struct {
40     LADSPA_Data *output[2];
41     LADSPA_Data *retune;
42     LADSPA_Data *basePitch;
43     LADSPA_Data *sustain;
44     LADSPA_Data *release;
45     LADSPA_Data *balance;
46     int          channels;
47     float       *sampleData[2];
48     size_t       sampleCount;
49     int          sampleRate;
50     long         ons[Sampler_NOTES];
51     long         offs[Sampler_NOTES];
52     char         velocities[Sampler_NOTES];
53     long         sampleNo;
54     char        *projectDir;
55     pthread_mutex_t mutex;
56 } Sampler;
57 
58 static void runSampler(LADSPA_Handle instance, unsigned long sample_count,
59 		       snd_seq_event_t *events, unsigned long EventCount);
60 
ladspa_descriptor(unsigned long index)61 const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
62 {
63     switch (index) {
64     case 0:
65 	return samplerStereoLDescriptor;
66     case 1:
67 	return samplerMonoLDescriptor;
68     default:
69 	return NULL;
70     }
71 }
72 
dssi_descriptor(unsigned long index)73 const DSSI_Descriptor *dssi_descriptor(unsigned long index)
74 {
75     switch (index) {
76     case 0:
77 	return samplerStereoDDescriptor;
78     case 1:
79 	return samplerMonoDDescriptor;
80     default:
81 	return NULL;
82     }
83 }
84 
cleanupSampler(LADSPA_Handle instance)85 static void cleanupSampler(LADSPA_Handle instance)
86 {
87     Sampler *plugin = (Sampler *)instance;
88     free(plugin);
89 }
90 
connectPortSampler(LADSPA_Handle instance,unsigned long port,LADSPA_Data * data)91 static void connectPortSampler(LADSPA_Handle instance, unsigned long port,
92 			       LADSPA_Data * data)
93 {
94     Sampler *plugin;
95 
96     plugin = (Sampler *) instance;
97     switch (port) {
98     case Sampler_OUTPUT_LEFT:
99 	plugin->output[0] = data;
100 	break;
101     case Sampler_RETUNE:
102 	plugin->retune = data;
103 	break;
104     case Sampler_BASE_PITCH:
105 	plugin->basePitch = data;
106 	break;
107     case Sampler_SUSTAIN:
108 	plugin->sustain = data;
109 	break;
110     case Sampler_RELEASE:
111 	plugin->release = data;
112 	break;
113     default:
114 	break;
115     }
116 
117     if (plugin->channels == 2) {
118 	switch (port) {
119 	case Sampler_OUTPUT_RIGHT:
120 	    plugin->output[1] = data;
121 	    break;
122 	case Sampler_BALANCE:
123 	    plugin->balance = data;
124 	    break;
125 	default:
126 	    break;
127 	}
128     }
129 }
130 
instantiateSampler(const LADSPA_Descriptor * descriptor,unsigned long s_rate)131 static LADSPA_Handle instantiateSampler(const LADSPA_Descriptor * descriptor,
132 					unsigned long s_rate)
133 {
134     Sampler *plugin_data = (Sampler *) malloc(sizeof(Sampler));
135     pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
136 
137     //!!! check rv from malloc throughout
138 
139     plugin_data->output[0] = 0;
140     plugin_data->output[1] = 0;
141     plugin_data->retune = 0;
142     plugin_data->basePitch = 0;
143     plugin_data->sustain = 0;
144     plugin_data->release = 0;
145     plugin_data->balance = 0;
146     plugin_data->channels = 1;
147     plugin_data->sampleData[0] = 0;
148     plugin_data->sampleData[1] = 0;
149     plugin_data->sampleCount = 0;
150     plugin_data->sampleRate = s_rate;
151     plugin_data->projectDir = 0;
152 
153     if (!strcmp(descriptor->Label, Sampler_Stereo_LABEL)) {
154 	plugin_data->channels = 2;
155     }
156 
157     memcpy(&plugin_data->mutex, &m, sizeof(pthread_mutex_t));
158 
159     return (LADSPA_Handle) plugin_data;
160 }
161 
activateSampler(LADSPA_Handle instance)162 static void activateSampler(LADSPA_Handle instance)
163 {
164     Sampler *plugin_data = (Sampler *) instance;
165     unsigned int i;
166 
167     pthread_mutex_lock(&plugin_data->mutex);
168 
169     plugin_data->sampleNo = 0;
170 
171     for (i = 0; i < Sampler_NOTES; i++) {
172 	plugin_data->ons[i] = -1;
173 	plugin_data->offs[i] = -1;
174 	plugin_data->velocities[i] = 0;
175     }
176 
177     pthread_mutex_unlock(&plugin_data->mutex);
178 }
179 
addSample(Sampler * plugin_data,int n,unsigned long pos,unsigned long count)180 static void addSample(Sampler *plugin_data, int n,
181 		      unsigned long pos, unsigned long count)
182 {
183     float ratio = 1.0;
184     float gain = 1.0;
185     unsigned long i, ch, s;
186 
187     if (plugin_data->retune && *plugin_data->retune) {
188 	if (plugin_data->basePitch && n != *plugin_data->basePitch) {
189 	    ratio = powf(1.059463094, n - *plugin_data->basePitch);
190 	}
191     }
192 
193     if (pos + plugin_data->sampleNo < plugin_data->ons[n]) return;
194 
195     gain = (float)plugin_data->velocities[n] / 127.0f;
196 
197     for (i = 0, s = pos + plugin_data->sampleNo - plugin_data->ons[n];
198 	 i < count;
199 	 ++i, ++s) {
200 
201 	float         lgain = gain;
202 	float         rs = s * ratio;
203 	unsigned long rsi = lrintf(floor(rs));
204 
205 	if (rsi >= plugin_data->sampleCount) {
206 	    plugin_data->ons[n] = -1;
207 	    break;
208 	}
209 
210 	if (plugin_data->offs[n] >= 0 &&
211 	    pos + i + plugin_data->sampleNo > plugin_data->offs[n]) {
212 
213 	    unsigned long dist =
214 		pos + i + plugin_data->sampleNo - plugin_data->offs[n];
215 
216 	    unsigned long releaseFrames = 200;
217 	    if (plugin_data->release) {
218 		releaseFrames = *plugin_data->release * plugin_data->sampleRate;
219 	    }
220 
221 	    if (dist > releaseFrames) {
222 		plugin_data->ons[n] = -1;
223 		break;
224 	    } else {
225 		lgain = lgain * (float)(releaseFrames - dist) / (float)releaseFrames;
226 	    }
227 	}
228 
229 	for (ch = 0; ch < plugin_data->channels; ++ch) {
230 
231 	    float sample = plugin_data->sampleData[ch][rsi] +
232 		((plugin_data->sampleData[ch][rsi + 1] -
233 		  plugin_data->sampleData[ch][rsi]) *
234 		 (rs - (float)rsi));
235 
236 	    if (plugin_data->balance) {
237 		if (ch == 0 && *plugin_data->balance > 0) {
238 		    sample *= 1.0 - *plugin_data->balance;
239 		} else if (ch == 1 && *plugin_data->balance < 0) {
240 		    sample *= 1.0 + *plugin_data->balance;
241 		}
242 	    }
243 
244 	    plugin_data->output[ch][pos + i] += lgain * sample;
245 	}
246     }
247 }
248 
runSampler(LADSPA_Handle instance,unsigned long sample_count,snd_seq_event_t * events,unsigned long event_count)249 static void runSampler(LADSPA_Handle instance, unsigned long sample_count,
250 		       snd_seq_event_t *events, unsigned long event_count)
251 {
252     Sampler *plugin_data = (Sampler *) instance;
253     unsigned long pos;
254     unsigned long count;
255     unsigned long event_pos;
256     int i;
257 
258     for (i = 0; i < plugin_data->channels; ++i) {
259 	memset(plugin_data->output[i], 0, sample_count * sizeof(float));
260     }
261 
262     if (pthread_mutex_trylock(&plugin_data->mutex)) {
263 	return;
264     }
265 
266     if (!plugin_data->sampleData || !plugin_data->sampleCount) {
267 	plugin_data->sampleNo += sample_count;
268 	pthread_mutex_unlock(&plugin_data->mutex);
269 	return;
270     }
271 
272     for (pos = 0, event_pos = 0; pos < sample_count; ) {
273 
274 	while (event_pos < event_count
275 	       && pos >= events[event_pos].time.tick) {
276 
277 	    if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
278 		snd_seq_ev_note_t n = events[event_pos].data.note;
279 		if (n.velocity > 0) {
280 		    plugin_data->ons[n.note] =
281 			plugin_data->sampleNo + events[event_pos].time.tick;
282 		    plugin_data->offs[n.note] = -1;
283 		    plugin_data->velocities[n.note] = n.velocity;
284 		} else {
285 		    if (!plugin_data->sustain || (*plugin_data->sustain < 0.001)) {
286 			plugin_data->offs[n.note] =
287 			    plugin_data->sampleNo + events[event_pos].time.tick;
288 		    }
289 		}
290 	    } else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF &&
291 		       (!plugin_data->sustain || (*plugin_data->sustain < 0.001))) {
292 		snd_seq_ev_note_t n = events[event_pos].data.note;
293 		plugin_data->offs[n.note] =
294 		    plugin_data->sampleNo + events[event_pos].time.tick;
295 	    }
296 
297 	    ++event_pos;
298 	}
299 
300 	count = sample_count - pos;
301 	if (event_pos < event_count &&
302 	    events[event_pos].time.tick < sample_count) {
303 	    count = events[event_pos].time.tick - pos;
304 	}
305 
306 	for (i = 0; i < Sampler_NOTES; ++i) {
307 	    if (plugin_data->ons[i] >= 0) {
308 		addSample(plugin_data, i, pos, count);
309 	    }
310 	}
311 
312 	pos += count;
313     }
314 
315     plugin_data->sampleNo += sample_count;
316     pthread_mutex_unlock(&plugin_data->mutex);
317 }
318 
runSamplerWrapper(LADSPA_Handle instance,unsigned long sample_count)319 static void runSamplerWrapper(LADSPA_Handle instance,
320 			 unsigned long sample_count)
321 {
322     runSampler(instance, sample_count, NULL, 0);
323 }
324 
getControllerSampler(LADSPA_Handle instance,unsigned long port)325 int getControllerSampler(LADSPA_Handle instance, unsigned long port)
326 {
327     if (port == Sampler_RETUNE) return DSSI_CC(12);
328     else if (port == Sampler_BASE_PITCH) return DSSI_CC(13);
329     else if (port == Sampler_SUSTAIN) return DSSI_CC(64);
330     else if (port == Sampler_RELEASE) return DSSI_CC(72);
331     else {
332 	Sampler *plugin_data = (Sampler *) instance;
333 	if (plugin_data->channels == 2) {
334 	    if (port == Sampler_BALANCE) return DSSI_CC(10);
335 	}
336     }
337     return DSSI_NONE;
338 }
339 
340 char *
dssi_configure_message(const char * fmt,...)341 dssi_configure_message(const char *fmt, ...)
342 {
343     va_list args;
344     char buffer[256];
345 
346     va_start(args, fmt);
347     vsnprintf(buffer, 256, fmt, args);
348     va_end(args);
349     return strdup(buffer);
350 }
351 
samplerLoad(Sampler * plugin_data,const char * path)352 char *samplerLoad(Sampler *plugin_data, const char *path)
353 {
354     SF_INFO info;
355     SNDFILE *file;
356     size_t samples = 0;
357     float *tmpFrames, *tmpSamples[2], *tmpResamples, *tmpOld[2];
358     char *revisedPath = 0;
359     size_t i;
360 
361     info.format = 0;
362     file = sf_open(path, SFM_READ, &info);
363 
364     if (!file) {
365 
366 	const char *filename = strrchr(path, '/');
367 	if (filename) ++filename;
368 	else filename = path;
369 
370 	if (*filename && plugin_data->projectDir) {
371 	    revisedPath = (char *)malloc(strlen(filename) +
372 					 strlen(plugin_data->projectDir) + 2);
373 	    sprintf(revisedPath, "%s/%s", plugin_data->projectDir, filename);
374 	    file = sf_open(revisedPath, SFM_READ, &info);
375 	    if (!file) {
376 		free(revisedPath);
377 	    }
378 	}
379 
380 	if (!file) {
381 	    return dssi_configure_message
382 		("error: unable to load sample file '%s'", path);
383 	}
384     }
385 
386     if (info.frames > Sampler_FRAMES_MAX) {
387 	return dssi_configure_message
388 	    ("error: sample file '%s' is too large (%ld frames, maximum is %ld)",
389 	     path, info.frames, Sampler_FRAMES_MAX);
390     }
391 
392     //!!! complain also if more than 2 channels
393 
394     samples = info.frames;
395 
396     tmpFrames = (float *)malloc(info.frames * info.channels * sizeof(float));
397     sf_readf_float(file, tmpFrames, info.frames);
398     sf_close(file);
399 
400     tmpResamples = 0;
401 
402     if (info.samplerate != plugin_data->sampleRate) {
403 
404 	double ratio = (double)plugin_data->sampleRate / (double)info.samplerate;
405 	size_t target = (size_t)(info.frames * ratio);
406 	SRC_DATA data;
407 
408 	tmpResamples = (float *)malloc(target * info.channels * sizeof(float));
409 	memset(tmpResamples, 0, target * info.channels * sizeof(float));
410 
411 	data.data_in = tmpFrames;
412 	data.data_out = tmpResamples;
413 	data.input_frames = info.frames;
414 	data.output_frames = target;
415 	data.src_ratio = ratio;
416 
417 	if (!src_simple(&data, SRC_SINC_BEST_QUALITY, info.channels)) {
418 	    free(tmpFrames);
419 	    tmpFrames = tmpResamples;
420 	    samples = target;
421 	} else {
422 	    free(tmpResamples);
423 	}
424     }
425 
426     /* add an extra sample for linear interpolation */
427     tmpSamples[0] = (float *)malloc((samples + 1) * sizeof(float));
428 
429     if (plugin_data->channels == 2) {
430 	tmpSamples[1] = (float *)malloc((samples + 1) * sizeof(float));
431     } else {
432 	tmpSamples[1] = NULL;
433     }
434 
435 
436     if (plugin_data->channels == 2) {
437 	for (i = 0; i < samples; ++i) {
438 	    int j;
439 	    for (j = 0; j < 2; ++j) {
440 		if (j == 1 && info.frames < 2) {
441 		    tmpSamples[j][i] = tmpSamples[0][i];
442 		} else {
443 		    tmpSamples[j][i] = tmpFrames[i * info.channels + j];
444 		}
445 	    }
446 	}
447     } else {
448 	for (i = 0; i < samples; ++i) {
449 	    int j;
450 	    tmpSamples[0][i] = 0.0f;
451 	    for (j = 0; j < info.channels; ++j) {
452 		tmpSamples[0][i] += tmpFrames[i * info.channels + j];
453 	    }
454 	}
455     }
456 
457     free(tmpFrames);
458 
459     /* add an extra sample for linear interpolation */
460     tmpSamples[0][samples] = 0.0f;
461     if (plugin_data->channels == 2) {
462 	tmpSamples[1][samples] = 0.0f;
463     }
464 
465     pthread_mutex_lock(&plugin_data->mutex);
466 
467     tmpOld[0] = plugin_data->sampleData[0];
468     tmpOld[1] = plugin_data->sampleData[1];
469     plugin_data->sampleData[0] = tmpSamples[0];
470     plugin_data->sampleData[1] = tmpSamples[1];
471     plugin_data->sampleCount = samples;
472 
473     for (i = 0; i < Sampler_NOTES; ++i) {
474 	plugin_data->ons[i] = -1;
475 	plugin_data->offs[i] = -1;
476 	plugin_data->velocities[i] = 0;
477     }
478 
479     pthread_mutex_unlock(&plugin_data->mutex);
480 
481     if (tmpOld[0]) free(tmpOld[0]);
482     if (tmpOld[1]) free(tmpOld[1]);
483 
484     printf("%s: loaded %s (%ld samples from original %ld channels resampled from %ld frames at %ld Hz)\n", (plugin_data->channels == 2 ? Sampler_Stereo_LABEL : Sampler_Mono_LABEL), path, (long)samples, (long)info.channels, (long)info.frames, (long)info.samplerate);
485 
486     if (revisedPath) {
487 	char *message = dssi_configure_message("warning: sample file '%s' not found: loading from '%s' instead", path, revisedPath);
488 	free(revisedPath);
489 	return message;
490     }
491 
492     return NULL;
493 }
494 
samplerConfigure(LADSPA_Handle instance,const char * key,const char * value)495 char *samplerConfigure(LADSPA_Handle instance, const char *key, const char *value)
496 {
497     Sampler *plugin_data = (Sampler *)instance;
498 
499     if (!strcmp(key, "load")) {
500 	return samplerLoad(plugin_data, value);
501     } else if (!strcmp(key, DSSI_PROJECT_DIRECTORY_KEY)) {
502 	if (plugin_data->projectDir) free(plugin_data->projectDir);
503 	plugin_data->projectDir = strdup(value);
504 	return 0;
505     }
506 
507     return strdup("error: unrecognized configure key");
508 }
509 
510 #ifdef __GNUC__
init()511 __attribute__((constructor)) void init()
512 #else
513 void _init()
514 #endif
515 {
516     char **port_names;
517     LADSPA_PortDescriptor *port_descriptors;
518     LADSPA_PortRangeHint *port_range_hints;
519     int channels;
520 
521     samplerMonoLDescriptor =
522 	(LADSPA_Descriptor *) malloc(sizeof(LADSPA_Descriptor));
523 
524     samplerStereoLDescriptor =
525 	(LADSPA_Descriptor *) malloc(sizeof(LADSPA_Descriptor));
526 
527     samplerMonoDDescriptor =
528 	(DSSI_Descriptor *) malloc(sizeof(DSSI_Descriptor));
529 
530     samplerStereoDDescriptor =
531 	(DSSI_Descriptor *) malloc(sizeof(DSSI_Descriptor));
532 
533     //!!! malloc rv
534 
535     for (channels = 1; channels <= 2; ++channels) {
536 
537 	int stereo = (channels == 2);
538 
539 	LADSPA_Descriptor *desc =
540 	    (stereo ? samplerStereoLDescriptor : samplerMonoLDescriptor);
541 
542 	desc->UniqueID = channels;
543 	desc->Label = (stereo ? Sampler_Stereo_LABEL : Sampler_Mono_LABEL);
544 	desc->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
545 	desc->Name = (stereo ? "Simple Stereo Sampler" : "Simple Mono Sampler");
546 	desc->Maker = "Chris Cannam <cannam@all-day-breakfast.com>";
547 	desc->Copyright = "GPL";
548 	desc->PortCount = (stereo ? Sampler_Stereo_COUNT : Sampler_Mono_COUNT);
549 
550 	port_descriptors = (LADSPA_PortDescriptor *)
551 	    calloc(desc->PortCount, sizeof(LADSPA_PortDescriptor));
552 	desc->PortDescriptors =
553 	    (const LADSPA_PortDescriptor *) port_descriptors;
554 
555 	port_range_hints = (LADSPA_PortRangeHint *)
556 	    calloc(desc->PortCount, sizeof (LADSPA_PortRangeHint));
557 	desc->PortRangeHints =
558 	    (const LADSPA_PortRangeHint *) port_range_hints;
559 
560 	port_names = (char **) calloc(desc->PortCount, sizeof(char *));
561 	desc->PortNames = (const char **) port_names;
562 
563 	/* Parameters for output left */
564 	port_descriptors[Sampler_OUTPUT_LEFT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
565 	port_names[Sampler_OUTPUT_LEFT] = "Output L";
566 	port_range_hints[Sampler_OUTPUT_LEFT].HintDescriptor = 0;
567 
568 	/* Parameters for retune */
569 	port_descriptors[Sampler_RETUNE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
570 	port_names[Sampler_RETUNE] = "Tuned (on/off)";
571 	port_range_hints[Sampler_RETUNE].HintDescriptor =
572 	    LADSPA_HINT_DEFAULT_MAXIMUM | LADSPA_HINT_INTEGER |
573 	    LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
574 	port_range_hints[Sampler_RETUNE].LowerBound = 0;
575 	port_range_hints[Sampler_RETUNE].UpperBound = 1;
576 
577 	/* Parameters for base pitch */
578 	port_descriptors[Sampler_BASE_PITCH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
579 	port_names[Sampler_BASE_PITCH] = "Base pitch (MIDI)";
580 	port_range_hints[Sampler_BASE_PITCH].HintDescriptor =
581 	    LADSPA_HINT_INTEGER | LADSPA_HINT_DEFAULT_MIDDLE |
582 	    LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
583 	port_range_hints[Sampler_BASE_PITCH].LowerBound = Sampler_BASE_PITCH_MIN;
584 	port_range_hints[Sampler_BASE_PITCH].UpperBound = Sampler_BASE_PITCH_MAX;
585 
586 	/* Parameters for sustain */
587 	port_descriptors[Sampler_SUSTAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
588 	port_names[Sampler_SUSTAIN] = "Sustain (on/off)";
589 	port_range_hints[Sampler_SUSTAIN].HintDescriptor =
590 	    LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_INTEGER |
591 	    LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
592 	port_range_hints[Sampler_SUSTAIN].LowerBound = 0.0f;
593 	port_range_hints[Sampler_SUSTAIN].UpperBound = 1.0f;
594 
595 	/* Parameters for release */
596 	port_descriptors[Sampler_RELEASE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
597 	port_names[Sampler_RELEASE] = "Release time (s)";
598 	port_range_hints[Sampler_RELEASE].HintDescriptor =
599 	    LADSPA_HINT_DEFAULT_MINIMUM | LADSPA_HINT_LOGARITHMIC |
600 	    LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
601 	port_range_hints[Sampler_RELEASE].LowerBound = Sampler_RELEASE_MIN;
602 	port_range_hints[Sampler_RELEASE].UpperBound = Sampler_RELEASE_MAX;
603 
604 	if (stereo) {
605 
606 	    /* Parameters for output right */
607 	    port_descriptors[Sampler_OUTPUT_RIGHT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
608 	    port_names[Sampler_OUTPUT_RIGHT] = "Output R";
609 	    port_range_hints[Sampler_OUTPUT_RIGHT].HintDescriptor = 0;
610 
611 	    /* Parameters for balance */
612 	    port_descriptors[Sampler_BALANCE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
613 	    port_names[Sampler_BALANCE] = "Pan / Balance";
614 	    port_range_hints[Sampler_BALANCE].HintDescriptor =
615 		LADSPA_HINT_DEFAULT_MIDDLE |
616 		LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
617 	    port_range_hints[Sampler_BALANCE].LowerBound = -1.0f;
618 	    port_range_hints[Sampler_BALANCE].UpperBound = 1.0f;
619 	}
620 
621 	desc->activate = activateSampler;
622 	desc->cleanup = cleanupSampler;
623 	desc->connect_port = connectPortSampler;
624 	desc->deactivate = activateSampler; // sic
625 	desc->instantiate = instantiateSampler;
626 	desc->run = runSamplerWrapper;
627 	desc->run_adding = NULL;
628 	desc->set_run_adding_gain = NULL;
629     }
630 
631     samplerMonoDDescriptor->DSSI_API_Version = 1;
632     samplerMonoDDescriptor->LADSPA_Plugin = samplerMonoLDescriptor;
633     samplerMonoDDescriptor->configure = samplerConfigure;
634     samplerMonoDDescriptor->get_program = NULL;
635     samplerMonoDDescriptor->get_midi_controller_for_port = getControllerSampler;
636     samplerMonoDDescriptor->select_program = NULL;
637     samplerMonoDDescriptor->run_synth = runSampler;
638     samplerMonoDDescriptor->run_synth_adding = NULL;
639     samplerMonoDDescriptor->run_multiple_synths = NULL;
640     samplerMonoDDescriptor->run_multiple_synths_adding = NULL;
641 
642     samplerStereoDDescriptor->DSSI_API_Version = 1;
643     samplerStereoDDescriptor->LADSPA_Plugin = samplerStereoLDescriptor;
644     samplerStereoDDescriptor->configure = samplerConfigure;
645     samplerStereoDDescriptor->get_program = NULL;
646     samplerStereoDDescriptor->get_midi_controller_for_port = getControllerSampler;
647     samplerStereoDDescriptor->select_program = NULL;
648     samplerStereoDDescriptor->run_synth = runSampler;
649     samplerStereoDDescriptor->run_synth_adding = NULL;
650     samplerStereoDDescriptor->run_multiple_synths = NULL;
651     samplerStereoDDescriptor->run_multiple_synths_adding = NULL;
652 }
653 
654 #ifdef __GNUC__
fini()655 __attribute__((destructor)) void fini()
656 #else
657 void _fini()
658 #endif
659 {
660     if (samplerMonoLDescriptor) {
661 	free((LADSPA_PortDescriptor *) samplerMonoLDescriptor->PortDescriptors);
662 	free((char **) samplerMonoLDescriptor->PortNames);
663 	free((LADSPA_PortRangeHint *) samplerMonoLDescriptor->PortRangeHints);
664 	free(samplerMonoLDescriptor);
665     }
666     if (samplerMonoDDescriptor) {
667 	free(samplerMonoDDescriptor);
668     }
669     if (samplerStereoLDescriptor) {
670 	free((LADSPA_PortDescriptor *) samplerStereoLDescriptor->PortDescriptors);
671 	free((char **) samplerStereoLDescriptor->PortNames);
672 	free((LADSPA_PortRangeHint *) samplerStereoLDescriptor->PortRangeHints);
673 	free(samplerStereoLDescriptor);
674     }
675     if (samplerStereoDDescriptor) {
676 	free(samplerStereoDDescriptor);
677     }
678 }
679