1 /*
2 * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <dlfcn.h>
23 #include <string.h>
24 #include <ctype.h>
25
26 #include <sandbox_slave.h>
27 #include <sandbox_io.h>
28
29 #include <xpress.lv2/xpress.h>
30
31 #include <lv2/lv2plug.in/ns/ext/log/log.h>
32 #include <lv2/lv2plug.in/ns/ext/options/options.h>
33 #include <lv2/lv2plug.in/ns/ext/uri-map/uri-map.h>
34 #include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
35
36 #include <lilv/lilv.h>
37
38 #define MAPPER_IMPLEMENTATION
39 #include <mapper.lv2/mapper.h>
40
41 struct _sandbox_slave_t {
42 mapper_t *mapper;
43
44 LV2_URID_Map *map;
45 LV2_URID_Unmap *unmap;
46 #pragma GCC diagnostic push
47 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
48 LV2_URI_Map_Feature uri_id;
49 #pragma GCC diagnostic pop
50
51 LV2_URID log_trace;
52 LV2_URID log_error;
53 LV2_URID log_warning;
54 LV2_URID log_note;
55
56 LV2_Log_Log log;
57
58 LV2UI_Port_Map port_map;
59 LV2UI_Port_Subscribe port_subscribe;
60 xpress_map_t xmap;
61 xpress_t xpress;
62
63 LV2UI_Resize host_resize;
64
65 LilvWorld *world;
66 LilvNode *plugin_bundle_node;
67 LilvNode *ui_bundle_node;
68 LilvNode *plugin_node;
69 LilvNode *ui_node;
70
71 const LilvPlugin *plug;
72 LilvUIs *uis;
73 const LilvUI *ui;
74
75 bool no_user_resize;
76 void *lib;
77 const LV2UI_Descriptor *desc;
78 void *handle;
79
80 sandbox_io_t io;
81
82 const sandbox_slave_driver_t *driver;
83 void *data;
84
85 bool initialized;
86
87 const char *plugin_urn;
88 const char *plugin_uri;
89 const char *plugin_bundle_path;
90 const char *ui_uri;
91 const char *ui_bundle_path;
92 const char *socket_path;
93 const char *window_title;
94 uint32_t minimum;
95 float sample_rate;
96 float update_rate;
97 };
98
99 #define ANSI_COLOR_BOLD "\x1b[1m"
100 #define ANSI_COLOR_RED "\x1b[31m"
101 #define ANSI_COLOR_GREEN "\x1b[32m"
102 #define ANSI_COLOR_YELLOW "\x1b[33m"
103 #define ANSI_COLOR_BLUE "\x1b[34m"
104 #define ANSI_COLOR_MAGENTA "\x1b[35m"
105 #define ANSI_COLOR_CYAN "\x1b[36m"
106 #define ANSI_COLOR_RESET "\x1b[0m"
107
108 enum {
109 COLOR_TRACE = 0,
110 COLOR_LOG,
111 COLOR_ERROR,
112 COLOR_NOTE,
113 COLOR_WARNING,
114
115 COLOR_UI,
116 COLOR_URN1,
117 COLOR_URN2
118 };
119
120 static const char *prefix [2][8] = {
121 [0] = {
122 [COLOR_TRACE] = "[Trace]",
123 [COLOR_LOG] = "[Log] ",
124 [COLOR_ERROR] = "[Error]",
125 [COLOR_NOTE] = "[Note] ",
126 [COLOR_WARNING] = "[Warn] ",
127
128 [COLOR_UI] = "(UI) ",
129 [COLOR_URN1] = "{",
130 [COLOR_URN2] = "}"
131 },
132 [1] = {
133 [COLOR_TRACE] = "["ANSI_COLOR_BLUE "Trace"ANSI_COLOR_RESET"]",
134 [COLOR_LOG] = "["ANSI_COLOR_MAGENTA"Log"ANSI_COLOR_RESET"] ",
135 [COLOR_ERROR] = "["ANSI_COLOR_RED "Error"ANSI_COLOR_RESET"]",
136 [COLOR_NOTE] = "["ANSI_COLOR_GREEN "Note"ANSI_COLOR_RESET"] ",
137 [COLOR_WARNING] = "["ANSI_COLOR_YELLOW "Warn"ANSI_COLOR_RESET"] ",
138
139 [COLOR_UI] = "("ANSI_COLOR_MAGENTA"UI"ANSI_COLOR_RESET") ",
140 [COLOR_URN1] = "{"ANSI_COLOR_BOLD,
141 [COLOR_URN2] = ANSI_COLOR_RESET"}",
142 }
143 };
144
145 static inline int
_log_vprintf(LV2_Log_Handle handle,LV2_URID type,const char * fmt,va_list args)146 _log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list args)
147 {
148 sandbox_slave_t *sb = handle;
149
150 int idx = COLOR_LOG;
151 if(type == sb->log_trace)
152 idx = COLOR_TRACE;
153 else if(type == sb->log_error)
154 idx = COLOR_ERROR;
155 else if(type == sb->log_note)
156 idx = COLOR_NOTE;
157 else if(type == sb->log_warning)
158 idx = COLOR_WARNING;
159
160 char *buf;
161 if(vasprintf(&buf, fmt, args) == -1)
162 buf = NULL;
163
164 if(buf)
165 {
166 const int istty = isatty(STDERR_FILENO);
167 const char *sep = "\n";
168 for(char *bufp = buf, *pch = strsep(&bufp, sep);
169 pch;
170 pch = strsep(&bufp, sep) )
171 {
172 if(strlen(pch))
173 {
174 fprintf(stderr, "%s %s ", prefix[istty][COLOR_UI], prefix[istty][idx]);
175 if(sb->plugin_urn)
176 fprintf(stderr, "%s%s%s ", prefix[istty][COLOR_URN1], sb->plugin_urn, prefix[istty][COLOR_URN2]);
177 fprintf(stderr, "%s\n", pch);
178 }
179 }
180
181 free(buf);
182 }
183
184 return 0;
185 }
186
187 static inline int __attribute__((format(printf, 3, 4)))
_log_printf(LV2_Log_Handle handle,LV2_URID type,const char * fmt,...)188 _log_printf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, ...)
189 {
190 va_list args;
191
192 va_start (args, fmt);
193 const int ret = _log_vprintf(handle, type, fmt, args);
194 va_end(args);
195
196 return ret;
197 }
198
199 static inline uint32_t
_port_index(LV2UI_Feature_Handle handle,const char * symbol)200 _port_index(LV2UI_Feature_Handle handle, const char *symbol)
201 {
202 sandbox_slave_t *sb = handle;
203 uint32_t index = LV2UI_INVALID_PORT_INDEX;
204
205 LilvNode *symbol_uri = lilv_new_string(sb->world, symbol);
206 if(symbol_uri)
207 {
208 const LilvPort *port = lilv_plugin_get_port_by_symbol(sb->plug, symbol_uri);
209
210 if(port)
211 index = lilv_port_get_index(sb->plug, port);
212
213 lilv_node_free(symbol_uri);
214 }
215
216 return index;
217 }
218
219 static inline void
_write_function(LV2UI_Controller controller,uint32_t index,uint32_t size,uint32_t protocol,const void * buf)220 _write_function(LV2UI_Controller controller, uint32_t index,
221 uint32_t size, uint32_t protocol, const void *buf)
222 {
223 sandbox_slave_t *sb = controller;
224
225 const int status = _sandbox_io_send(&sb->io, index, size, protocol, buf);
226 (void)status; //TODO
227 }
228
229 static inline uint32_t
_port_subscribe(LV2UI_Feature_Handle handle,uint32_t index,uint32_t protocol,const LV2_Feature * const * features)230 _port_subscribe(LV2UI_Feature_Handle handle, uint32_t index, uint32_t protocol,
231 const LV2_Feature *const *features)
232 {
233 sandbox_slave_t *sb = handle;
234
235 const sandbox_io_subscription_t sub = {
236 .state = 1,
237 .protocol = protocol
238 };
239 _write_function(handle, index, sizeof(sandbox_io_subscription_t), sb->io.ui_port_subscribe, &sub);
240
241 return 0;
242 }
243
244 static inline uint32_t
_port_unsubscribe(LV2UI_Feature_Handle handle,uint32_t index,uint32_t protocol,const LV2_Feature * const * features)245 _port_unsubscribe(LV2UI_Feature_Handle handle, uint32_t index, uint32_t protocol,
246 const LV2_Feature *const *features)
247 {
248 sandbox_slave_t *sb = handle;
249
250 const sandbox_io_subscription_t sub = {
251 .state = 0,
252 .protocol = protocol
253 };
254 _write_function(handle, index, sizeof(sandbox_io_subscription_t), sb->io.ui_port_subscribe, &sub);
255
256 return 0;
257 }
258
259 static inline bool
_sandbox_recv_cb(LV2UI_Handle handle,uint32_t index,uint32_t size,uint32_t protocol,const void * buf)260 _sandbox_recv_cb(LV2UI_Handle handle, uint32_t index, uint32_t size,
261 uint32_t protocol, const void *buf)
262 {
263 sandbox_slave_t *sb = handle;
264
265 if(sb->desc && sb->desc->port_event)
266 sb->desc->port_event(sb->handle, index, size, protocol, buf);
267
268 return true; // continue handling messages
269 }
270
271 #pragma GCC diagnostic push
272 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
273 static uint32_t
_sb_uri_to_id(LV2_URI_Map_Callback_Data handle,const char * map,const char * uri)274 _sb_uri_to_id(LV2_URI_Map_Callback_Data handle, const char *map, const char *uri)
275 {
276 sandbox_slave_t *sb = handle;
277 (void)map;
278
279 return sb->map->map(sb->map->handle, uri);
280 }
281 #pragma GCC diagnostic pop
282
283 static uint32_t
_voice_map_new_uuid(void * data,uint32_t flags)284 _voice_map_new_uuid(void *data, uint32_t flags __attribute__((unused)))
285 {
286 xpress_t *xpress = data;
287
288 return xpress_map(xpress);
289 }
290
291 sandbox_slave_t *
sandbox_slave_new(int argc,char ** argv,const sandbox_slave_driver_t * driver,void * data,int * res)292 sandbox_slave_new(int argc, char **argv, const sandbox_slave_driver_t *driver,
293 void *data, int *res)
294 {
295 sandbox_slave_t *sb = calloc(1, sizeof(sandbox_slave_t));
296 if(!sb)
297 {
298 fprintf(stderr, "allocation failed\n");
299 goto fail;
300 }
301
302 sb->plugin_urn = NULL;
303 sb->window_title = "Untitled"; // fall-back
304 sb->minimum = 0x100000; // fall-back
305 sb->sample_rate = 44100.f; // fall-back
306 sb->update_rate = 25.f; // fall-back
307
308 fprintf(stderr,
309 "Synthpod "SYNTHPOD_VERSION"\n"
310 "Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)\n"
311 "Released under Artistic License 2.0 by Open Music Kontrollers\n");
312
313 int c;
314 while((c = getopt(argc, argv, "vhn:p:P:u:U:s:w:m:r:f:")) != -1)
315 {
316 switch(c)
317 {
318 case 'v':
319 fprintf(stderr,
320 "--------------------------------------------------------------------\n"
321 "This is free software: you can redistribute it and/or modify\n"
322 "it under the terms of the Artistic License 2.0 as published by\n"
323 "The Perl Foundation.\n"
324 "\n"
325 "This source is distributed in the hope that it will be useful,\n"
326 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
327 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
328 "Artistic License 2.0 for more details.\n"
329 "\n"
330 "You should have received a copy of the Artistic License 2.0\n"
331 "along the source as a COPYING file. If not, obtain it from\n"
332 "http://www.perlfoundation.org/artistic_license_2_0.\n\n");
333 *res = EXIT_SUCCESS;
334 return NULL;
335 case 'h':
336 fprintf(stderr,
337 "--------------------------------------------------------------------\n"
338 "USAGE\n"
339 " %s [OPTIONS]\n"
340 "\n"
341 "OPTIONS\n"
342 " [-v] print version and full license information\n"
343 " [-h] print usage information\n"
344 " [-n] plugin-urn Plugin URN\n"
345 " [-p] plugin-uri Plugin URI\n"
346 " [-P] plugin-bundle Plugin bundle path\n"
347 " [-u] ui-uri Plugin UI URI\n"
348 " [-U] ui-bundle Plugin UI bundle path\n"
349 " [-s] socket-path Socket path\n"
350 " [-w] window-title Window title\n"
351 " [-m] minimum-size Minimum ringbuffer size\n"
352 " [-r] sample-rate Sample rate (44100)\n"
353 " [-f] update-rate GUI update rate (25)\n\n"
354 , argv[0]);
355 *res = EXIT_SUCCESS;
356 return NULL;
357 case 'n':
358 sb->plugin_urn = optarg;
359 break;
360 case 'p':
361 sb->plugin_uri = optarg;
362 break;
363 case 'P':
364 sb->plugin_bundle_path = optarg;
365 break;
366 case 'u':
367 sb->ui_uri = optarg;
368 break;
369 case 'U':
370 sb->ui_bundle_path = optarg;
371 break;
372 case 's':
373 sb->socket_path = optarg;
374 break;
375 case 'w':
376 sb->window_title = optarg;
377 break;
378 case 'm':
379 sb->minimum = atoi(optarg);
380 break;
381 case 'r':
382 sb->sample_rate = atof(optarg);
383 break;
384 case 'f':
385 sb->update_rate = atof(optarg);
386 break;
387 case '?':
388 if( (optopt == 'n') || (optopt == 'p') || (optopt == 'P') || (optopt == 'u') || (optopt == 'U') || (optopt == 's') || (optopt == 'w') || (optopt == 'm') || (optopt == 'r') || (optopt == 'f') )
389 fprintf(stderr, "Option `-%c' requires an argument.\n", optopt);
390 else if(isprint(optopt))
391 fprintf(stderr, "Unknown option `-%c'.\n", optopt);
392 else
393 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
394 goto fail;
395 default:
396 goto fail;
397 }
398 }
399
400 if( !sb->plugin_uri
401 || !sb->plugin_bundle_path
402 || !sb->ui_uri
403 || !sb->ui_bundle_path
404 || !sb->socket_path)
405 {
406 fprintf(stderr, "not enough arguments\n");
407 goto fail;
408 }
409
410 sb->driver = driver;
411 sb->data = data;
412
413 sb->log.handle = sb;
414 sb->log.printf = _log_printf;
415 sb->log.vprintf = _log_vprintf;
416
417 sb->port_map.handle = sb;
418 sb->port_map.port_index = _port_index;
419
420 sb->port_subscribe.handle = sb;
421 sb->port_subscribe.subscribe = _port_subscribe;
422 sb->port_subscribe.unsubscribe = _port_unsubscribe;
423
424 sb->host_resize.handle = data;
425 sb->host_resize.ui_resize = driver->resize_cb;
426
427 if(!(sb->mapper = mapper_new(0x1000000, 0, NULL, NULL, NULL, NULL))) // 16M
428 {
429 fprintf(stderr, "mapper_new failed\n");
430 goto fail;
431 }
432
433 sb->map = mapper_get_map(sb->mapper);
434 sb->unmap = mapper_get_unmap(sb->mapper);
435 sb->uri_id.callback_data = sb;
436 sb->uri_id.uri_to_id = _sb_uri_to_id;
437
438 sb->log_trace = sb->map->map(sb->map->handle, LV2_LOG__Trace);
439 sb->log_error = sb->map->map(sb->map->handle, LV2_LOG__Error);
440 sb->log_warning = sb->map->map(sb->map->handle, LV2_LOG__Warning);
441 sb->log_note = sb->map->map(sb->map->handle, LV2_LOG__Note);
442
443 xpress_init(&sb->xpress, 0, sb->map, NULL,
444 XPRESS_EVENT_NONE, NULL, NULL, NULL);
445 sb->xmap.new_uuid = _voice_map_new_uuid;
446 sb->xmap.handle = &sb->xpress;
447
448 if(!(sb->world = lilv_world_new()))
449 {
450 fprintf(stderr, "lilv_world_new failed\n");
451 goto fail;
452 }
453
454 sb->plugin_bundle_node = lilv_new_file_uri(sb->world, NULL, sb->plugin_bundle_path);
455 if(strcmp(sb->plugin_bundle_path, sb->ui_bundle_path))
456 {
457 sb->ui_bundle_node = lilv_new_file_uri(sb->world, NULL, sb->ui_bundle_path);
458 }
459
460 sb->plugin_node = lilv_new_uri(sb->world, sb->plugin_uri);
461 sb->ui_node = lilv_new_uri(sb->world, sb->ui_uri);
462
463 if(!sb->plugin_bundle_node || !sb->plugin_node || !sb->ui_node)
464 {
465 fprintf(stderr, "lilv_new_uri failed\n");
466 goto fail;
467 }
468
469 lilv_world_load_bundle(sb->world, sb->plugin_bundle_node);
470 if(sb->ui_bundle_node)
471 {
472 lilv_world_load_bundle(sb->world, sb->ui_bundle_node);
473 }
474
475 lilv_world_load_resource(sb->world, sb->plugin_node);
476 lilv_world_load_resource(sb->world, sb->ui_node);
477
478 const LilvPlugins *plugins = lilv_world_get_all_plugins(sb->world);
479 if(!plugins)
480 {
481 fprintf(stderr, "lilv_world_get_all_plugins failed\n");
482 goto fail;
483 }
484
485 if(!(sb->plug = lilv_plugins_get_by_uri(plugins, sb->plugin_node)))
486 {
487 fprintf(stderr, "lilv_plugins_get_by_uri failed\n");
488 goto fail;
489 }
490
491 sb->uis = lilv_plugin_get_uis(sb->plug);
492 if(!sb->uis)
493 {
494 fprintf(stderr, "lilv_plugin_get_uis failed\n");
495 goto fail;
496 }
497
498 if(!(sb->ui = lilv_uis_get_by_uri(sb->uis, sb->ui_node)))
499 {
500 fprintf(stderr, "lilv_uis_get_by_uri failed\n");
501 goto fail;
502 }
503
504 const LilvNode *ui_path = lilv_ui_get_binary_uri(sb->ui);
505 if(!ui_path)
506 {
507 fprintf(stderr, "lilv_ui_get_binary_uri failed\n");
508 goto fail;
509 }
510
511 LilvNode *no_user_resize_uri = lilv_new_uri(sb->world, LV2_UI__noUserResize);
512 if(no_user_resize_uri)
513 {
514 sb->no_user_resize = lilv_world_ask(sb->world, sb->ui_node, no_user_resize_uri, NULL);
515 lilv_node_free(no_user_resize_uri);
516 }
517
518 #if defined(LILV_0_22)
519 char *binary_path = lilv_file_uri_parse(lilv_node_as_string(ui_path), NULL);
520 #else
521 const char *binary_path = lilv_uri_to_path(lilv_node_as_string(ui_path));
522 #endif
523 if(!(sb->lib = dlopen(binary_path, RTLD_LAZY | RTLD_LOCAL)))
524 {
525 fprintf(stderr, "dlopen failed: %s\n", dlerror());
526 goto fail;
527 }
528
529 #if defined(LILV_0_22)
530 lilv_free(binary_path);
531 #endif
532
533 LV2UI_DescriptorFunction desc_func = dlsym(sb->lib, "lv2ui_descriptor");
534 if(!desc_func)
535 {
536 fprintf(stderr, "dlsym failed\n");
537 goto fail;
538 }
539
540 for(int i=0; true; i++)
541 {
542 const LV2UI_Descriptor *desc = desc_func(i);
543 if(!desc) // sentinel
544 break;
545
546 if(!strcmp(desc->URI, sb->ui_uri))
547 {
548 sb->desc = desc;
549 break;
550 }
551 }
552
553 if(!sb->desc)
554 {
555 fprintf(stderr, "LV2UI_Descriptor lookup failed\n");
556 goto fail;
557 }
558
559 if(_sandbox_io_init(&sb->io, sb->map, sb->unmap, sb->socket_path, false, false, sb->minimum))
560 {
561 fprintf(stderr, "_sandbox_io_init failed: are you sure that the host is running?\n");
562 goto fail;
563 }
564
565 if(driver->init_cb && (driver->init_cb(sb, data) != 0) )
566 {
567 fprintf(stderr, "driver->init_cb failed\n");
568 goto fail;
569 }
570
571 sb->initialized = true;
572 *res = EXIT_SUCCESS;
573 return sb; // success
574
575 fail:
576 sandbox_slave_free(sb);
577 *res = EXIT_FAILURE;
578 return NULL;
579 }
580
581 void
sandbox_slave_free(sandbox_slave_t * sb)582 sandbox_slave_free(sandbox_slave_t *sb)
583 {
584 if(!sb)
585 return;
586
587 xpress_deinit(&sb->xpress);
588
589 if(sb->desc && sb->desc->cleanup && sb->handle)
590 sb->desc->cleanup(sb->handle);
591
592 if(sb->driver && sb->driver->deinit_cb && sb->initialized)
593 sb->driver->deinit_cb(sb->data);
594
595 _sandbox_io_deinit(&sb->io, false);
596
597 if(sb->lib)
598 dlclose(sb->lib);
599
600 if(sb->world)
601 {
602 if(sb->uis)
603 {
604 lilv_uis_free(sb->uis);
605 }
606
607 if(sb->ui_node)
608 {
609 lilv_world_unload_resource(sb->world, sb->ui_node);
610 lilv_node_free(sb->ui_node);
611 }
612
613 if(sb->plugin_node)
614 {
615 lilv_world_unload_resource(sb->world, sb->plugin_node);
616 lilv_node_free(sb->plugin_node);
617 }
618
619 if(sb->ui_bundle_node)
620 {
621 lilv_world_unload_bundle(sb->world, sb->ui_bundle_node);
622 lilv_node_free(sb->ui_bundle_node);
623 }
624
625 if(sb->plugin_bundle_node)
626 {
627 lilv_world_unload_bundle(sb->world, sb->plugin_bundle_node);
628 lilv_node_free(sb->plugin_bundle_node);
629 }
630
631 lilv_world_free(sb->world);
632 }
633
634 if(sb->mapper)
635 {
636 mapper_free(sb->mapper);
637 }
638
639 free(sb);
640 }
641
642 void *
sandbox_slave_instantiate(sandbox_slave_t * sb,const LV2_Feature * parent_feature,void * widget)643 sandbox_slave_instantiate(sandbox_slave_t *sb, const LV2_Feature *parent_feature, void *widget)
644 {
645 LV2_Options_Option options [] = {
646 [0] = {
647 .context = LV2_OPTIONS_INSTANCE,
648 .subject = 0,
649 .key = sb->io.ui_window_title,
650 .size = strlen(sb->plugin_uri) + 1,
651 .type = sb->io.forge.String,
652 .value = sb->plugin_uri
653 },
654 [1] = {
655 .context = LV2_OPTIONS_INSTANCE,
656 .subject = 0,
657 .key = sb->io.params_sample_rate,
658 .size = sizeof(float),
659 .type = sb->io.forge.Float,
660 .value = &sb->sample_rate
661 },
662 [2] = {
663 .context = LV2_OPTIONS_INSTANCE,
664 .subject = 0,
665 .key = sb->io.ui_update_rate,
666 .size = sizeof(float),
667 .type = sb->io.forge.Float,
668 .value = &sb->update_rate
669 },
670 [3] = {
671 .key = 0,
672 .value = NULL
673 }
674 };
675
676 const LV2_Feature map_feature = {
677 .URI = LV2_URID__map,
678 .data = sb->map
679 };
680 const LV2_Feature unmap_feature = {
681 .URI = LV2_URID__unmap,
682 .data = sb->unmap
683 };
684 const LV2_Feature uri_id_feature= {
685 .URI = LV2_URI_MAP_URI,
686 .data = &sb->uri_id
687 };
688 const LV2_Feature log_feature = {
689 .URI = LV2_LOG__log,
690 .data = &sb->log
691 };
692 const LV2_Feature port_map_feature = {
693 .URI = LV2_UI__portMap,
694 .data = &sb->port_map
695 };
696 const LV2_Feature port_subscribe_feature = {
697 .URI = LV2_UI__portSubscribe,
698 .data = &sb->port_subscribe
699 };
700 const LV2_Feature options_feature = {
701 .URI = LV2_OPTIONS__options,
702 .data = options
703 };
704 const LV2_Feature voice_map_feature = {
705 .URI = XPRESS__voiceMap,
706 .data = &sb->xmap
707 };
708 const LV2_Feature resize_feature = {
709 .URI = LV2_UI__resize,
710 .data = &sb->host_resize
711 };
712
713 const LV2_Feature *const features [] = {
714 &map_feature,
715 &unmap_feature,
716 &uri_id_feature,
717 &log_feature,
718 &port_map_feature,
719 &port_subscribe_feature,
720 &options_feature,
721 &voice_map_feature,
722 sb->host_resize.ui_resize ? &resize_feature : parent_feature,
723 sb->host_resize.ui_resize && parent_feature ? parent_feature : NULL,
724 NULL
725 };
726
727 //FIXME check features
728
729 const LilvNode *ui_bundle_uri = lilv_ui_get_bundle_uri(sb->ui);
730 #if defined(LILV_0_22)
731 char *ui_plugin_bundle_path = lilv_file_uri_parse(lilv_node_as_string(ui_bundle_uri), NULL);
732 #else
733 const char *ui_plugin_bundle_path = lilv_uri_to_path(lilv_node_as_string(ui_bundle_uri));
734 #endif
735
736 if(sb->desc && sb->desc->instantiate)
737 {
738 sb->handle = sb->desc->instantiate(sb->desc, sb->plugin_uri,
739 ui_plugin_bundle_path, _write_function, sb, widget, features);
740 }
741
742 #if defined(LILV_0_22)
743 lilv_free(ui_plugin_bundle_path);
744 #endif
745
746 if(sb->handle)
747 return sb->handle; // success
748
749 return NULL;
750 }
751
752 int
sandbox_slave_recv(sandbox_slave_t * sb)753 sandbox_slave_recv(sandbox_slave_t *sb)
754 {
755 if(sb)
756 return _sandbox_io_recv(&sb->io, _sandbox_recv_cb, NULL, sb);
757
758 return -1;
759 }
760
761 void
sandbox_slave_wait(sandbox_slave_t * sb)762 sandbox_slave_wait(sandbox_slave_t *sb)
763 {
764 _sandbox_io_wait(&sb->io);
765 }
766
767 bool
sandbox_slave_timedwait(sandbox_slave_t * sb,const struct timespec * abs_timeout)768 sandbox_slave_timedwait(sandbox_slave_t *sb, const struct timespec *abs_timeout)
769 {
770 return _sandbox_io_timedwait(&sb->io, abs_timeout);
771 }
772
773 const void *
sandbox_slave_extension_data(sandbox_slave_t * sb,const char * URI)774 sandbox_slave_extension_data(sandbox_slave_t *sb, const char *URI)
775 {
776 if(sb && sb->desc && sb->desc->extension_data)
777 return sb->desc->extension_data(URI);
778
779 return NULL;
780 }
781
782 void
sandbox_slave_run(sandbox_slave_t * sb)783 sandbox_slave_run(sandbox_slave_t *sb)
784 {
785 if(sb && sb->driver && sb->driver->run_cb)
786 sb->driver->run_cb(sb, sb->update_rate, sb->data);
787 }
788
789 const char *
sandbox_slave_title_get(sandbox_slave_t * sb)790 sandbox_slave_title_get(sandbox_slave_t *sb)
791 {
792 if(sb)
793 return sb->window_title;
794
795 return NULL;
796 }
797
798 bool
sandbox_slave_no_user_resize_get(sandbox_slave_t * sb)799 sandbox_slave_no_user_resize_get(sandbox_slave_t *sb)
800 {
801 if(sb)
802 return sb->no_user_resize;
803
804 return false;
805 }
806