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 <inttypes.h>
19 #include <unistd.h>
20
21 #include <synthpod_app_private.h>
22
23 #define ANSI_COLOR_BOLD "\x1b[1m"
24 #define ANSI_COLOR_RESET "\x1b[0m"
25
26 //tools.ietf.org/html/rfc4122 version 4
27 static void
urn_uuid_unparse_random(urn_uuid_t urn_uuid)28 urn_uuid_unparse_random(urn_uuid_t urn_uuid)
29 {
30 uint8_t bytes [0x10];
31
32 for(unsigned i=0x0; i<0x10; i++)
33 bytes[i] = rand() & 0xff;
34
35 bytes[6] = (bytes[6] & 0b00001111) | 0b01000000; // set four most significant bits of 7th byte to 0b0100
36 bytes[8] = (bytes[8] & 0b00111111) | 0b10000000; // set two most significant bits of 9th byte to 0b10
37
38 snprintf(urn_uuid, URN_UUID_LENGTH, "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
39 bytes[0x0], bytes[0x1], bytes[0x2], bytes[0x3],
40 bytes[0x4], bytes[0x5],
41 bytes[0x6], bytes[0x7],
42 bytes[0x8], bytes[0x9],
43 bytes[0xa], bytes[0xb], bytes[0xc], bytes[0xd], bytes[0xe], bytes[0xf]);
44 }
45
46 #if defined(_WIN32)
47 static inline char *
strsep(char ** sp,char * sep)48 strsep(char **sp, char *sep)
49 {
50 char *p, *s;
51 if(sp == NULL || *sp == NULL || **sp == '\0')
52 return(NULL);
53 s = *sp;
54 p = s + strcspn(s, sep);
55 if(*p != '\0')
56 *p++ = '\0';
57 *sp = p;
58 return(s);
59 }
60 #endif
61
62 //FIXME is actually __realtime
63 __non_realtime static int
_log_vprintf(LV2_Log_Handle handle,LV2_URID type,const char * fmt,va_list args)64 _log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list args)
65 {
66 mod_t *mod = handle;
67 sp_app_t *app = mod->app;
68
69 char prefix [128]; //TODO how big?
70 char buf [1024]; //TODO how big?
71
72 if(isatty(STDERR_FILENO))
73 snprintf(prefix, sizeof(prefix), "{"ANSI_COLOR_BOLD"%s"ANSI_COLOR_RESET"} ", mod->urn_uri);
74 else
75 snprintf(prefix, sizeof(prefix), "{%s} ", mod->urn_uri);
76 vsnprintf(buf, sizeof(buf), fmt, args);
77
78 const char *sep = "\n";
79 for(char *bufp = buf, *pch = strsep(&bufp, sep);
80 pch;
81 pch = strsep(&bufp, sep) )
82 {
83 if(strlen(pch) && app->driver->log)
84 app->driver->log->printf(app->driver->log->handle, type, "%s%s\n", prefix, pch);
85 }
86
87 return 0;
88 }
89
90 //FIXME is actually __realtime
91 __non_realtime static int __attribute__((format(printf, 3, 4)))
_log_printf(LV2_Log_Handle handle,LV2_URID type,const char * fmt,...)92 _log_printf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, ...)
93 {
94 va_list args;
95 int ret;
96
97 va_start (args, fmt);
98 ret = _log_vprintf(handle, type, fmt, args);
99 va_end(args);
100
101 return ret;
102 }
103
104 __realtime static LV2_Worker_Status
_schedule_work(LV2_Worker_Schedule_Handle handle,uint32_t size,const void * data)105 _schedule_work(LV2_Worker_Schedule_Handle handle, uint32_t size, const void *data)
106 {
107 mod_t *mod = handle;
108 mod_worker_t *mod_worker = &mod->mod_worker;
109
110 void *target;
111 if((target = varchunk_write_request(mod_worker->app_to_worker, size)))
112 {
113 memcpy(target, data, size);
114 varchunk_write_advance(mod_worker->app_to_worker, size);
115 sem_post(&mod_worker->sem);
116
117 return LV2_WORKER_SUCCESS;
118 }
119
120 sp_app_log_trace(mod->app, "%s: failed to request buffer\n", __func__);
121
122 return LV2_WORKER_ERR_NO_SPACE;
123 }
124
125 __non_realtime static char *
_mod_make_path(LV2_State_Make_Path_Handle instance,const char * abstract_path)126 _mod_make_path(LV2_State_Make_Path_Handle instance, const char *abstract_path)
127 {
128 mod_t *mod = instance;
129 sp_app_t *app = mod->app;
130
131 char *absolute_path = NULL;
132 asprintf(&absolute_path, "%s/%s/%s", app->bundle_path, mod->urn_uri, abstract_path);
133
134 // create leading directory tree, e.g. up to last '/'
135 if(absolute_path)
136 {
137 const char *end = strrchr(absolute_path, '/');
138 if(end)
139 {
140 char *path = strndup(absolute_path, end - absolute_path);
141 if(path)
142 {
143 mkpath(path);
144
145 free(path);
146 }
147 }
148 }
149
150 return absolute_path;
151 }
152
153 static inline int
_sp_app_mod_alloc_pool(pool_t * pool)154 _sp_app_mod_alloc_pool(pool_t *pool)
155 {
156 #if defined(_WIN32)
157 pool->buf = _aligned_malloc(pool->size, 8);
158 #else
159 posix_memalign(&pool->buf, 8, pool->size);
160 #endif
161 if(pool->buf)
162 {
163 memset(pool->buf, 0x0, pool->size);
164
165 return 0;
166 }
167
168 return -1;
169 }
170
171 static inline void
_sp_app_mod_free_pool(pool_t * pool)172 _sp_app_mod_free_pool(pool_t *pool)
173 {
174 if(pool->buf)
175 {
176 free(pool->buf);
177 pool->buf = NULL;
178 }
179 }
180
181 static inline void
_sp_app_mod_slice_pool(mod_t * mod,port_type_t type)182 _sp_app_mod_slice_pool(mod_t *mod, port_type_t type)
183 {
184 // set ptr to pool buffer
185 void *ptr = mod->pools[type].buf;
186
187 for(port_direction_t dir=0; dir<PORT_DIRECTION_NUM; dir++)
188 {
189 for(unsigned i=0; i<mod->num_ports; i++)
190 {
191 port_t *tar = &mod->ports[i];
192
193 if( (tar->type != type) || (tar->direction != dir) )
194 continue; //skip
195
196 // define buffer slice
197 tar->base = ptr;
198
199 // initialize control buffers to default value
200 if(tar->type == PORT_TYPE_CONTROL)
201 {
202 control_port_t *control = &tar->control;
203
204 float *buf_ptr = PORT_BASE_ALIGNED(tar);
205 *buf_ptr = control->dflt;
206 control->stash = control->dflt;
207 control->last = control->dflt;
208 control->auto_dirty = true;
209 }
210
211 ptr += lv2_atom_pad_size(tar->size);
212 }
213 }
214 }
215
216 void
_sp_app_mod_reinitialize(mod_t * mod)217 _sp_app_mod_reinitialize(mod_t *mod)
218 {
219 sp_app_t *app = mod->app;
220
221 // reinitialize all modules,
222 lilv_instance_deactivate(mod->inst);
223 lilv_instance_free(mod->inst);
224 mod->inst = NULL;
225 mod->handle = NULL;
226
227 // mod->features should be up-to-date
228 mod->inst = lilv_plugin_instantiate(mod->plug, app->driver->sample_rate, mod->features);
229 mod->handle = lilv_instance_get_handle(mod->inst);
230
231 //TODO should we re-get extension_data?
232
233 // resize sample based buffers only (e.g. AUDIO and CV)
234 _sp_app_mod_free_pool(&mod->pools[PORT_TYPE_AUDIO]);
235 _sp_app_mod_free_pool(&mod->pools[PORT_TYPE_CV]);
236
237 mod->pools[PORT_TYPE_AUDIO].size = 0;
238 mod->pools[PORT_TYPE_CV].size = 0;
239
240 for(unsigned i=0; i<mod->num_ports; i++)
241 {
242 port_t *tar = &mod->ports[i];
243
244 if( (tar->type == PORT_TYPE_AUDIO)
245 || (tar->type == PORT_TYPE_CV) )
246 {
247 tar->size = app->driver->max_block_size * sizeof(float);
248 mod->pools[tar->type].size += lv2_atom_pad_size(tar->size);
249 }
250 }
251
252 _sp_app_mod_alloc_pool(&mod->pools[PORT_TYPE_AUDIO]);
253 _sp_app_mod_alloc_pool(&mod->pools[PORT_TYPE_CV]);
254
255 _sp_app_mod_slice_pool(mod, PORT_TYPE_AUDIO);
256 _sp_app_mod_slice_pool(mod, PORT_TYPE_CV);
257 }
258
259 static inline int
_sp_app_mod_features_populate(sp_app_t * app,mod_t * mod)260 _sp_app_mod_features_populate(sp_app_t *app, mod_t *mod)
261 {
262 // populate feature list
263 int nfeatures = 0;
264 mod->feature_list[nfeatures].URI = LV2_URID__map;
265 mod->feature_list[nfeatures++].data = app->driver->map;
266
267 mod->feature_list[nfeatures].URI = LV2_URID__unmap;
268 mod->feature_list[nfeatures++].data = app->driver->unmap;
269
270 mod->feature_list[nfeatures].URI = XPRESS__voiceMap;
271 mod->feature_list[nfeatures++].data = app->driver->xmap;
272
273 mod->feature_list[nfeatures].URI = LV2_WORKER__schedule;
274 mod->feature_list[nfeatures++].data = &mod->worker.schedule;
275
276 mod->feature_list[nfeatures].URI = LV2_LOG__log;
277 mod->feature_list[nfeatures++].data = &mod->log;
278
279 mod->feature_list[nfeatures].URI = LV2_STATE__makePath;
280 mod->feature_list[nfeatures++].data = &mod->make_path;
281
282 mod->feature_list[nfeatures].URI = LV2_BUF_SIZE__boundedBlockLength;
283 mod->feature_list[nfeatures++].data = NULL;
284
285 mod->feature_list[nfeatures].URI = LV2_OPTIONS__options;
286 mod->feature_list[nfeatures++].data = mod->opts.options;
287
288 /* TODO support
289 mod->feature_list[nfeatures].URI = LV2_PORT_PROPS__supportsStrictBounds;
290 mod->feature_list[nfeatures++].data = NULL;
291 */
292
293 /* TODO support
294 mod->feature_list[nfeatures].URI = LV2_RESIZE_PORT__resize;
295 mod->feature_list[nfeatures++].data = NULL;
296 */
297
298 mod->feature_list[nfeatures].URI = LV2_STATE__loadDefaultState;
299 mod->feature_list[nfeatures++].data = NULL;
300
301 if(app->driver->system_port_add && app->driver->system_port_del)
302 {
303 mod->feature_list[nfeatures].URI = SYNTHPOD_PREFIX"systemPorts";
304 mod->feature_list[nfeatures++].data = NULL;
305 }
306
307 if(app->driver->osc_sched)
308 {
309 mod->feature_list[nfeatures].URI = LV2_OSC__schedule;
310 mod->feature_list[nfeatures++].data = app->driver->osc_sched;
311 }
312
313 if(app->driver->features & SP_APP_FEATURE_FIXED_BLOCK_LENGTH)
314 {
315 mod->feature_list[nfeatures].URI = LV2_BUF_SIZE__fixedBlockLength;
316 mod->feature_list[nfeatures++].data = NULL;
317 }
318
319 if(app->driver->features & SP_APP_FEATURE_POWER_OF_2_BLOCK_LENGTH)
320 {
321 mod->feature_list[nfeatures].URI = LV2_BUF_SIZE__powerOf2BlockLength;
322 mod->feature_list[nfeatures++].data = NULL;
323 }
324
325 mod->feature_list[nfeatures].URI = LV2_URI_MAP_URI;
326 mod->feature_list[nfeatures++].data = &app->uri_to_id;
327
328 mod->feature_list[nfeatures].URI = LV2_CORE__inPlaceBroken;
329 mod->feature_list[nfeatures++].data = NULL;
330
331 mod->feature_list[nfeatures].URI = LV2_INLINEDISPLAY__queue_draw;
332 mod->feature_list[nfeatures++].data = &mod->idisp.queue_draw;
333
334 mod->feature_list[nfeatures].URI = LV2_STATE__threadSafeRestore;
335 mod->feature_list[nfeatures++].data = NULL;
336
337 assert(nfeatures <= NUM_FEATURES);
338
339 for(int i=0; i<nfeatures; i++)
340 mod->features[i] = &mod->feature_list[i];
341 mod->features[nfeatures] = NULL; // sentinel
342
343 return nfeatures;
344 }
345
346 static const LilvPlugin *
_sp_app_mod_is_supported(sp_app_t * app,const char * uri)347 _sp_app_mod_is_supported(sp_app_t *app, const char *uri)
348 {
349 LilvNode *uri_node = lilv_new_uri(app->world, uri);
350 if(!uri_node)
351 {
352 sp_app_log_trace(app, "%s: failed to create URI\n", __func__);
353 return NULL;
354 }
355
356 const LilvPlugin *plug = lilv_plugins_get_by_uri(app->plugs, uri_node);
357 lilv_node_free(uri_node);
358
359 if(!plug)
360 {
361 sp_app_log_trace(app, "%s: failed to get plugin\n", __func__);
362 return NULL;
363 }
364
365 const LilvNode *library_uri= lilv_plugin_get_library_uri(plug);
366 if(!library_uri)
367 {
368 sp_app_log_trace(app, "%s: failed to get library URI\n", __func__);
369 return NULL;
370 }
371
372 if(!app->driver->bad_plugins)
373 {
374 // check whether DSP and UI code is mixed into same binary
375 bool mixed_binary = false;
376 LilvUIs *all_uis = lilv_plugin_get_uis(plug);
377 if(all_uis)
378 {
379 LILV_FOREACH(uis, ptr, all_uis)
380 {
381 const LilvUI *ui = lilv_uis_get(all_uis, ptr);
382 if(!ui)
383 continue;
384
385 const LilvNode *ui_uri_node = lilv_ui_get_uri(ui);
386 if(!ui_uri_node)
387 continue;
388
389 // nedded if ui ttl referenced via rdfs#seeAlso
390 lilv_world_load_resource(app->world, ui_uri_node);
391
392 const LilvNode *ui_library_uri= lilv_ui_get_binary_uri(ui);
393 if(ui_library_uri && lilv_node_equals(library_uri, ui_library_uri))
394 mixed_binary = true; // this is bad, we don't support that
395
396 lilv_world_unload_resource(app->world, ui_uri_node);
397 }
398
399 lilv_uis_free(all_uis);
400 }
401
402 if(mixed_binary)
403 {
404 sp_app_log_error(app, "%s: <%s> NOT supported: mixes DSP and UI code in same binary.\n", __func__, uri);
405 return NULL;
406 }
407 }
408
409 // populate feature list in dummy mod structure
410 mod_t mod;
411 const int nfeatures = _sp_app_mod_features_populate(app, &mod);
412
413 // check for missing features
414 int missing_required_feature = 0;
415 LilvNodes *required_features = lilv_plugin_get_required_features(plug);
416 if(required_features)
417 {
418 LILV_FOREACH(nodes, i, required_features)
419 {
420 const LilvNode* required_feature = lilv_nodes_get(required_features, i);
421 const char *required_feature_uri = lilv_node_as_uri(required_feature);
422 missing_required_feature = 1;
423
424 for(int f=0; f<nfeatures; f++)
425 {
426 if(!strcmp(mod.feature_list[f].URI, required_feature_uri))
427 {
428 missing_required_feature = 0;
429 break;
430 }
431 }
432
433 if(missing_required_feature)
434 {
435 sp_app_log_error(app, "%s: <%s> NOT supported: requires feature <%s>\n",
436 __func__, uri, required_feature_uri);
437 break;
438 }
439 }
440 lilv_nodes_free(required_features);
441 }
442
443 if(missing_required_feature)
444 return NULL;
445
446 return plug;
447 }
448
449 __non_realtime static LV2_Worker_Status
_sp_worker_respond_async(LV2_Worker_Respond_Handle handle,uint32_t size,const void * data)450 _sp_worker_respond_async(LV2_Worker_Respond_Handle handle, uint32_t size, const void *data)
451 {
452 mod_t *mod = handle;
453 mod_worker_t *mod_worker = &mod->mod_worker;
454
455 void *payload;
456 if((payload = varchunk_write_request(mod_worker->app_from_worker, size)))
457 {
458 memcpy(payload, data, size);
459 varchunk_write_advance(mod_worker->app_from_worker, size);
460 return LV2_WORKER_SUCCESS;
461 }
462
463 sp_app_log_error(mod->app, "%s: failed to request buffer\n", __func__);
464
465 return LV2_WORKER_ERR_NO_SPACE;
466 }
467
468 __non_realtime static LV2_Worker_Status
_sp_worker_respond_sync(LV2_Worker_Respond_Handle handle,uint32_t size,const void * data)469 _sp_worker_respond_sync(LV2_Worker_Respond_Handle handle, uint32_t size, const void *data)
470 {
471 mod_t *mod = handle;
472
473 if(mod->worker.iface && mod->worker.iface->work_response)
474 return mod->worker.iface->work_response(mod->handle, size, data);
475
476 sp_app_log_error(mod->app, "%s: failed to call work:response\n", __func__);
477
478 return LV2_WORKER_ERR_NO_SPACE;
479 }
480
481 __non_realtime LV2_Worker_Status
_sp_app_mod_worker_work_sync(mod_t * mod,size_t size,const void * payload)482 _sp_app_mod_worker_work_sync(mod_t *mod, size_t size, const void *payload)
483 {
484 if(mod->worker.iface && mod->worker.iface->work)
485 {
486 return mod->worker.iface->work(mod->handle, _sp_worker_respond_sync, mod,
487 size, payload);
488 }
489
490 sp_app_log_error(mod->app, "%s: failed to call work:work\n", __func__);
491
492 return LV2_WORKER_ERR_NO_SPACE;
493 }
494
495 __non_realtime static void
_sp_app_mod_worker_work_async(mod_t * mod,size_t size,const void * payload)496 _sp_app_mod_worker_work_async(mod_t *mod, size_t size, const void *payload)
497 {
498 //printf("_mod_worker_work: %s, %zu\n", mod->urn_uri, size);
499
500 if(mod->worker.iface && mod->worker.iface->work)
501 {
502 mod->worker.iface->work(mod->handle, _sp_worker_respond_async, mod,
503 size, payload);
504 //TODO check return status
505 }
506 else
507 {
508 sp_app_log_error(mod->app, "%s: failed to call work:work\n", __func__);
509 }
510 }
511
512 __non_realtime static void *
_mod_worker_thread(void * data)513 _mod_worker_thread(void *data)
514 {
515 mod_t *mod = data;
516 mod_worker_t *mod_worker = &mod->mod_worker;
517
518 // will inherit thread priority from main worker thread
519
520 while(!atomic_load_explicit(&mod_worker->kill, memory_order_acquire))
521 {
522 sem_wait(&mod_worker->sem);
523
524 const void *payload;
525 size_t size;
526 while((payload = varchunk_read_request(mod_worker->app_to_worker, &size)))
527 {
528 _sp_app_mod_worker_work_async(mod, size, payload);
529
530 varchunk_read_advance(mod_worker->app_to_worker);
531 }
532
533 while((payload = varchunk_read_request(mod_worker->state_to_worker, &size)))
534 {
535 _sp_app_mod_worker_work_async(mod, size, payload);
536
537 varchunk_read_advance(mod_worker->state_to_worker);
538 }
539
540 if(mod->idisp.iface && mod->idisp.iface->render)
541 {
542 if(atomic_exchange(&mod->idisp.draw_queued, false))
543 {
544 const uint32_t w = 256; //FIXME
545 const uint32_t h = 256; //FIXME
546
547 // lock surface
548 while(atomic_flag_test_and_set(&mod->idisp.lock))
549 {
550 // spin
551 }
552
553 mod->idisp.surf = mod->idisp.iface->render(mod->handle, w, h);
554
555 // unlock surface
556 atomic_flag_clear(&mod->idisp.lock);
557 }
558 }
559 }
560
561 return NULL;
562 }
563
564 __realtime void
_sp_app_mod_queue_draw(mod_t * mod)565 _sp_app_mod_queue_draw(mod_t *mod)
566 {
567 mod_worker_t *mod_worker = &mod->mod_worker;
568
569 if(mod->idisp.iface && mod->idisp.subscribed)
570 {
571 if(mod->idisp.counter >= mod->idisp.threshold)
572 {
573 mod->idisp.counter = 0;
574
575 atomic_store(&mod->idisp.draw_queued, true);
576 sem_post(&mod_worker->sem);
577 }
578 }
579 }
580
581 __realtime static void
_mod_queue_draw(void * data)582 _mod_queue_draw(void *data)
583 {
584 mod_t *mod = data;
585
586 _sp_app_mod_queue_draw(mod);
587 }
588
589 mod_t *
_sp_app_mod_add(sp_app_t * app,const char * uri,LV2_URID urn)590 _sp_app_mod_add(sp_app_t *app, const char *uri, LV2_URID urn)
591 {
592 const LilvPlugin *plug;
593
594 if(!(plug = _sp_app_mod_is_supported(app, uri)))
595 {
596 sp_app_log_error(app, "%s: plugin is not supported\n", __func__);
597 return NULL;
598 }
599
600 mod_t *mod = calloc(1, sizeof(mod_t));
601 if(!mod)
602 {
603 sp_app_log_error(app, "%s: allocation failed\n", __func__);
604 return NULL;
605 }
606
607 mod->needs_bypassing = false; // plugins with control ports only need no bypassing upon preset load
608 mod->bypassed = false;
609 atomic_init(&mod->dsp_client.ref_count, 0);
610
611 // populate worker schedule
612 mod->worker.schedule.handle = mod;
613 mod->worker.schedule.schedule_work = _schedule_work;
614
615 // populate log
616 mod->log.handle = mod;
617 mod->log.printf = _log_printf;
618 mod->log.vprintf = _log_vprintf;
619
620 mod->make_path.handle = mod;
621 mod->make_path.path = _mod_make_path;
622
623 mod->idisp.queue_draw.handle = mod;
624 mod->idisp.queue_draw.queue_draw = _mod_queue_draw;
625 atomic_init(&mod->idisp.draw_queued, false);
626 mod->idisp.lock = (atomic_flag)ATOMIC_FLAG_INIT;
627 mod->idisp.threshold = app->driver->sample_rate / app->driver->update_rate;
628
629 // populate options
630 mod->opts.options[0].context = LV2_OPTIONS_INSTANCE;
631 mod->opts.options[0].subject = 0;
632 mod->opts.options[0].key = app->regs.bufsz.max_block_length.urid;
633 mod->opts.options[0].size = sizeof(int32_t);
634 mod->opts.options[0].type = app->forge.Int;
635 mod->opts.options[0].value = &app->driver->max_block_size;
636
637 mod->opts.options[1].context = LV2_OPTIONS_INSTANCE;
638 mod->opts.options[1].subject = 0;
639 mod->opts.options[1].key = app->regs.bufsz.min_block_length.urid;
640 mod->opts.options[1].size = sizeof(int32_t);
641 mod->opts.options[1].type = app->forge.Int;
642 mod->opts.options[1].value = &app->driver->min_block_size;
643
644 mod->opts.options[2].context = LV2_OPTIONS_INSTANCE;
645 mod->opts.options[2].subject = 0;
646 mod->opts.options[2].key = app->regs.bufsz.sequence_size.urid;
647 mod->opts.options[2].size = sizeof(int32_t);
648 mod->opts.options[2].type = app->forge.Int;
649 mod->opts.options[2].value = &app->driver->seq_size;
650
651 mod->opts.options[3].context = LV2_OPTIONS_INSTANCE;
652 mod->opts.options[3].subject = 0;
653 mod->opts.options[3].key = app->regs.bufsz.nominal_block_length.urid;
654 mod->opts.options[3].size = sizeof(int32_t);
655 mod->opts.options[3].type = app->forge.Int;
656 mod->opts.options[3].value = &app->driver->max_block_size; // set to max by default
657
658 mod->opts.options[4].context = LV2_OPTIONS_INSTANCE;
659 mod->opts.options[4].subject = 0;
660 mod->opts.options[4].key = app->regs.param.sample_rate.urid;
661 mod->opts.options[4].size = sizeof(float);
662 mod->opts.options[4].type = app->forge.Float;
663 mod->opts.options[4].value = &app->driver->sample_rate;
664
665 mod->opts.options[5].context = LV2_OPTIONS_INSTANCE;
666 mod->opts.options[5].subject = 0;
667 mod->opts.options[5].key = app->regs.ui.update_rate.urid;
668 mod->opts.options[5].size = sizeof(float);
669 mod->opts.options[5].type = app->forge.Float;
670 mod->opts.options[5].value = &app->driver->update_rate;
671
672 mod->opts.options[6].key = 0; // sentinel
673 mod->opts.options[6].value = NULL; // sentinel
674
675 _sp_app_mod_features_populate(app, mod);
676
677 mod->app = app;
678 if(urn == 0)
679 {
680 urn_uuid_unparse_random(mod->urn_uri);
681 urn = app->driver->map->map(app->driver->map->handle, mod->urn_uri);
682 }
683 else
684 {
685 const char *urn_uri = app->driver->unmap->unmap(app->driver->unmap->handle, urn);
686 strcpy(mod->urn_uri, urn_uri);
687 }
688 //printf("urn: %s\n", mod->urn_uri);
689 mod->urn = urn;
690 mod->plug = plug;
691 mod->plug_urid = app->driver->map->map(app->driver->map->handle, uri);
692 mod->num_ports = lilv_plugin_get_num_ports(plug) + 2; // + automation ports
693 mod->inst = lilv_plugin_instantiate(plug, app->driver->sample_rate, mod->features);
694 if(!mod->inst)
695 {
696 sp_app_log_error(app, "%s: instantiation failed\n", __func__);
697 free(mod);
698 return NULL;
699 }
700 mod->uri_str = strdup(uri); //TODO check
701 mod->handle = lilv_instance_get_handle(mod->inst);
702 mod->worker.iface = lilv_instance_get_extension_data(mod->inst,
703 LV2_WORKER__interface);
704 mod->opts.iface = lilv_instance_get_extension_data(mod->inst,
705 LV2_OPTIONS__interface);
706 const bool has_ro_canvas_graph = lilv_world_ask(app->world,
707 lilv_plugin_get_uri(mod->plug), app->regs.patch.readable.node,
708 app->regs.canvas.graph.node);
709 const bool has_rw_canvas_graph = lilv_world_ask(app->world,
710 lilv_plugin_get_uri(mod->plug), app->regs.patch.writable.node,
711 app->regs.canvas.graph.node);
712 if(has_ro_canvas_graph || has_rw_canvas_graph)
713 {
714 //sp_app_log_note(app, "%s: detected canvas:graph parameter\n", __func__);
715 }
716 else
717 {
718 mod->idisp.iface = lilv_instance_get_extension_data(mod->inst,
719 LV2_INLINEDISPLAY__interface);
720 }
721 mod->state.iface = lilv_instance_get_extension_data(mod->inst,
722 LV2_STATE__interface);
723 mod->system_ports = lilv_plugin_has_feature(plug, app->regs.synthpod.system_ports.node);
724 const bool load_default_state = lilv_plugin_has_feature(plug, app->regs.state.load_default_state.node);
725 const bool thread_safe_restore = lilv_plugin_has_feature(plug, app->regs.state.thread_safe_restore.node);
726
727 if(mod->state.iface) // plugins with state:interface need bypassing upon preset load
728 mod->needs_bypassing = true;
729
730 if(thread_safe_restore) // plugins with state:threadSafeRestore need no bypassing upon preset load
731 mod->needs_bypassing = false;
732
733 // clear pool sizes
734 for(port_type_t pool=0; pool<PORT_TYPE_NUM; pool++)
735 mod->pools[pool].size = 0;
736
737 mod->ports = calloc(mod->num_ports, sizeof(port_t));
738 if(!mod->ports)
739 {
740 sp_app_log_error(app, "%s: pool allocation failed\n", __func__);
741 free(mod);
742 return NULL; // failed to alloc ports
743 }
744
745 for(unsigned i=0; i<mod->num_ports - 2; i++) // - automation ports
746 {
747 port_t *tar = &mod->ports[i];
748 const LilvPort *port = lilv_plugin_get_port_by_index(plug, i);
749
750 tar->size = 0;
751 tar->mod = mod;
752 tar->index = i;
753 tar->symbol = lilv_node_as_string(lilv_port_get_symbol(plug, port));
754 tar->direction = lilv_port_is_a(plug, port, app->regs.port.input.node)
755 ? PORT_DIRECTION_INPUT
756 : PORT_DIRECTION_OUTPUT;
757
758 // register system ports
759 if(mod->system_ports)
760 {
761 if(lilv_port_is_a(plug, port, app->regs.synthpod.control_port.node))
762 tar->sys.type = SYSTEM_PORT_CONTROL;
763 else if(lilv_port_is_a(plug, port, app->regs.synthpod.audio_port.node))
764 tar->sys.type = SYSTEM_PORT_AUDIO;
765 else if(lilv_port_is_a(plug, port, app->regs.synthpod.cv_port.node))
766 tar->sys.type = SYSTEM_PORT_CV;
767 else if(lilv_port_is_a(plug, port, app->regs.synthpod.midi_port.node))
768 tar->sys.type = SYSTEM_PORT_MIDI;
769 else if(lilv_port_is_a(plug, port, app->regs.synthpod.osc_port.node))
770 tar->sys.type = SYSTEM_PORT_OSC;
771 else if(lilv_port_is_a(plug, port, app->regs.synthpod.com_port.node))
772 tar->sys.type = SYSTEM_PORT_COM;
773 else
774 tar->sys.type = SYSTEM_PORT_NONE;
775
776 if(app->driver->system_port_add)
777 {
778 //FIXME check lilv returns
779 char *short_name = NULL;
780 char *pretty_name = NULL;
781 const char *designation = NULL;
782 const LilvNode *port_symbol_node = lilv_port_get_symbol(plug, port);
783 LilvNode *port_name_node = lilv_port_get_name(plug, port);
784 LilvNode *port_designation= lilv_port_get(plug, port, app->regs.core.designation.node);
785
786 asprintf(&short_name, "#%"PRIu32"_%s",
787 mod->urn, lilv_node_as_string(port_symbol_node));
788 asprintf(&pretty_name, "#%"PRIu32" - %s",
789 mod->urn, lilv_node_as_string(port_name_node));
790 designation = port_designation ? lilv_node_as_string(port_designation) : NULL;
791 const uint32_t order = (mod->urn << 16) | tar->index;
792
793 tar->sys.data = app->driver->system_port_add(app->data, tar->sys.type,
794 short_name, pretty_name, designation,
795 tar->direction == PORT_DIRECTION_OUTPUT, order);
796
797 lilv_node_free(port_designation);
798 lilv_node_free(port_name_node);
799 free(short_name);
800 free(pretty_name);
801 }
802 }
803 else
804 {
805 tar->sys.type = SYSTEM_PORT_NONE;
806 tar->sys.data = NULL;
807 }
808
809 if(lilv_port_is_a(plug, port, app->regs.port.audio.node))
810 {
811 tar->size = app->driver->max_block_size * sizeof(float);
812 tar->type = PORT_TYPE_AUDIO;
813 tar->protocol = app->regs.port.peak_protocol.urid;
814 tar->driver = &audio_port_driver;
815 }
816 else if(lilv_port_is_a(plug, port, app->regs.port.cv.node))
817 {
818 tar->size = app->driver->max_block_size * sizeof(float);
819 tar->type = PORT_TYPE_CV;
820 tar->protocol = app->regs.port.peak_protocol.urid;
821 tar->driver = &cv_port_driver;
822 }
823 else if(lilv_port_is_a(plug, port, app->regs.port.control.node))
824 {
825 tar->size = sizeof(float);
826 tar->type = PORT_TYPE_CONTROL;
827 tar->protocol = app->regs.port.float_protocol.urid;
828 tar->driver = &control_port_driver;
829
830 control_port_t *control = &tar->control;
831 control->is_integer = lilv_port_has_property(plug, port, app->regs.port.integer.node);
832 control->is_toggled = lilv_port_has_property(plug, port, app->regs.port.toggled.node);
833 control->lock = (atomic_flag)ATOMIC_FLAG_INIT;
834
835 LilvNode *dflt_node;
836 LilvNode *min_node;
837 LilvNode *max_node;
838 lilv_port_get_range(plug, port, &dflt_node, &min_node, &max_node);
839 control->dflt = dflt_node ? lilv_node_as_float(dflt_node) : 0.f; //FIXME int, bool
840 control->min = min_node ? lilv_node_as_float(min_node) : 0.f; //FIXME int, bool
841 control->max = max_node ? lilv_node_as_float(max_node) : 1.f; //FIXME int, bool
842 control->range = control->max - control->min;
843 control->range_1 = 1.f / control->range;
844 lilv_node_free(dflt_node);
845 lilv_node_free(min_node);
846 lilv_node_free(max_node);
847 }
848 else if(lilv_port_is_a(plug, port, app->regs.port.atom.node))
849 {
850 tar->size = app->driver->seq_size;
851 tar->type = PORT_TYPE_ATOM;
852 tar->protocol = app->regs.port.event_transfer.urid; //FIXME handle atom_transfer
853 tar->driver = &seq_port_driver; // FIXME handle atom_port_driver
854
855 tar->atom.buffer_type = PORT_BUFFER_TYPE_SEQUENCE; //FIXME properly discover this
856
857 // does this port support patch:Message?
858 tar->atom.patchable = lilv_port_supports_event(plug, port, app->regs.patch.message.node);
859
860 // check whether this is a control port
861 const LilvPort *control_port = lilv_plugin_get_port_by_designation(plug,
862 tar->direction == PORT_DIRECTION_INPUT
863 ? app->regs.port.input.node
864 : app->regs.port.output.node
865 , app->regs.core.control.node);
866 (void)control_port; //TODO use this?
867 }
868 else
869 {
870 sp_app_log_warning(app, "%s: unknown port type\n", __func__); //FIXME plugin should fail to initialize here
871
872 free(mod->uri_str);
873 free(mod->ports);
874 free(mod);
875
876 return NULL;
877 }
878
879 // get minimum port size if specified
880 LilvNode *minsize = lilv_port_get(plug, port, app->regs.port.minimum_size.node);
881 if(minsize)
882 {
883 tar->size = lilv_node_as_int(minsize);
884 lilv_node_free(minsize);
885 }
886
887 // increase pool sizes
888 mod->pools[tar->type].size += lv2_atom_pad_size(tar->size);
889 }
890
891 // automation input port //FIXME check
892 {
893 const unsigned i = mod->num_ports - 2;
894 port_t *tar = &mod->ports[i];
895
896 tar->mod = mod;
897 tar->index = i;
898 tar->symbol = "__automation__in__";
899 tar->direction = PORT_DIRECTION_INPUT;
900
901 tar->size = app->driver->seq_size;
902 tar->type = PORT_TYPE_ATOM;
903 tar->protocol = app->regs.port.event_transfer.urid;
904 tar->driver = &seq_port_driver;
905
906 tar->atom.buffer_type = PORT_BUFFER_TYPE_SEQUENCE;
907
908 tar->sys.type = SYSTEM_PORT_NONE;
909 tar->sys.data = NULL;
910
911 // increase pool sizes
912 mod->pools[tar->type].size += lv2_atom_pad_size(tar->size);
913 }
914
915 // automation output port //FIXME check
916 {
917 const unsigned i = mod->num_ports - 1;
918 port_t *tar = &mod->ports[i];
919
920 tar->mod = mod;
921 tar->index = i;
922 tar->symbol = "__automation__out__";
923 tar->direction = PORT_DIRECTION_OUTPUT;
924
925 tar->size = app->driver->seq_size;
926 tar->type = PORT_TYPE_ATOM;
927 tar->protocol = app->regs.port.event_transfer.urid;
928 tar->driver = &seq_port_driver;
929
930 tar->atom.buffer_type = PORT_BUFFER_TYPE_SEQUENCE;
931
932 tar->sys.type = SYSTEM_PORT_NONE;
933 tar->sys.data = NULL;
934
935 // increase pool sizes
936 mod->pools[tar->type].size += lv2_atom_pad_size(tar->size);
937 }
938
939 // allocate 8-byte aligned buffer per plugin and port type pool
940 int alloc_failed = 0;
941 for(port_type_t pool=0; pool<PORT_TYPE_NUM; pool++)
942 {
943 if(_sp_app_mod_alloc_pool(&mod->pools[pool]))
944 {
945 alloc_failed = 1;
946 break;
947 }
948 }
949
950 if(alloc_failed)
951 {
952 sp_app_log_error(app, "%s: pool tiling failed\n", __func__);
953
954 for(port_type_t pool=0; pool<PORT_TYPE_NUM; pool++)
955 _sp_app_mod_free_pool(&mod->pools[pool]);
956
957 free(mod->uri_str);
958 free(mod->ports);
959 free(mod);
960
961 return NULL;
962 }
963
964 // slice plugin buffer into per-port-type-and-direction regions for
965 // efficient dereference in plugin instance
966 for(port_type_t pool=0; pool<PORT_TYPE_NUM; pool++)
967 _sp_app_mod_slice_pool(mod, pool);
968
969 for(unsigned i=0; i<mod->num_ports - 2; i++)
970 {
971 port_t *tar = &mod->ports[i];
972
973 // set port buffer
974 lilv_instance_connect_port(mod->inst, i, tar->base);
975 }
976
977 // load presets
978 mod->presets = lilv_plugin_get_related(plug, app->regs.pset.preset.node);
979
980 // spawn worker thread
981 if(mod->worker.iface || mod->idisp.iface)
982 {
983 mod_worker_t *mod_worker = &mod->mod_worker;
984
985 sem_init(&mod_worker->sem, 0, 0);
986 atomic_init(&mod_worker->kill, false);
987 mod_worker->app_to_worker = varchunk_new(2048, true); //FIXME how big
988 mod_worker->state_to_worker = varchunk_new(2048, true); //FIXME how big
989 mod_worker->app_from_worker = varchunk_new(2048, true); //FIXME how big
990 pthread_attr_t attr;
991 pthread_attr_init(&attr);
992 pthread_create(&mod_worker->thread, &attr, _mod_worker_thread, mod);
993 }
994
995 // activate
996 lilv_instance_activate(mod->inst);
997
998 // load default state
999 if(load_default_state && _sp_app_state_preset_load(app, mod, uri, false))
1000 sp_app_log_error(app, "%s: default state loading failed\n", __func__);
1001
1002 // initialize profiling reference time
1003 mod->prof.sum = 0;
1004
1005 return mod;
1006 }
1007
1008 int
_sp_app_mod_del(sp_app_t * app,mod_t * mod)1009 _sp_app_mod_del(sp_app_t *app, mod_t *mod)
1010 {
1011 // deinit worker thread
1012 if(mod->worker.iface || mod->idisp.iface)
1013 {
1014 mod_worker_t *mod_worker = &mod->mod_worker;
1015
1016 atomic_store_explicit(&mod_worker->kill, true, memory_order_release);
1017 sem_post(&mod_worker->sem);
1018 void *ret;
1019 pthread_join(mod_worker->thread, &ret);
1020 varchunk_free(mod_worker->app_to_worker);
1021 varchunk_free(mod_worker->state_to_worker);
1022 varchunk_free(mod_worker->app_from_worker);
1023 sem_destroy(&mod_worker->sem);
1024 }
1025
1026 // deinit instance
1027 lilv_nodes_free(mod->presets);
1028 lilv_instance_deactivate(mod->inst);
1029 lilv_instance_free(mod->inst);
1030
1031 // free memory
1032 for(port_type_t pool=0; pool<PORT_TYPE_NUM; pool++)
1033 _sp_app_mod_free_pool(&mod->pools[pool]);
1034
1035 // unregister system ports
1036 for(unsigned i=0; i<mod->num_ports; i++)
1037 {
1038 port_t *port = &mod->ports[i];
1039
1040 if(port->sys.data && app->driver->system_port_del)
1041 app->driver->system_port_del(app->data, port->sys.data);
1042 }
1043
1044 // free ports
1045 if(mod->ports)
1046 {
1047 free(mod->ports);
1048 }
1049
1050 if(mod->uri_str)
1051 free(mod->uri_str);
1052
1053 free(mod);
1054
1055 return 0; //success
1056 }
1057
1058 mod_t *
_sp_app_mod_get_by_uid(sp_app_t * app,int32_t uid)1059 _sp_app_mod_get_by_uid(sp_app_t *app, int32_t uid)
1060 {
1061 for(unsigned m = 0; m < app->num_mods; m++)
1062 {
1063 mod_t *mod = app->mods[m];
1064
1065 if(mod->uid == uid)
1066 return mod;
1067 }
1068
1069 return NULL;
1070 }
1071
1072 void
_sp_app_mod_eject(sp_app_t * app,mod_t * mod)1073 _sp_app_mod_eject(sp_app_t *app, mod_t *mod)
1074 {
1075 // eject module from graph
1076 app->num_mods -= 1;
1077 // remove mod from ->mods
1078 for(unsigned m=0, offset=0; m<app->num_mods; m++)
1079 {
1080 if(app->mods[m] == mod)
1081 offset += 1;
1082 app->mods[m] = app->mods[m+offset];
1083 }
1084
1085 // disconnect all ports
1086 for(unsigned p1=0; p1<mod->num_ports; p1++)
1087 {
1088 port_t *port = &mod->ports[p1];
1089
1090 connectable_t *conn = _sp_app_port_connectable(port);
1091 if(conn)
1092 {
1093 // disconnect sources
1094 for(int s=0; s<conn->num_sources; s++)
1095 _sp_app_port_disconnect(app, conn->sources[s].port, port);
1096 }
1097
1098 // disconnect sinks
1099 for(unsigned m=0; m<app->num_mods; m++)
1100 {
1101 for(unsigned p2=0; p2<app->mods[m]->num_ports; p2++)
1102 _sp_app_port_disconnect(app, port, &app->mods[m]->ports[p2]);
1103 }
1104 }
1105
1106 // send request to worker thread
1107 size_t size = sizeof(job_t);
1108 job_t *job = _sp_app_to_worker_request(app, size);
1109 if(job)
1110 {
1111 job->request = JOB_TYPE_REQUEST_MODULE_DEL;
1112 job->mod = mod;
1113 _sp_app_to_worker_advance(app, size);
1114 }
1115 else
1116 {
1117 sp_app_log_error(app, "%s: failed requesting buffer\n", __func__);
1118 }
1119
1120 _sp_app_order(app);
1121
1122 #if 0
1123 // signal to ui
1124 size = sizeof(transmit_module_del_t);
1125 transmit_module_del_t *trans = _sp_app_to_ui_request(app, size);
1126 if(trans)
1127 {
1128 _sp_transmit_module_del_fill(&app->regs, &app->forge, trans, size, mod->uid);
1129 _sp_app_to_ui_advance(app, size);
1130 }
1131 #endif
1132 }
1133
1134 static void
_sp_app_mod_reinitialize_soft(mod_t * mod)1135 _sp_app_mod_reinitialize_soft(mod_t *mod)
1136 {
1137 sp_app_t *app = mod->app;
1138
1139 // reinitialize all modules,
1140 lilv_instance_deactivate(mod->inst);
1141 lilv_instance_free(mod->inst);
1142
1143 mod->inst = NULL;
1144 mod->handle = NULL;
1145
1146 // mod->features should be up-to-date
1147 mod->inst = lilv_plugin_instantiate(mod->plug, app->driver->sample_rate, mod->features);
1148 mod->handle = lilv_instance_get_handle(mod->inst);
1149
1150 // refresh all connections
1151 for(unsigned i=0; i<mod->num_ports - 2; i++)
1152 {
1153 port_t *tar = &mod->ports[i];
1154
1155 // set port buffer
1156 lilv_instance_connect_port(mod->inst, i, tar->base);
1157 }
1158 }
1159
1160 void
_sp_app_mod_reinstantiate(sp_app_t * app,mod_t * mod)1161 _sp_app_mod_reinstantiate(sp_app_t *app, mod_t *mod)
1162 {
1163 char *path;
1164
1165 if(asprintf(&path, "file:///tmp/%s.preset.lv2", mod->urn_uri) == -1)
1166 {
1167 sp_app_log_note(app, "%s: failed to create temporary path\n", __func__);
1168 return;
1169 }
1170
1171 LilvState *const state = _sp_app_state_preset_create(app, mod, path);
1172 free(path);
1173
1174 if(state)
1175 {
1176 _sp_app_mod_reinitialize_soft(mod);
1177
1178 lilv_instance_activate(mod->inst);
1179
1180 _sp_app_state_preset_restore(app, mod, state, false);
1181
1182 lilv_state_free(state);
1183 }
1184 }
1185