1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
2
3 /* jack-dssi-host.c
4 *
5 * DSSI Soft Synth Interface
6 *
7 * This is a host for DSSI plugins. It listens for MIDI events on an
8 * ALSA sequencer port, delivers them to DSSI synths and outputs the
9 * result via JACK.
10 *
11 * This program expects the names of up to 16 DSSI synth plugins, in
12 * the form '<dll-name>:<label>',* to be provided on the command line.
13 * If just '<dll-name>' is provided, the first plugin in the DLL is
14 * is used. MIDI channels are assigned to each plugin instance, in
15 * order, beginning with channel 0 (zero-based). A plugin may be
16 * easily instantiated multiple times by preceding its name and label
17 * with a dash followed immediately by the desired number of instances,
18 * e.g. '-3 my_plugins.so:zoomy' would create three instances of the
19 * 'zoomy' plugin.
20 */
21
22 /*
23 * Copyright 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton.
24 *
25 * Permission to use, copy, modify, distribute, and sell this software
26 * for any purpose is hereby granted without fee, provided that the
27 * above copyright notice and this permission notice are included in
28 * all copies or substantial portions of the software.
29 */
30
31 #define _BSD_SOURCE 1
32 #define _SVID_SOURCE 1
33 #define _ISOC99_SOURCE 1
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <ladspa.h>
40 #include "dssi.h"
41 #include <alsa/asoundlib.h>
42 #include <alsa/seq.h>
43 #include <jack/jack.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <assert.h>
48 #include <dlfcn.h>
49 #include <unistd.h>
50 #include <math.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <sys/time.h>
54 #include <sys/wait.h>
55 #include <signal.h>
56 #include <dirent.h>
57 #include <time.h>
58 #include <libgen.h>
59
60 #include <lo/lo.h>
61
62 #include "jack-dssi-host.h"
63
64 #include "../message_buffer/message_buffer.h"
65
66 #ifdef MIDI_ALSA
67 static snd_seq_t *alsaClient;
68 #endif
69
70 static jack_client_t *jackClient;
71 static jack_port_t **inputPorts, **outputPorts;
72
73 static d3h_dll_t *dlls;
74
75 static d3h_plugin_t *plugins;
76 static int plugin_count = 0;
77
78 static float sample_rate;
79
80 static d3h_instance_t instances[D3H_MAX_INSTANCES];
81 static int instance_count = 0;
82
83 static LADSPA_Handle *instanceHandles;
84 static snd_seq_event_t **instanceEventBuffers;
85 static unsigned long *instanceEventCounts;
86
87 static int insTotal, outsTotal;
88 static float **pluginInputBuffers, **pluginOutputBuffers;
89
90 static int controlInsTotal, controlOutsTotal;
91 static float *pluginControlIns, *pluginControlOuts;
92 static d3h_instance_t *channel2instance[D3H_MAX_CHANNELS]; /* maps MIDI channel to instance */
93 static d3h_instance_t **pluginControlInInstances; /* maps global control in # to instance */
94 static unsigned long *pluginControlInPortNumbers; /* maps global control in # to instance LADSPA port # */
95 static int *pluginPortUpdated; /* indexed by global control in # */
96
97 static char osc_path_tmp[1024];
98
99 static char *projectDirectory;
100
101 lo_server_thread serverThread;
102
103 static sigset_t _signals;
104
105 int exiting = 0;
106 static int verbose = 0;
107 static int autoconnect = 1;
108 static int load_guis = 1;
109 const char *myName = NULL;
110
111 #define EVENT_BUFFER_SIZE 1024
112 static snd_seq_event_t midiEventBuffer[EVENT_BUFFER_SIZE]; /* ring buffer */
113 static int midiEventReadIndex = 0, midiEventWriteIndex = 0;
114
115 static pthread_mutex_t midiEventBufferMutex = PTHREAD_MUTEX_INITIALIZER;
116
117 LADSPA_Data get_port_default(const LADSPA_Descriptor *plugin, int port);
118
119 void osc_error(int num, const char *m, const char *path);
120
121 int osc_message_handler(const char *path, const char *types, lo_arg **argv, int
122 argc, void *data, void *user_data) ;
123 int osc_debug_handler(const char *path, const char *types, lo_arg **argv, int
124 argc, void *data, void *user_data) ;
125
126 void
signalHandler(int sig)127 signalHandler(int sig)
128 {
129 fprintf(stderr, "%s: signal %d caught, trying to clean up and exit\n",
130 myName, sig);
131 exiting = 1;
132 }
133
134 void
midi_callback()135 midi_callback()
136 {
137 snd_seq_event_t *ev = 0;
138 struct timeval tv;
139
140 pthread_mutex_lock(&midiEventBufferMutex);
141
142 #ifdef MIDI_ALSA
143 do {
144 if (snd_seq_event_input(alsaClient, &ev) > 0) {
145
146 if (midiEventReadIndex == midiEventWriteIndex + 1) {
147 fprintf(stderr, "%s: Warning: MIDI event buffer overflow! ignoring incoming event\n", myName);
148 continue;
149 }
150
151 midiEventBuffer[midiEventWriteIndex] = *ev;
152
153 ev = &midiEventBuffer[midiEventWriteIndex];
154
155 /* At this point we change the event timestamp so that its
156 real-time field contains the actual time at which it was
157 received and processed (i.e. now). Then in the audio
158 callback we use that to calculate frame offset. */
159
160 gettimeofday(&tv, NULL);
161 ev->time.time.tv_sec = tv.tv_sec;
162 ev->time.time.tv_nsec = tv.tv_usec * 1000L;
163
164 if (ev->type == SND_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0) {
165 ev->type = SND_SEQ_EVENT_NOTEOFF;
166 }
167
168 /* We don't need to handle EVENT_NOTE here, because ALSA
169 won't ever deliver them on the sequencer queue -- it
170 unbundles them into NOTE_ON and NOTE_OFF when they're
171 dispatched. We would only need worry about them when
172 retrieving MIDI events from some other source. */
173
174 midiEventWriteIndex = (midiEventWriteIndex + 1) % EVENT_BUFFER_SIZE;
175 }
176
177 } while (snd_seq_event_input_pending(alsaClient, 0) > 0);
178 #endif
179
180 pthread_mutex_unlock(&midiEventBufferMutex);
181 }
182
183 void
setControl(d3h_instance_t * instance,long controlIn,snd_seq_event_t * event)184 setControl(d3h_instance_t *instance, long controlIn, snd_seq_event_t *event)
185 {
186 long port = pluginControlInPortNumbers[controlIn];
187
188 const LADSPA_Descriptor *p = instance->plugin->descriptor->LADSPA_Plugin;
189
190 LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor;
191
192 LADSPA_Data lb = p->PortRangeHints[port].LowerBound *
193 (LADSPA_IS_HINT_SAMPLE_RATE(p->PortRangeHints[port].HintDescriptor) ?
194 sample_rate : 1.0f);
195
196 LADSPA_Data ub = p->PortRangeHints[port].UpperBound *
197 (LADSPA_IS_HINT_SAMPLE_RATE(p->PortRangeHints[port].HintDescriptor) ?
198 sample_rate : 1.0f);
199
200 float value = (float)event->data.control.value;
201
202 if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) {
203 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
204 /* unbounded: might as well leave the value alone. */
205 return;
206 } else {
207 /* bounded above only. just shift the range. */
208 value = ub - 127.0f + value;
209 }
210 } else {
211 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
212 /* bounded below only. just shift the range. */
213 value = lb + value;
214 } else {
215 /* bounded both ends. more interesting. */
216 if (LADSPA_IS_HINT_LOGARITHMIC(d) && lb > 0.0f && ub > 0.0f) {
217 const float llb = logf(lb);
218 const float lub = logf(ub);
219
220 value = expf(llb + ((lub - llb) * value / 127.0f));
221 } else {
222 value = lb + ((ub - lb) * value / 127.0f);
223 }
224 }
225 }
226 if (LADSPA_IS_HINT_INTEGER(d)) {
227 value = lrintf(value);
228 }
229
230 if (verbose) {
231 printf("%s: %s MIDI controller %d=%d -> control in %ld=%f\n", myName,
232 instance->friendly_name, event->data.control.param,
233 event->data.control.value, controlIn, value);
234 }
235
236 pluginControlIns[controlIn] = value;
237 pluginPortUpdated[controlIn] = 1;
238 }
239
240 int
audio_callback(jack_nframes_t nframes,void * arg)241 audio_callback(jack_nframes_t nframes, void *arg)
242 {
243 int i;
244 int outCount, inCount;
245 d3h_instance_t *instance;
246 struct timeval tv, evtv, diff;
247 long framediff;
248
249 gettimeofday(&tv, NULL);
250
251 /* Not especially pretty or efficient */
252
253 for (i = 0; i < instance_count; i++) {
254 instanceEventCounts[i] = 0;
255 }
256
257 for ( ; midiEventReadIndex != midiEventWriteIndex;
258 midiEventReadIndex = (midiEventReadIndex + 1) % EVENT_BUFFER_SIZE) {
259
260 snd_seq_event_t *ev = &midiEventBuffer[midiEventReadIndex];
261
262 if (!snd_seq_ev_is_channel_type(ev)) {
263 /* discard non-channel oriented messages */
264 continue;
265 }
266
267 instance = channel2instance[ev->data.note.channel];
268 if (!instance
269 /* || instance->inactive */) /* no -- see comment in osc_exiting_handler */
270 {
271 /* discard messages intended for channels we aren't using or
272 absent or exited plugins */
273 continue;
274 }
275 i = instance->number;
276
277 /* Stop processing incoming MIDI if an instance's event buffer is
278 * full. */
279 if (instanceEventCounts[i] == EVENT_BUFFER_SIZE)
280 break;
281
282 /* Each event has a real-time timestamp indicating when it was
283 * received (set by midi_callback). We need to calculate the
284 * difference between then and the start of the audio callback
285 * (held in tv), and use that to assign a frame offset, to
286 * avoid jitter. We should stop processing when we reach any
287 * event received after the start of the audio callback. */
288
289 evtv.tv_sec = ev->time.time.tv_sec;
290 evtv.tv_usec = ev->time.time.tv_nsec / 1000;
291
292 if (evtv.tv_sec > tv.tv_sec ||
293 (evtv.tv_sec == tv.tv_sec &&
294 evtv.tv_usec > tv.tv_usec)) {
295 break;
296 }
297
298 diff.tv_sec = tv.tv_sec - evtv.tv_sec;
299 if (tv.tv_usec < evtv.tv_usec) {
300 --diff.tv_sec;
301 diff.tv_usec = tv.tv_usec + 1000000 - evtv.tv_usec;
302 } else {
303 diff.tv_usec = tv.tv_usec - evtv.tv_usec;
304 }
305
306 framediff =
307 diff.tv_sec * sample_rate +
308 ((diff.tv_usec / 1000) * sample_rate) / 1000 +
309 ((diff.tv_usec - 1000 * (diff.tv_usec / 1000)) * sample_rate) / 1000000;
310
311 if (framediff >= nframes) framediff = nframes - 1;
312 else if (framediff < 0) framediff = 0;
313
314 ev->time.tick = nframes - framediff - 1;
315
316 if (ev->type == SND_SEQ_EVENT_CONTROLLER) {
317
318 int controller = ev->data.control.param;
319 #ifdef DEBUG
320 MB_MESSAGE("%s CC %d(0x%02x) = %d\n", instance->friendly_name,
321 controller, controller, ev->data.control.value);
322 #endif
323
324 if (controller == 0) { // bank select MSB
325
326 instance->pendingBankMSB = ev->data.control.value;
327
328 } else if (controller == 32) { // bank select LSB
329
330 instance->pendingBankLSB = ev->data.control.value;
331
332 } else if (controller > 0 && controller < MIDI_CONTROLLER_COUNT) {
333
334 long controlIn = instance->controllerMap[controller];
335 if (controlIn >= 0) {
336
337 /* controller is mapped to LADSPA port, update the port */
338 setControl(instance, controlIn, ev);
339
340 } else {
341
342 /* controller is not mapped, so pass the event through to plugin */
343 instanceEventBuffers[i][instanceEventCounts[i]] = *ev;
344 instanceEventCounts[i]++;
345 }
346 }
347
348 } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) {
349
350 instance->pendingProgramChange = ev->data.control.value;
351 instance->uiNeedsProgramUpdate = 1;
352
353 } else {
354
355 instanceEventBuffers[i][instanceEventCounts[i]] = *ev;
356 instanceEventCounts[i]++;
357 }
358 }
359
360 /* process pending program changes */
361 for (i = 0; i < instance_count; i++) {
362 instance = &instances[i];
363
364 /* no -- see comment in osc_exiting_handler */
365 /* if (instance->inactive) continue; */
366
367 if (instance->pendingProgramChange >= 0) {
368
369 int pc = instance->pendingProgramChange;
370 int msb = instance->pendingBankMSB;
371 int lsb = instance->pendingBankLSB;
372
373 //!!! gosh, I don't know this -- need to check with the specs:
374 // if you only send one of MSB/LSB controllers, should the
375 // other go to zero or remain as it was? Assume it remains as
376 // it was, for now.
377
378 if (lsb >= 0) {
379 if (msb >= 0) {
380 instance->currentBank = lsb + 128 * msb;
381 } else {
382 instance->currentBank = lsb + 128 * (instance->currentBank / 128);
383 }
384 } else if (msb >= 0) {
385 instance->currentBank = (instance->currentBank % 128) + 128 * msb;
386 }
387
388 instance->currentProgram = pc;
389
390 instance->pendingProgramChange = -1;
391 instance->pendingBankMSB = -1;
392 instance->pendingBankLSB = -1;
393
394 if (instance->plugin->descriptor->select_program) {
395 instance->plugin->descriptor->
396 select_program(instanceHandles[instance->number],
397 instance->currentBank,
398 instance->currentProgram);
399 }
400 }
401 }
402
403 for (inCount = 0; inCount < insTotal; ++inCount) {
404
405 jack_default_audio_sample_t *buffer =
406 jack_port_get_buffer(inputPorts[inCount], nframes);
407
408 memcpy(pluginInputBuffers[inCount], buffer, nframes * sizeof(LADSPA_Data));
409 }
410
411 /* call run_synth() or run_multiple_synths() for all instances */
412
413 i = 0;
414 outCount = 0;
415
416 while (i < instance_count) {
417
418 /* no -- see comment in osc_exiting_handler */
419 /*
420 if (instances[i].inactive) {
421 int j;
422 for (j = 0; j < instances[i].plugin->outs; ++j) {
423 memset(pluginOutputBuffers[outCount + j], 0, nframes * sizeof(LADSPA_Data));
424 }
425 outCount += j;
426 ++i;
427 continue;
428 }
429 */
430 outCount += instances[i].plugin->outs;
431
432 if (instances[i].plugin->descriptor->run_multiple_synths) {
433 instances[i].plugin->descriptor->run_multiple_synths
434 (instances[i].plugin->instances,
435 instanceHandles + i,
436 nframes,
437 instanceEventBuffers + i,
438 instanceEventCounts + i);
439 i += instances[i].plugin->instances;
440 } else if (instances[i].plugin->descriptor->run_synth) {
441 instances[i].plugin->descriptor->run_synth(instanceHandles[i],
442 nframes,
443 instanceEventBuffers[i],
444 instanceEventCounts[i]);
445 i++;
446 } else if (instances[i].plugin->descriptor->LADSPA_Plugin->run) {
447 instances[i].plugin->descriptor->LADSPA_Plugin->run(instanceHandles[i],
448 nframes);
449 i++;
450 } else {
451 fprintf(stderr, "DSSI plugin %d has no run_multiple_synths, run_synth or run method!\n", i);
452 i++;
453 }
454 }
455
456 assert(sizeof(LADSPA_Data) == sizeof(jack_default_audio_sample_t));
457
458 for (outCount = 0; outCount < outsTotal; ++outCount) {
459
460 jack_default_audio_sample_t *buffer =
461 jack_port_get_buffer(outputPorts[outCount], nframes);
462
463 memcpy(buffer, pluginOutputBuffers[outCount], nframes * sizeof(LADSPA_Data));
464 }
465
466 return 0;
467 }
468
469 #ifndef RTLD_LOCAL
470 #define RTLD_LOCAL (0)
471 #endif
472
473 char *
load(const char * dllName,void ** dll,int quiet)474 load(const char *dllName, void **dll, int quiet) /* returns directory where dll found */
475 {
476 static char *defaultDssiPath = 0;
477 const char *dssiPath = getenv("DSSI_PATH");
478 char *path, *origPath, *element, *message;
479 void *handle = 0;
480
481 /* If the dllName is an absolute path */
482 if (*dllName == '/') {
483 if ((handle = dlopen(dllName, RTLD_NOW | /* real-time programs should not use RTLD_LAZY */
484 RTLD_LOCAL))) { /* do not share symbols across plugins
485 * (some systems (e.g. Mac OS X) default
486 * to RTLD_GLOBAL!) */
487 *dll = handle;
488 path = strdup(dllName);
489 return dirname(path);
490 } else {
491 if (!quiet) {
492 fprintf(stderr, "Cannot find DSSI or LADSPA plugin at '%s'\n", dllName);
493 }
494 return NULL;
495 }
496 }
497
498 if (!dssiPath) {
499 if (!defaultDssiPath) {
500 const char *home = getenv("HOME");
501 if (home) {
502 defaultDssiPath = malloc(strlen(home) + 60);
503 sprintf(defaultDssiPath, "/usr/local/lib/dssi:/usr/lib/dssi:%s/.dssi", home);
504 } else {
505 defaultDssiPath = strdup("/usr/local/lib/dssi:/usr/lib/dssi");
506 }
507 }
508 dssiPath = defaultDssiPath;
509 if (!quiet) {
510 fprintf(stderr, "\n%s: Warning: DSSI path not set\n%s: Defaulting to \"%s\"\n\n", myName, myName, dssiPath);
511 }
512 }
513
514 path = strdup(dssiPath);
515 origPath = path;
516 *dll = 0;
517
518 while ((element = strtok(path, ":")) != 0) {
519
520 char *filePath;
521
522 path = 0;
523
524 if (element[0] != '/') {
525 if (!quiet) {
526 fprintf(stderr, "%s: Ignoring relative element \"%s\" in path\n", myName, element);
527 }
528 continue;
529 }
530
531 if (!quiet && verbose) {
532 fprintf(stderr, "%s: Looking for library \"%s\" in %s... ", myName, dllName, element);
533 }
534
535 filePath = (char *)malloc(strlen(element) + strlen(dllName) + 2);
536 sprintf(filePath, "%s/%s", element, dllName);
537
538 if ((handle = dlopen(filePath, RTLD_NOW | /* real-time programs should not use RTLD_LAZY */
539 RTLD_LOCAL))) { /* do not share symbols across plugins */
540 if (!quiet && verbose) {
541 fprintf(stderr, "found\n");
542 }
543 *dll = handle;
544 free(filePath);
545 path = strdup(element);
546 free(origPath);
547 return path;
548 }
549
550 if (!quiet && verbose) {
551 message = dlerror();
552 if (message) {
553 fprintf(stderr, "not found: %s\n", message);
554 } else {
555 fprintf(stderr, "not found\n");
556 }
557 }
558
559 free(filePath);
560 }
561
562 free(origPath);
563 return 0;
564 }
565
566 static int
instance_sort_cmp(const void * a,const void * b)567 instance_sort_cmp(const void *a, const void *b)
568 {
569 d3h_instance_t *ia = (d3h_instance_t *)a;
570 d3h_instance_t *ib = (d3h_instance_t *)b;
571
572 if (ia->plugin->number != ib->plugin->number) {
573 return ia->plugin->number - ib->plugin->number;
574 } else {
575 return ia->channel - ib->channel;
576 }
577 }
578
579 void
startGUI(const char * directory,const char * dllName,const char * label,const char * oscUrl,const char * instanceTag)580 startGUI(const char *directory, const char *dllName, const char *label,
581 const char *oscUrl, const char *instanceTag)
582 {
583 struct dirent *entry;
584 char *dllBase = strdup(dllName);
585 char *subpath;
586 DIR *subdir;
587 char *filename;
588 struct stat buf;
589 int fuzzy;
590
591 if (strlen(dllBase) > 3 &&
592 !strcasecmp(dllBase + strlen(dllBase) - 3, ".so")) {
593 dllBase[strlen(dllBase) - 3] = '\0';
594 }
595
596 if (*dllBase == '/') {
597 subpath = dllBase;
598 dllBase = strdup(strrchr(subpath, '/') + 1);
599 } else {
600 subpath = (char *)malloc(strlen(directory) + strlen(dllBase) + 2);
601 sprintf(subpath, "%s/%s", directory, dllBase);
602 }
603
604 for (fuzzy = 0; fuzzy <= 1; ++fuzzy) {
605
606 if (!(subdir = opendir(subpath))) {
607 if (verbose) {
608 fprintf(stderr, "%s: can't open plugin GUI directory \"%s\"\n", myName, subpath);
609 }
610 free(subpath);
611 free(dllBase);
612 return;
613 }
614
615 while ((entry = readdir(subdir))) {
616
617 if (entry->d_name[0] == '.') continue;
618 if (!strchr(entry->d_name, '_')) continue;
619
620 if (fuzzy) {
621 if (verbose) {
622 fprintf(stderr, "checking %s against %s\n", entry->d_name, dllBase);
623 }
624 if (strlen(entry->d_name) <= strlen(dllBase) ||
625 strncmp(entry->d_name, dllBase, strlen(dllBase)) ||
626 entry->d_name[strlen(dllBase)] != '_')
627 continue;
628 } else {
629 if (verbose) {
630 fprintf(stderr, "checking %s against %s\n", entry->d_name, label);
631 }
632 if (strlen(entry->d_name) <= strlen(label) ||
633 strncmp(entry->d_name, label, strlen(label)) ||
634 entry->d_name[strlen(label)] != '_')
635 continue;
636 }
637
638 filename = (char *)malloc(strlen(subpath) + strlen(entry->d_name) + 2);
639 sprintf(filename, "%s/%s", subpath, entry->d_name);
640
641 if (stat(filename, &buf)) {
642 perror("stat failed");
643 free(filename);
644 continue;
645 }
646
647 if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) &&
648 (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
649
650 if (verbose) {
651 fprintf(stderr, "%s: trying to execute GUI at \"%s\"\n",
652 myName, filename);
653 }
654
655 if (fork() == 0) {
656 execlp(filename, filename, oscUrl, dllName, label, instanceTag, NULL);
657 perror("exec failed");
658 exit(1);
659 }
660
661 free(filename);
662 free(subpath);
663 free(dllBase);
664 return;
665 }
666
667 free(filename);
668 }
669 }
670
671 if (verbose) {
672 fprintf(stderr, "%s: no GUI found for plugin \"%s\" in \"%s/\"\n",
673 myName, label, subpath);
674 }
675 free(subpath);
676 free(dllBase);
677 }
678
679 void
query_programs(d3h_instance_t * instance)680 query_programs(d3h_instance_t *instance)
681 {
682 int i;
683
684 /* free old lot */
685 if (instance->pluginPrograms) {
686 for (i = 0; i < instance->pluginProgramCount; i++)
687 free((void *)instance->pluginPrograms[i].Name);
688 free((char *)instance->pluginPrograms);
689 instance->pluginPrograms = NULL;
690 instance->pluginProgramCount = 0;
691 }
692
693 instance->pendingBankLSB = -1;
694 instance->pendingBankMSB = -1;
695 instance->pendingProgramChange = -1;
696
697 if (instance->plugin->descriptor->get_program &&
698 instance->plugin->descriptor->select_program) {
699
700 /* Count the plugins first */
701 for (i = 0; instance->plugin->descriptor->
702 get_program(instanceHandles[instance->number], i); ++i);
703
704 if (i > 0) {
705 instance->pluginProgramCount = i;
706 instance->pluginPrograms = (DSSI_Program_Descriptor *)
707 malloc(i * sizeof(DSSI_Program_Descriptor));
708 while (i > 0) {
709 const DSSI_Program_Descriptor *descriptor;
710 --i;
711 descriptor = instance->plugin->descriptor->
712 get_program(instanceHandles[instance->number], i);
713 instance->pluginPrograms[i].Bank = descriptor->Bank;
714 instance->pluginPrograms[i].Program = descriptor->Program;
715 instance->pluginPrograms[i].Name = strdup(descriptor->Name);
716 if (verbose) {
717 printf("%s: %s program %d is MIDI bank %lu program %lu, named '%s'\n",
718 myName, instance->friendly_name, i,
719 instance->pluginPrograms[i].Bank,
720 instance->pluginPrograms[i].Program,
721 instance->pluginPrograms[i].Name);
722 }
723 }
724 }
725 }
726 }
727
728 int
main(int argc,char ** argv)729 main(int argc, char **argv)
730 {
731 int portid;
732 int npfd;
733 struct pollfd *pfd;
734
735 d3h_dll_t *dll;
736 d3h_plugin_t *plugin;
737 d3h_instance_t *instance;
738 void *pluginObject;
739 char *dllName;
740 char *label;
741 const char **ports;
742 char *tmp;
743 char *url;
744 int i, reps, j;
745 int in, out, controlIn, controlOut;
746 char clientName[33];
747 int haveClientName = 0;
748 const int clientLen = 32;
749 jack_status_t status;
750
751 setsid();
752 sigemptyset (&_signals);
753 sigaddset(&_signals, SIGHUP);
754 sigaddset(&_signals, SIGINT);
755 sigaddset(&_signals, SIGQUIT);
756 sigaddset(&_signals, SIGPIPE);
757 sigaddset(&_signals, SIGTERM);
758 sigaddset(&_signals, SIGUSR1);
759 sigaddset(&_signals, SIGUSR2);
760 pthread_sigmask(SIG_BLOCK, &_signals, 0);
761
762 insTotal = outsTotal = controlInsTotal = controlOutsTotal = 0;
763
764 /* Handle run-plugin-from-executable-name special case */
765
766 if (argc == 1) {
767
768 const char *basename = strrchr(argv[0], '/');
769 if (!basename) basename = argv[0];
770 else ++basename;
771
772 if (basename[0] && strcmp(basename, "jack-dssi-host")) {
773 /* look for basename + .so as plugin */
774 dllName = malloc(strlen(basename) + 4);
775 sprintf(dllName, "%s.so", basename);
776 if (load(dllName, &pluginObject, 1)) {
777 dlclose(pluginObject);
778 argc = 2;
779 myName = strdup(argv[0]);
780 argv = (char **)malloc(2 * sizeof(char *));
781 argv[0] = "jack-dssi-host";
782 argv[1] = dllName;
783 }
784 }
785 }
786
787 if (!myName) myName = strdup(argv[0]);
788
789 /* Parse args and report usage */
790
791 if (argc < 2) {
792 fprintf(stderr, "\nUsage: %s [-v] [-a] [-n] [-p <projdir>] [-c <cname>] [-<i>] <libname>[%c<label>] [...]\n", argv[0], LABEL_SEP);
793 fprintf(stderr, "\n -v Verbose mode\n");
794 fprintf(stderr, " -a Don't autoconnect outputs to JACK physical outputs\n");
795 fprintf(stderr, " -n Don't automatically start plugin GUIs\n");
796 fprintf(stderr, " <projdir> Project directory to pass to plugin and UI\n");
797 fprintf(stderr, " <cname> Client name to use for ALSA and JACK\n");
798 fprintf(stderr, " <i> Number of instances of each plugin to run (max %d total, default 1)\n", D3H_MAX_INSTANCES);
799 fprintf(stderr, " <libname> DSSI plugin library .so to load (searched for in $DSSI_PATH)\n");
800 fprintf(stderr, " <label> Label of plugin to load from library\n");
801 fprintf(stderr, " [...] Optionally more instance counts, plugins and labels\n");
802 fprintf(stderr, "\nExample: %s -2 lib1.so -1 lib2.so%cfuzzy\n", argv[0], LABEL_SEP);
803 fprintf(stderr, " run two instances of the first plugin found in lib1.so, assigned to MIDI\n channels 0 and 1 and connected to the first available JACK outputs, and one\n instance of the \"fuzzy\" plugin in lib2.so with MIDI channels 2 and 3 and\n connected to the next available JACK outputs.\n");
804 fprintf(stderr,"\nAs a special case, if this program is started with a name other than\njack-dssi-host, and if that name (plus .so suffix) can be found in the DSSI path\nas a valid plugin library, and if no further command line arguments are given,\nthen the first plugin in that library will be loaded automatically.\n\n");
805 return 2;
806 }
807
808 if (verbose) {
809 fprintf(stderr, "%s: Starting...\n", myName);
810 }
811
812 projectDirectory = NULL;
813
814 reps = 1;
815 for (i = 1; i < argc; i++) {
816
817 if (!strcmp(argv[i], "-v")) {
818 verbose = 1;
819 continue;
820 }
821 if (!strcmp(argv[i], "-a")) {
822 autoconnect = 0;
823 continue;
824 }
825 if (!strcmp(argv[i], "-n")) {
826 load_guis = 0;
827 continue;
828 }
829
830 if (!strcmp(argv[i], "-p")) {
831 if (i < argc - 1) {
832 projectDirectory = argv[++i];
833 } else {
834 fprintf(stderr, "%s: project directory expected after -p\n", myName);
835 return 2;
836 }
837 continue;
838 }
839
840 if (!strcmp(argv[i], "-c")) {
841 if (i < argc - 1) {
842 strncpy(clientName, argv[++i], clientLen);
843 clientName[clientLen] = '\0';
844 haveClientName = 1;
845 } else {
846 fprintf(stderr, "%s: client name expected after -c\n", myName);
847 return 2;
848 }
849 continue;
850 }
851
852 if (instance_count >= D3H_MAX_INSTANCES) {
853 fprintf(stderr, "%s: too many plugin instances specified (max is %d)\n", myName, D3H_MAX_INSTANCES);
854 return 2;
855 }
856
857 /* parse repetition count */
858 if (argv[i][0] == '-') {
859 reps = atoi(&argv[i][1]);
860 if (reps > 0) {
861 continue;
862 } else {
863 reps = 1;
864 }
865 }
866
867 /* parse dll name, plus a label if supplied */
868 tmp = strchr(argv[i], LABEL_SEP);
869 if (tmp) {
870 dllName = calloc(1, tmp - argv[i] + 1);
871 strncpy(dllName, argv[i], tmp - argv[i]);
872 label = strdup(tmp + 1);
873 } else {
874 dllName = strdup(argv[i]);
875 label = NULL;
876 }
877
878 /* check if we've seen this plugin before */
879 for (plugin = plugins; plugin; plugin = plugin->next) {
880 if (label) {
881 if (!strcmp(dllName, plugin->dll->name) &&
882 !strcmp(label, plugin->label))
883 break;
884 } else {
885 if (!strcmp(dllName, plugin->dll->name) &&
886 plugin->is_first_in_dll)
887 break;
888 }
889 }
890
891 if (plugin) {
892 /* have already seen this plugin */
893
894 free(dllName);
895 free(label);
896
897 } else {
898 /* this is a new plugin */
899
900 plugin = (d3h_plugin_t *)calloc(1, sizeof(d3h_plugin_t));
901 plugin->number = plugin_count;
902 plugin->label = label;
903
904 /* check if we've seen this dll before */
905 for (dll = dlls; dll; dll = dll->next) {
906 if (!strcmp(dllName, dll->name))
907 break;
908 }
909 if (!dll) {
910 /* this is a new dll */
911 dll = (d3h_dll_t *)calloc(1, sizeof(d3h_dll_t));
912 dll->name = dllName;
913
914 dll->directory = load(dllName, &pluginObject, 0);
915 if (!dll->directory || !pluginObject) {
916 fprintf(stderr, "\n%s: Error: Failed to load plugin library \"%s\"\n", myName, dllName);
917 return 1;
918 }
919
920 dll->descfn = (DSSI_Descriptor_Function)dlsym(pluginObject,
921 "dssi_descriptor");
922 if (dll->descfn) {
923 dll->is_DSSI_dll = 1;
924 } else {
925 dll->descfn = (DSSI_Descriptor_Function)dlsym(pluginObject,
926 "ladspa_descriptor");
927 if (!dll->descfn) {
928 fprintf(stderr, "\n%s: Error: \"%s\" is not a DSSI or LADSPA plugin library\n", myName, dllName);
929 return 1;
930 }
931 dll->is_DSSI_dll = 0;
932 }
933
934 dll->next = dlls;
935 dlls = dll;
936 }
937 plugin->dll = dll;
938
939 /* get the plugin descriptor */
940 j = 0;
941 if (dll->is_DSSI_dll) {
942 const DSSI_Descriptor *desc;
943
944 while ((desc = dll->descfn(j++))) {
945 if (!plugin->label ||
946 !strcmp(desc->LADSPA_Plugin->Label, plugin->label)) {
947 plugin->descriptor = desc;
948 break;
949 }
950 }
951 } else { /* LADSPA plugin; create and use a dummy DSSI descriptor */
952 LADSPA_Descriptor *desc;
953
954 plugin->descriptor = (const DSSI_Descriptor *)calloc(1, sizeof(DSSI_Descriptor));
955 ((DSSI_Descriptor *)plugin->descriptor)->DSSI_API_Version = 1;
956
957 while ((desc = (LADSPA_Descriptor *)dll->descfn(j++))) {
958 if (!plugin->label ||
959 !strcmp(desc->Label, plugin->label)) {
960 ((DSSI_Descriptor *)plugin->descriptor)->LADSPA_Plugin = desc;
961 break;
962 }
963 }
964 if (!plugin->descriptor->LADSPA_Plugin) {
965 free((void *)plugin->descriptor);
966 plugin->descriptor = NULL;
967 }
968 }
969 if (!plugin->descriptor) {
970 fprintf(stderr, "\n%s: Error: Plugin label \"%s\" not found in library \"%s\"\n",
971 myName, plugin->label ? plugin->label : "(none)", dllName);
972 return 1;
973 }
974 plugin->is_first_in_dll = (j = 1);
975 if (!plugin->label) {
976 plugin->label = strdup(plugin->descriptor->LADSPA_Plugin->Label);
977 }
978
979 /* Count number of i/o buffers and ports required */
980 plugin->ins = 0;
981 plugin->outs = 0;
982 plugin->controlIns = 0;
983 plugin->controlOuts = 0;
984
985 for (j = 0; j < plugin->descriptor->LADSPA_Plugin->PortCount; j++) {
986
987 LADSPA_PortDescriptor pod =
988 plugin->descriptor->LADSPA_Plugin->PortDescriptors[j];
989
990 if (LADSPA_IS_PORT_AUDIO(pod)) {
991
992 if (LADSPA_IS_PORT_INPUT(pod)) ++plugin->ins;
993 else if (LADSPA_IS_PORT_OUTPUT(pod)) ++plugin->outs;
994
995 } else if (LADSPA_IS_PORT_CONTROL(pod)) {
996
997 if (LADSPA_IS_PORT_INPUT(pod)) ++plugin->controlIns;
998 else if (LADSPA_IS_PORT_OUTPUT(pod)) ++plugin->controlOuts;
999 }
1000 }
1001
1002 /* finish up new plugin */
1003 plugin->instances = 0;
1004 plugin->next = plugins;
1005 plugins = plugin;
1006 plugin_count++;
1007 }
1008
1009 /* set up instances */
1010 for (j = 0; j < reps; j++) {
1011 if (instance_count < D3H_MAX_INSTANCES) {
1012 instance = &instances[instance_count];
1013
1014 instance->plugin = plugin;
1015 instance->channel = instance_count;
1016 instance->inactive = 1;
1017 tmp = (char *)malloc(strlen(plugin->dll->name) +
1018 strlen(plugin->label) + 9);
1019 instance->friendly_name = tmp;
1020 strcpy(tmp, plugin->dll->name);
1021 if (strlen(tmp) > 3 &&
1022 !strcasecmp(tmp + strlen(tmp) - 3, ".so")) {
1023 tmp = tmp + strlen(tmp) - 3;
1024 } else {
1025 tmp = tmp + strlen(tmp);
1026 }
1027 sprintf(tmp, "/%s/chan%02d", plugin->label, instance->channel);
1028 instance->pluginProgramCount = 0;
1029 instance->pluginPrograms = NULL;
1030 instance->currentBank = 0;
1031 instance->currentProgram = 0;
1032 instance->pendingBankLSB = -1;
1033 instance->pendingBankMSB = -1;
1034 instance->pendingProgramChange = -1;
1035 instance->uiTarget = NULL;
1036 instance->uiSource = NULL;
1037 instance->ui_initial_show_sent = 0;
1038 instance->uiNeedsProgramUpdate = 0;
1039 instance->ui_osc_control_path = NULL;
1040 instance->ui_osc_program_path = NULL;
1041 instance->ui_osc_quit_path = NULL;
1042 instance->ui_osc_rate_path = NULL;
1043 instance->ui_osc_show_path = NULL;
1044
1045 insTotal += plugin->ins;
1046 outsTotal += plugin->outs;
1047 controlInsTotal += plugin->controlIns;
1048 controlOutsTotal += plugin->controlOuts;
1049
1050 plugin->instances++;
1051 instance_count++;
1052 } else {
1053 fprintf(stderr, "%s: too many plugin instances specified\n", myName);
1054 return 2;
1055 }
1056 }
1057 reps = 1;
1058 }
1059
1060 if (instance_count == 0) {
1061 fprintf(stderr, "%s: No plugin specified\n", myName);
1062 return 2;
1063 }
1064
1065 /* sort array of instances to group them by plugin */
1066 if (instance_count > 1) {
1067 qsort(instances, instance_count, sizeof(d3h_instance_t), instance_sort_cmp);
1068 }
1069
1070 /* build channel2instance[] while showing what our instances are */
1071 for (i = 0; i < D3H_MAX_CHANNELS; i++)
1072 channel2instance[i] = NULL;
1073 for (i = 0; i < instance_count; i++) {
1074 instance = &instances[i];
1075 instance->number = i;
1076 channel2instance[instance->channel] = instance;
1077 if (verbose) {
1078 fprintf(stderr, "%s: instance %2d on channel %2d, plugin %2d is \"%s\"\n",
1079 myName, i, instance->channel, instance->plugin->number,
1080 instance->friendly_name);
1081 }
1082 }
1083
1084 /* Create buffers and JACK client and ports */
1085
1086 if (!haveClientName) {
1087 if (instance_count > 1) strcpy(clientName, "jack-dssi-host");
1088 else {
1089 strncpy(clientName, instances[0].plugin->descriptor->LADSPA_Plugin->Name, clientLen);
1090 clientName[clientLen] = '\0';
1091 }
1092 }
1093
1094 if ((jackClient = jack_client_open(clientName, 0, &status)) == 0) {
1095 fprintf(stderr, "\n%s: Error: Failed to connect to JACK server\n",
1096 myName);
1097 return 1;
1098 }
1099 if (status & JackNameNotUnique) {
1100 strncpy(clientName, jack_get_client_name(jackClient), clientLen);
1101 clientName[clientLen] = '\0';
1102 }
1103
1104 sample_rate = jack_get_sample_rate(jackClient);
1105
1106 inputPorts = (jack_port_t **)malloc(insTotal * sizeof(jack_port_t *));
1107 pluginInputBuffers = (float **)malloc(insTotal * sizeof(float *));
1108 pluginControlIns = (float *)calloc(controlInsTotal, sizeof(float));
1109 pluginControlInInstances =
1110 (d3h_instance_t **)malloc(controlInsTotal * sizeof(d3h_instance_t *));
1111 pluginControlInPortNumbers =
1112 (unsigned long *)malloc(controlInsTotal * sizeof(unsigned long));
1113 pluginPortUpdated = (int *)malloc(controlInsTotal * sizeof(int));
1114
1115 outputPorts = (jack_port_t **)malloc(outsTotal * sizeof(jack_port_t *));
1116 pluginOutputBuffers = (float **)malloc(outsTotal * sizeof(float *));
1117 pluginControlOuts = (float *)calloc(controlOutsTotal, sizeof(float));
1118
1119 instanceHandles = (LADSPA_Handle *)malloc(instance_count *
1120 sizeof(LADSPA_Handle));
1121 instanceEventBuffers = (snd_seq_event_t **)malloc(instance_count *
1122 sizeof(snd_seq_event_t *));
1123 instanceEventCounts = (unsigned long *)malloc(instance_count *
1124 sizeof(unsigned long));
1125
1126 for (i = 0; i < instance_count; i++) {
1127 instanceEventBuffers[i] = (snd_seq_event_t *)malloc(EVENT_BUFFER_SIZE *
1128 sizeof(snd_seq_event_t));
1129 instances[i].pluginPortControlInNumbers =
1130 (int *)malloc(instances[i].plugin->descriptor->LADSPA_Plugin->PortCount *
1131 sizeof(int));
1132 }
1133
1134 in = 0;
1135 out = 0;
1136 reps = 0;
1137 for (i = 0; i < instance_count; i++) {
1138 if (i > 0 &&
1139 !strcmp(instances[i ].plugin->descriptor->LADSPA_Plugin->Name,
1140 instances[i-1].plugin->descriptor->LADSPA_Plugin->Name)) {
1141 ++reps;
1142 } else if (i < instance_count - 1 &&
1143 !strcmp(instances[i ].plugin->descriptor->LADSPA_Plugin->Name,
1144 instances[i+1].plugin->descriptor->LADSPA_Plugin->Name)) {
1145 reps = 1;
1146 } else {
1147 reps = 0;
1148 }
1149 for (j = 0; j < instances[i].plugin->ins; ++j) {
1150 char portName[40];
1151 if (haveClientName) {
1152 /* if we're given a specific client name for the whole
1153 application, just name our individual ports by
1154 number rather than by instance
1155 */
1156 sprintf(portName, "in_%d", in);
1157 } else {
1158 strncpy(portName, instances[i].plugin->descriptor->LADSPA_Plugin->Name, 30);
1159 if (reps > 0) {
1160 portName[25] = '\0';
1161 sprintf(portName + strlen(portName), " %d in_%d", reps, j + 1);
1162 } else {
1163 portName[30] = '\0';
1164 sprintf(portName + strlen(portName), " in_%d", j + 1);
1165 }
1166 }
1167 inputPorts[in] = jack_port_register(jackClient, portName,
1168 JACK_DEFAULT_AUDIO_TYPE,
1169 JackPortIsInput, 0);
1170 pluginInputBuffers[in] =
1171 (float *)calloc(jack_get_buffer_size(jackClient), sizeof(float));
1172 ++in;
1173 }
1174 for (j = 0; j < instances[i].plugin->outs; ++j) {
1175 char portName[40];
1176 if (haveClientName) {
1177 /* if we're given a specific client name for the whole
1178 application, just name our individual ports by
1179 number rather than by instance
1180 */
1181 sprintf(portName, "out_%d", out);
1182 } else {
1183 strncpy(portName, instances[i].plugin->descriptor->LADSPA_Plugin->Name, 30);
1184 if (reps > 0) {
1185 portName[25] = '\0';
1186 sprintf(portName + strlen(portName), " %d out_%d", reps, j + 1);
1187 } else {
1188 portName[30] = '\0';
1189 sprintf(portName + strlen(portName), " out_%d", j + 1);
1190 }
1191 }
1192 outputPorts[out] = jack_port_register(jackClient, portName,
1193 JACK_DEFAULT_AUDIO_TYPE,
1194 JackPortIsOutput, 0);
1195 pluginOutputBuffers[out] =
1196 (float *)calloc(jack_get_buffer_size(jackClient), sizeof(float));
1197 ++out;
1198 }
1199 }
1200
1201 jack_set_process_callback(jackClient, audio_callback, 0);
1202
1203 /* Instantiate plugins */
1204
1205 for (i = 0; i < instance_count; i++) {
1206 plugin = instances[i].plugin;
1207 instanceHandles[i] = plugin->descriptor->LADSPA_Plugin->instantiate
1208 (plugin->descriptor->LADSPA_Plugin, sample_rate);
1209 if (!instanceHandles[i]) {
1210 fprintf(stderr, "\n%s: Error: Failed to instantiate instance %d!, plugin \"%s\"\n",
1211 myName, i, plugin->label);
1212 return 1;
1213 }
1214 if (projectDirectory && plugin->descriptor->configure) {
1215 char *rv =plugin->descriptor->configure(instanceHandles[i],
1216 DSSI_PROJECT_DIRECTORY_KEY,
1217 projectDirectory);
1218 if (rv) {
1219 fprintf(stderr, "%s: Warning: plugin doesn't like project directory: \"%s\"\n", myName, rv);
1220 }
1221 }
1222 }
1223
1224 /* Create OSC thread */
1225
1226 serverThread = lo_server_thread_new(NULL, osc_error);
1227 snprintf((char *)osc_path_tmp, 31, "/dssi");
1228 tmp = lo_server_thread_get_url(serverThread);
1229 url = (char *)malloc(strlen(tmp) + strlen(osc_path_tmp));
1230 sprintf(url, "%s%s", tmp, osc_path_tmp + 1);
1231 if (verbose) {
1232 printf("%s: registering %s\n", myName, url);
1233 }
1234 free(tmp);
1235
1236 lo_server_thread_add_method(serverThread, NULL, NULL, osc_message_handler,
1237 NULL);
1238 lo_server_thread_start(serverThread);
1239
1240 /* Connect and activate plugins */
1241
1242 for (in = 0; in < controlInsTotal; in++) {
1243 pluginPortUpdated[in] = 0;
1244 }
1245
1246 in = out = controlIn = controlOut = 0;
1247
1248 for (i = 0; i < instance_count; i++) { /* i is instance number */
1249 instance = &instances[i];
1250
1251 instance->firstControlIn = controlIn;
1252 for (j = 0; j < MIDI_CONTROLLER_COUNT; j++) {
1253 instance->controllerMap[j] = -1;
1254 }
1255
1256 plugin = instance->plugin;
1257 for (j = 0; j < plugin->descriptor->LADSPA_Plugin->PortCount; j++) { /* j is LADSPA port number */
1258
1259 LADSPA_PortDescriptor pod =
1260 plugin->descriptor->LADSPA_Plugin->PortDescriptors[j];
1261
1262 instance->pluginPortControlInNumbers[j] = -1;
1263
1264 if (LADSPA_IS_PORT_AUDIO(pod)) {
1265
1266 if (LADSPA_IS_PORT_INPUT(pod)) {
1267 plugin->descriptor->LADSPA_Plugin->connect_port
1268 (instanceHandles[i], j, pluginInputBuffers[in++]);
1269
1270 } else if (LADSPA_IS_PORT_OUTPUT(pod)) {
1271 plugin->descriptor->LADSPA_Plugin->connect_port
1272 (instanceHandles[i], j, pluginOutputBuffers[out++]);
1273 }
1274
1275 } else if (LADSPA_IS_PORT_CONTROL(pod)) {
1276
1277 if (LADSPA_IS_PORT_INPUT(pod)) {
1278
1279 if (plugin->descriptor->get_midi_controller_for_port) {
1280
1281 int controller = plugin->descriptor->
1282 get_midi_controller_for_port(instanceHandles[i], j);
1283
1284 if (controller == 0) {
1285 MB_MESSAGE
1286 ("Buggy plugin: wants mapping for bank MSB\n");
1287 } else if (controller == 32) {
1288 MB_MESSAGE
1289 ("Buggy plugin: wants mapping for bank LSB\n");
1290 } else if (DSSI_IS_CC(controller)) {
1291 instance->controllerMap[DSSI_CC_NUMBER(controller)]
1292 = controlIn;
1293 }
1294 }
1295
1296 pluginControlInInstances[controlIn] = instance;
1297 pluginControlInPortNumbers[controlIn] = j;
1298 instance->pluginPortControlInNumbers[j] = controlIn;
1299
1300 pluginControlIns[controlIn] = get_port_default
1301 (plugin->descriptor->LADSPA_Plugin, j);
1302
1303 plugin->descriptor->LADSPA_Plugin->connect_port
1304 (instanceHandles[i], j, &pluginControlIns[controlIn++]);
1305
1306 } else if (LADSPA_IS_PORT_OUTPUT(pod)) {
1307 plugin->descriptor->LADSPA_Plugin->connect_port
1308 (instanceHandles[i], j, &pluginControlOuts[controlOut++]);
1309 }
1310 }
1311 } /* 'for (j...' LADSPA port number */
1312
1313 if (plugin->descriptor->LADSPA_Plugin->activate) {
1314 plugin->descriptor->LADSPA_Plugin->activate(instanceHandles[i]);
1315 }
1316 instance->inactive = 0;
1317 } /* 'for (i...' instance number */
1318
1319 assert(in == insTotal);
1320 assert(out == outsTotal);
1321 assert(controlIn == controlInsTotal);
1322 assert(controlOut == controlOutsTotal);
1323
1324 /* Look up synth programs */
1325
1326 for (i = 0; i < instance_count; i++) {
1327 instance = &instances[i];
1328
1329 query_programs(instance);
1330
1331 if (instance->plugin->descriptor->select_program &&
1332 instance->pluginProgramCount > 0) {
1333
1334 /* select program at index 0 */
1335 unsigned long bank = instance->pluginPrograms[0].Bank;
1336 instance->pendingBankMSB = bank / 128;
1337 instance->pendingBankLSB = bank % 128;
1338 instance->pendingProgramChange = instance->pluginPrograms[0].Program;
1339 instance->uiNeedsProgramUpdate = 1;
1340 }
1341 }
1342
1343 /* Create ALSA MIDI port */
1344
1345 #ifdef MIDI_ALSA
1346 if (snd_seq_open(&alsaClient, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
1347 fprintf(stderr, "\n%s: Error: Failed to open ALSA sequencer interface\n",
1348 myName);
1349 return 1;
1350 }
1351
1352 snd_seq_set_client_name(alsaClient, clientName);
1353
1354 if ((portid = snd_seq_create_simple_port
1355 (alsaClient, clientName,
1356 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
1357 fprintf(stderr, "\n%s: Error: Failed to create ALSA sequencer port\n",
1358 myName);
1359 return 1;
1360 }
1361
1362 npfd = snd_seq_poll_descriptors_count(alsaClient, POLLIN);
1363 pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
1364 snd_seq_poll_descriptors(alsaClient, pfd, npfd, POLLIN);
1365 #endif /* MIDI_ALSA */
1366
1367 mb_init("host: ");
1368
1369 /* activate JACK and connect ports */
1370 if (jack_activate(jackClient)) {
1371 fprintf (stderr, "cannot activate jack client");
1372 exit(1);
1373 }
1374
1375 if (autoconnect) {
1376 /* !FIX! this to more intelligently connect ports: */
1377 ports = jack_get_ports(jackClient, NULL,
1378 "^" JACK_DEFAULT_AUDIO_TYPE "$",
1379 JackPortIsPhysical|JackPortIsInput);
1380 if (ports && ports[0]) {
1381 for (i = 0, j = 0; i < outsTotal; ++i) {
1382 if (jack_connect(jackClient, jack_port_name(outputPorts[i]),
1383 ports[j])) {
1384 fprintf (stderr, "cannot connect output port %d\n", i);
1385 }
1386 if (!ports[++j]) j = 0;
1387 }
1388 free(ports);
1389 }
1390 }
1391
1392 signal(SIGINT, signalHandler);
1393 signal(SIGTERM, signalHandler);
1394 signal(SIGHUP, signalHandler);
1395 signal(SIGQUIT, signalHandler);
1396 pthread_sigmask(SIG_UNBLOCK, &_signals, 0);
1397
1398 /* Attempt to locate and start up a GUI for the plugin -- but
1399 * continue even if we can't */
1400 /* -FIX- Ack! So many windows all at once! */
1401 if (load_guis) {
1402 for (i = 0; i < instance_count; i++) {
1403 char tag[12];
1404 plugin = instances[i].plugin;
1405 snprintf(osc_path_tmp, 1024, "%s/%s", url, instances[i].friendly_name);
1406 snprintf(tag, 12, "channel %d", instances[i].channel);
1407 printf("\n%s: OSC URL is:\n%s\n\n", myName, osc_path_tmp);
1408 fflush(stdout);
1409 startGUI(plugin->dll->directory, plugin->dll->name,
1410 plugin->descriptor->LADSPA_Plugin->Label, osc_path_tmp, tag);
1411 }
1412 }
1413
1414 MB_MESSAGE("Ready\n");
1415
1416 exiting = 0;
1417
1418 while (!exiting) {
1419
1420 #ifdef MIDI_ALSA
1421 if (poll(pfd, npfd, 100) > 0) {
1422 midi_callback();
1423 }
1424 #endif /* MIDI_ALSA */
1425
1426 /* Race conditions here, because the programs and ports are
1427 updated from the audio thread. We at least try to minimise
1428 trouble by copying out before the expensive OSC call */
1429
1430 for (i = 0; i < instance_count; i++) {
1431 instance = &instances[i];
1432 if (instance->uiNeedsProgramUpdate && instance->pendingProgramChange < 0) {
1433 int bank = instance->currentBank;
1434 int program = instance->currentProgram;
1435 instance->uiNeedsProgramUpdate = 0;
1436 if (instance->uiTarget) {
1437 lo_send(instance->uiTarget, instance->ui_osc_program_path, "ii", bank, program);
1438 }
1439 }
1440 }
1441
1442 for (i = 0; i < controlInsTotal; ++i) {
1443 if (pluginPortUpdated[i]) {
1444 int port = pluginControlInPortNumbers[i];
1445 float value = pluginControlIns[i];
1446 instance = pluginControlInInstances[i];
1447 pluginPortUpdated[i] = 0;
1448 if (instance->uiTarget) {
1449 lo_send(instance->uiTarget, instance->ui_osc_control_path, "if", port, value);
1450 }
1451 }
1452 }
1453 }
1454
1455 jack_client_close(jackClient);
1456
1457 /* cleanup plugins */
1458 for (i = 0; i < instance_count; i++) {
1459 instance = &instances[i];
1460
1461 if (instance->uiTarget) {
1462 lo_send(instance->uiTarget, instance->ui_osc_quit_path, "");
1463 lo_address_free(instance->uiTarget);
1464 instance->uiTarget = NULL;
1465 }
1466
1467 if (instance->uiSource) {
1468 lo_address_free(instance->uiSource);
1469 instance->uiSource = NULL;
1470 }
1471
1472 if (instance->plugin->descriptor->LADSPA_Plugin->deactivate) {
1473 instance->plugin->descriptor->LADSPA_Plugin->deactivate
1474 (instanceHandles[i]);
1475 }
1476
1477 if (instance->plugin->descriptor->LADSPA_Plugin->cleanup) {
1478 instance->plugin->descriptor->LADSPA_Plugin->cleanup
1479 (instanceHandles[i]);
1480 }
1481 }
1482
1483 sleep(1);
1484 sigemptyset (&_signals);
1485 sigaddset(&_signals, SIGHUP);
1486 pthread_sigmask(SIG_BLOCK, &_signals, 0);
1487 kill(0, SIGHUP);
1488
1489 return 0;
1490 }
1491
get_port_default(const LADSPA_Descriptor * plugin,int port)1492 LADSPA_Data get_port_default(const LADSPA_Descriptor *plugin, int port)
1493 {
1494 LADSPA_PortRangeHint hint = plugin->PortRangeHints[port];
1495 float lower = hint.LowerBound *
1496 (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? sample_rate : 1.0f);
1497 float upper = hint.UpperBound *
1498 (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? sample_rate : 1.0f);
1499
1500 if (!LADSPA_IS_HINT_HAS_DEFAULT(hint.HintDescriptor)) {
1501 if (!LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) ||
1502 !LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) {
1503 /* No hint, its not bounded, wild guess */
1504 return 0.0f;
1505 }
1506
1507 if (lower <= 0.0f && upper >= 0.0f) {
1508 /* It spans 0.0, 0.0 is often a good guess */
1509 return 0.0f;
1510 }
1511
1512 /* No clues, return minimum */
1513 return lower;
1514 }
1515
1516 /* Try all the easy ones */
1517
1518 if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor)) {
1519 return 0.0f;
1520 } else if (LADSPA_IS_HINT_DEFAULT_1(hint.HintDescriptor)) {
1521 return 1.0f;
1522 } else if (LADSPA_IS_HINT_DEFAULT_100(hint.HintDescriptor)) {
1523 return 100.0f;
1524 } else if (LADSPA_IS_HINT_DEFAULT_440(hint.HintDescriptor)) {
1525 return 440.0f;
1526 }
1527
1528 /* All the others require some bounds */
1529
1530 if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) {
1531 if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor)) {
1532 return lower;
1533 }
1534 }
1535 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) {
1536 if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor)) {
1537 return upper;
1538 }
1539 if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) {
1540 if (LADSPA_IS_HINT_LOGARITHMIC(hint.HintDescriptor) &&
1541 lower > 0.0f && upper > 0.0f) {
1542 if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) {
1543 return expf(logf(lower) * 0.75f + logf(upper) * 0.25f);
1544 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) {
1545 return expf(logf(lower) * 0.5f + logf(upper) * 0.5f);
1546 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) {
1547 return expf(logf(lower) * 0.25f + logf(upper) * 0.75f);
1548 }
1549 } else {
1550 if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) {
1551 return lower * 0.75f + upper * 0.25f;
1552 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) {
1553 return lower * 0.5f + upper * 0.5f;
1554 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) {
1555 return lower * 0.25f + upper * 0.75f;
1556 }
1557 }
1558 }
1559 }
1560
1561 /* fallback */
1562 return 0.0f;
1563 }
1564
osc_error(int num,const char * msg,const char * path)1565 void osc_error(int num, const char *msg, const char *path)
1566 {
1567 fprintf(stderr, "%s: liblo server error %d in path %s: %s\n",
1568 myName, num, path, msg);
1569 }
1570
1571 int
osc_midi_handler(d3h_instance_t * instance,lo_arg ** argv)1572 osc_midi_handler(d3h_instance_t *instance, lo_arg **argv)
1573 {
1574 static snd_midi_event_t *alsaCoder = NULL;
1575 static snd_seq_event_t alsaEncodeBuffer[10];
1576 long count;
1577 snd_seq_event_t *ev = &alsaEncodeBuffer[0];
1578
1579 if (verbose) {
1580 printf("%s: OSC: got midi request for %s "
1581 "(%02x %02x %02x %02x)\n", myName, instance->friendly_name,
1582 argv[0]->m[0], argv[0]->m[1], argv[0]->m[2], argv[0]->m[3]);
1583 }
1584
1585 if (!alsaCoder) {
1586 if (snd_midi_event_new(10, &alsaCoder)) {
1587 fprintf(stderr, "%s: Failed to initialise ALSA MIDI coder!\n",
1588 myName);
1589 return 0;
1590 }
1591 }
1592
1593 snd_midi_event_reset_encode(alsaCoder);
1594
1595 count = snd_midi_event_encode
1596 (alsaCoder, (argv[0]->m) + 1, 3, alsaEncodeBuffer); /* ignore OSC "port id" in argv[0]->m[0] */
1597
1598 if (!count || !snd_seq_ev_is_channel_type(ev)) {
1599 return 0;
1600 }
1601
1602 /* substitute correct MIDI channel */
1603 ev->data.note.channel = instance->channel;
1604
1605 if (ev->type == SND_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0) {
1606 ev->type = SND_SEQ_EVENT_NOTEOFF;
1607 }
1608
1609 pthread_mutex_lock(&midiEventBufferMutex);
1610
1611 if (midiEventReadIndex == midiEventWriteIndex + 1) {
1612
1613 fprintf(stderr, "%s: Warning: MIDI event buffer overflow!\n", myName);
1614
1615 } else if (ev->type == SND_SEQ_EVENT_CONTROLLER &&
1616 (ev->data.control.param == 0 || ev->data.control.param == 32)) {
1617
1618 fprintf(stderr, "%s: Warning: %s UI sent bank select controller (should use /program OSC call), ignoring\n", myName, instance->friendly_name);
1619
1620 } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) {
1621
1622 fprintf(stderr, "%s: Warning: %s UI sent program change (should use /program OSC call), ignoring\n", myName, instance->friendly_name);
1623
1624 } else {
1625
1626 midiEventBuffer[midiEventWriteIndex] = *ev;
1627 midiEventWriteIndex = (midiEventWriteIndex + 1) % EVENT_BUFFER_SIZE;
1628
1629 }
1630
1631 pthread_mutex_unlock(&midiEventBufferMutex);
1632
1633 return 0;
1634 }
1635
1636 int
osc_control_handler(d3h_instance_t * instance,lo_arg ** argv)1637 osc_control_handler(d3h_instance_t *instance, lo_arg **argv)
1638 {
1639 int port = argv[0]->i;
1640 LADSPA_Data value = argv[1]->f;
1641
1642 if (port < 0 || port > instance->plugin->descriptor->LADSPA_Plugin->PortCount) {
1643 fprintf(stderr, "%s: OSC: %s port number (%d) is out of range\n",
1644 myName, instance->friendly_name, port);
1645 return 0;
1646 }
1647 if (instance->pluginPortControlInNumbers[port] == -1) {
1648 fprintf(stderr, "%s: OSC: %s port %d is not a control in\n",
1649 myName, instance->friendly_name, port);
1650 return 0;
1651 }
1652 pluginControlIns[instance->pluginPortControlInNumbers[port]] = value;
1653 if (verbose) {
1654 printf("%s: OSC: %s port %d = %f\n",
1655 myName, instance->friendly_name, port, value);
1656 }
1657
1658 return 0;
1659 }
1660
1661 int
osc_program_handler(d3h_instance_t * instance,lo_arg ** argv)1662 osc_program_handler(d3h_instance_t *instance, lo_arg **argv)
1663 {
1664 int bank = argv[0]->i;
1665 int program = argv[1]->i;
1666 int i;
1667 int found = 0;
1668
1669 for (i = 0; i < instance->pluginProgramCount; ++i) {
1670 if (instance->pluginPrograms[i].Bank == bank &&
1671 instance->pluginPrograms[i].Program == program) {
1672 if (verbose) {
1673 printf("%s: OSC: %s setting bank %d, program %d, name %s\n",
1674 myName,
1675 instance->friendly_name, bank, program,
1676 instance->pluginPrograms[i].Name);
1677 }
1678 found = 1;
1679 break;
1680 }
1681 }
1682
1683 if (!found) {
1684 printf("%s: OSC: %s UI requested unknown program: bank %d, program %d: sending to plugin anyway (plugin should ignore it)\n",
1685 myName, instance->friendly_name, bank, program);
1686 }
1687
1688 instance->pendingBankMSB = bank / 128;
1689 instance->pendingBankLSB = bank % 128;
1690 instance->pendingProgramChange = program;
1691
1692 return 0;
1693 }
1694
1695 int
osc_configure_handler(d3h_instance_t * instance,lo_arg ** argv)1696 osc_configure_handler(d3h_instance_t *instance, lo_arg **argv)
1697 {
1698 const char *key = (const char *)&argv[0]->s;
1699 const char *value = (const char *)&argv[1]->s;
1700 char *message;
1701
1702 /* This is pretty much the simplest legal implementation of
1703 * configure in a DSSI host. */
1704
1705 /* The host has the option to remember the set of (key,value)
1706 * pairs associated with a particular instance, so that if it
1707 * wants to restore the "same" instance on another occasion it can
1708 * just call configure() on it for each of those pairs and so
1709 * restore state without any input from a GUI. Any real-world GUI
1710 * host will probably want to do that. This host doesn't have any
1711 * concept of restoring an instance from one run to the next, so
1712 * we don't bother remembering these at all. */
1713
1714 if (instance->plugin->descriptor->configure) {
1715
1716 int n = instance->number;
1717 int m = n;
1718
1719 if (!strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX,
1720 strlen(DSSI_RESERVED_CONFIGURE_PREFIX))) {
1721 fprintf(stderr, "%s: OSC: UI for plugin '%s' attempted to use reserved configure key \"%s\", ignoring\n", myName, instance->friendly_name, key);
1722 return 0;
1723 }
1724
1725 if (instance->plugin->instances > 1 &&
1726 !strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX,
1727 strlen(DSSI_GLOBAL_CONFIGURE_PREFIX))) {
1728 while (n > 0 && instances[n-1].plugin == instances[m].plugin) --n;
1729 m = n + instances[n].plugin->instances - 1;
1730 }
1731
1732 while (n <= m) {
1733
1734 message = instances[n].plugin->descriptor->configure
1735 (instanceHandles[n], key, value);
1736 if (message) {
1737 printf("%s: on configure '%s' '%s', plugin '%s' returned error '%s'\n",
1738 myName, key, value, instance->friendly_name, message);
1739 free(message);
1740 }
1741
1742 // also call back on UIs for plugins other than the one
1743 // that requested this:
1744 if (n != instance->number && instances[n].uiTarget) {
1745 lo_send(instances[n].uiTarget,
1746 instances[n].ui_osc_configure_path, "ss", key, value);
1747 }
1748
1749 /* configure invalidates bank and program information, so
1750 we should do this again now: */
1751 query_programs(&instances[n]);
1752
1753 ++n;
1754 }
1755 }
1756
1757 return 0;
1758 }
1759
1760 int
osc_update_handler(d3h_instance_t * instance,lo_arg ** argv,lo_address source)1761 osc_update_handler(d3h_instance_t *instance, lo_arg **argv, lo_address source)
1762 {
1763 const char *url = (char *)&argv[0]->s;
1764 const char *path;
1765 unsigned int i;
1766 char *host, *port;
1767 const char *chost, *cport;
1768
1769 if (verbose) {
1770 printf("%s: OSC: got update request from <%s>\n", myName, url);
1771 }
1772
1773 if (instance->uiTarget) lo_address_free(instance->uiTarget);
1774 host = lo_url_get_hostname(url);
1775 port = lo_url_get_port(url);
1776 instance->uiTarget = lo_address_new(host, port);
1777 free(host);
1778 free(port);
1779
1780 if (instance->uiSource) lo_address_free(instance->uiSource);
1781 chost = lo_address_get_hostname(source);
1782 cport = lo_address_get_port(source);
1783 instance->uiSource = lo_address_new(chost, cport);
1784
1785 path = lo_url_get_path(url);
1786
1787 if (instance->ui_osc_control_path) free(instance->ui_osc_control_path);
1788 instance->ui_osc_control_path = (char *)malloc(strlen(path) + 10);
1789 sprintf(instance->ui_osc_control_path, "%s/control", path);
1790
1791 if (instance->ui_osc_configure_path) free(instance->ui_osc_configure_path);
1792 instance->ui_osc_configure_path = (char *)malloc(strlen(path) + 12);
1793 sprintf(instance->ui_osc_configure_path, "%s/configure", path);
1794
1795 if (instance->ui_osc_program_path) free(instance->ui_osc_program_path);
1796 instance->ui_osc_program_path = (char *)malloc(strlen(path) + 10);
1797 sprintf(instance->ui_osc_program_path, "%s/program", path);
1798
1799 if (instance->ui_osc_quit_path) free(instance->ui_osc_quit_path);
1800 instance->ui_osc_quit_path = (char *)malloc(strlen(path) + 10);
1801 sprintf(instance->ui_osc_quit_path, "%s/quit", path);
1802
1803 if (instance->ui_osc_rate_path) free(instance->ui_osc_rate_path);
1804 instance->ui_osc_rate_path = (char *)malloc(strlen(path) + 13);
1805 sprintf(instance->ui_osc_rate_path, "%s/sample-rate", path);
1806
1807 if (instance->ui_osc_show_path) free(instance->ui_osc_show_path);
1808 instance->ui_osc_show_path = (char *)malloc(strlen(path) + 10);
1809 sprintf(instance->ui_osc_show_path, "%s/show", path);
1810
1811 free((char *)path);
1812
1813 /* Send sample rate */
1814 lo_send(instance->uiTarget, instance->ui_osc_rate_path, "i", lrintf(sample_rate));
1815
1816 /* At this point a more substantial host might also call
1817 * configure() on the UI to set any state that it had remembered
1818 * for the plugin instance. But we don't remember state for
1819 * plugin instances (see our own configure() implementation in
1820 * osc_configure_handler), and so we have nothing to send except
1821 * the optional project directory. */
1822
1823 if (projectDirectory) {
1824 lo_send(instance->uiTarget, instance->ui_osc_configure_path, "ss",
1825 DSSI_PROJECT_DIRECTORY_KEY, projectDirectory);
1826 }
1827
1828 /* Send current bank/program (-FIX- another race...) */
1829 if (instance->pendingProgramChange < 0) {
1830 unsigned long bank = instance->currentBank;
1831 unsigned long program = instance->currentProgram;
1832 instance->uiNeedsProgramUpdate = 0;
1833 if (instance->uiTarget) {
1834 lo_send(instance->uiTarget, instance->ui_osc_program_path, "ii", bank, program);
1835 }
1836 }
1837
1838 /* Send control ports */
1839 for (i = 0; i < instance->plugin->controlIns; i++) {
1840 int in = i + instance->firstControlIn;
1841 int port = pluginControlInPortNumbers[in];
1842 lo_send(instance->uiTarget, instance->ui_osc_control_path, "if", port,
1843 pluginControlIns[in]);
1844 /* Avoid overloading the GUI if there are lots and lots of ports */
1845 if ((i+1) % 50 == 0) usleep(300000);
1846 }
1847
1848 /* Send 'show' */
1849 if (!instance->ui_initial_show_sent) {
1850 lo_send(instance->uiTarget, instance->ui_osc_show_path, "");
1851 instance->ui_initial_show_sent = 1;
1852 }
1853
1854 return 0;
1855 }
1856
1857 int
osc_exiting_handler(d3h_instance_t * instance,lo_arg ** argv)1858 osc_exiting_handler(d3h_instance_t *instance, lo_arg **argv)
1859 {
1860 int i;
1861
1862 if (verbose) {
1863 printf("%s: OSC: got exiting notification for instance %d\n", myName,
1864 instance->number);
1865 }
1866
1867 if (instance->uiTarget) {
1868 lo_address_free(instance->uiTarget);
1869 instance->uiTarget = NULL;
1870 }
1871
1872 if (instance->uiSource) {
1873 lo_address_free(instance->uiSource);
1874 instance->uiSource = NULL;
1875 }
1876
1877 if (instance->plugin) {
1878
1879 /*!!! No, this isn't safe -- plugins deactivated in this way
1880 would still be included in a run_multiple_synths call unless
1881 we re-jigged the instance array at the same time -- leave it
1882 for now
1883 if (instance->plugin->descriptor->LADSPA_Plugin->deactivate) {
1884 instance->plugin->descriptor->LADSPA_Plugin->deactivate
1885 (instanceHandles[instance->number]);
1886 }
1887 */
1888 /* Leave this flag though, as we need it to determine when to exit */
1889 instance->inactive = 1;
1890 }
1891
1892 /* Do we have any plugins left running? */
1893
1894 for (i = 0; i < instance_count; ++i) {
1895 if (!instances[i].inactive) return 0;
1896 }
1897
1898 if (verbose) {
1899 printf("%s: That was the last remaining plugin, exiting...\n", myName);
1900 }
1901 exiting = 1;
1902 return 0;
1903 }
1904
osc_debug_handler(const char * path,const char * types,lo_arg ** argv,int argc,void * data,void * user_data)1905 int osc_debug_handler(const char *path, const char *types, lo_arg **argv,
1906 int argc, void *data, void *user_data)
1907 {
1908 int i;
1909
1910 printf("%s: got unhandled OSC message:\npath: <%s>\n", myName, path);
1911 for (i=0; i<argc; i++) {
1912 printf("%s: arg %d '%c' ", myName, i, types[i]);
1913 lo_arg_pp(types[i], argv[i]);
1914 printf("\n");
1915 }
1916 printf("%s:\n", myName);
1917
1918 return 1;
1919 }
1920
osc_message_handler(const char * path,const char * types,lo_arg ** argv,int argc,void * data,void * user_data)1921 int osc_message_handler(const char *path, const char *types, lo_arg **argv,
1922 int argc, void *data, void *user_data)
1923 {
1924 int i;
1925 d3h_instance_t *instance = NULL;
1926 const char *method;
1927 unsigned int flen = 0;
1928 lo_message message;
1929 lo_address source;
1930 int send_to_ui = 0;
1931
1932 if (strncmp(path, "/dssi/", 6))
1933 return osc_debug_handler(path, types, argv, argc, data, user_data);
1934
1935 for (i = 0; i < instance_count; i++) {
1936 flen = strlen(instances[i].friendly_name);
1937 if (!strncmp(path + 6, instances[i].friendly_name, flen) &&
1938 *(path + 6 + flen) == '/') { /* avoid matching prefix only */
1939 instance = &instances[i];
1940 break;
1941 }
1942 }
1943 if (!instance)
1944 return osc_debug_handler(path, types, argv, argc, data, user_data);
1945
1946 /* no -- see comment in osc_exiting_handler */
1947 /*
1948 if (instance->inactive)
1949 return 0;
1950 */
1951 method = path + 6 + flen;
1952 if (*method != '/' || *(method + 1) == 0)
1953 return osc_debug_handler(path, types, argv, argc, data, user_data);
1954 method++;
1955
1956 message = (lo_message)data;
1957 source = lo_message_get_source(message);
1958
1959 if (instance->uiSource && instance->uiTarget) {
1960 if (strcmp(lo_address_get_hostname(source),
1961 lo_address_get_hostname(instance->uiSource)) ||
1962 strcmp(lo_address_get_port(source),
1963 lo_address_get_port(instance->uiSource))) {
1964 /* This didn't come from our known UI for this plugin,
1965 so send an update to that as well */
1966 send_to_ui = 1;
1967 }
1968 }
1969
1970 if (!strcmp(method, "configure") && argc == 2 && !strcmp(types, "ss")) {
1971
1972 if (send_to_ui) {
1973 lo_send(instance->uiTarget, instance->ui_osc_configure_path, "ss",
1974 &argv[0]->s, &argv[1]->s);
1975 }
1976
1977 return osc_configure_handler(instance, argv);
1978
1979 } else if (!strcmp(method, "control") && argc == 2 && !strcmp(types, "if")) {
1980
1981 if (send_to_ui) {
1982 lo_send(instance->uiTarget, instance->ui_osc_control_path, "if",
1983 argv[0]->i, argv[1]->f);
1984 }
1985
1986 return osc_control_handler(instance, argv);
1987
1988 } else if (!strcmp(method, "midi") && argc == 1 && !strcmp(types, "m")) {
1989
1990 return osc_midi_handler(instance, argv);
1991
1992 } else if (!strcmp(method, "program") && argc == 2 && !strcmp(types, "ii")) {
1993
1994 if (send_to_ui) {
1995 lo_send(instance->uiTarget, instance->ui_osc_program_path, "ii",
1996 argv[0]->i, argv[1]->i);
1997 }
1998
1999 return osc_program_handler(instance, argv);
2000
2001 } else if (!strcmp(method, "update") && argc == 1 && !strcmp(types, "s")) {
2002
2003 return osc_update_handler(instance, argv, source);
2004
2005 } else if (!strcmp(method, "exiting") && argc == 0) {
2006
2007 return osc_exiting_handler(instance, argv);
2008 }
2009
2010 return osc_debug_handler(path, types, argv, argc, data, user_data);
2011 }
2012
2013