3 * Copyright (C) 2016-2020 William Morrow
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 #include "bcwindowbase.h"
25 #include "pluginlv2.h"
31 PluginLV2::PluginLV2()
36 in_buffers = 0; iport = 0;
37 out_buffers = 0; oport = 0;
64 powerOf2BlockLength = 0;
66 boundedBlockLength = 0;
70 memset(&schedule, 0, sizeof(schedule));
71 schedule.handle = (LV2_Worker_Schedule_Handle)this;
72 schedule.schedule_work = lv2_worker_schedule;
73 worker_iface = 0; worker_done = -1;
74 pthread_mutex_init(&worker_lock, 0);
75 pthread_mutex_init(&startup_lock, 0);
76 pthread_mutex_lock(&startup_lock);
77 pthread_cond_init(&worker_ready, 0);
78 work_avail = 0; work_input = 0;
79 work_output = 0; work_tail = &work_output;
82 PluginLV2::~PluginLV2()
85 if( world ) lilv_world_free(world);
86 pthread_mutex_destroy(&worker_lock);
87 pthread_cond_destroy(&worker_ready);
90 void PluginLV2::reset_lv2()
93 if( inst ) lilv_instance_deactivate(inst);
94 lilv_instance_free(inst); inst = 0;
95 lilv_uis_free(lilv_uis); lilv_uis = 0;
97 lilv_node_free(lv2_InputPort); lv2_InputPort = 0;
98 lilv_node_free(lv2_OutputPort); lv2_OutputPort = 0;
99 lilv_node_free(lv2_AudioPort); lv2_AudioPort = 0;
100 lilv_node_free(lv2_ControlPort); lv2_ControlPort = 0;
101 lilv_node_free(lv2_CVPort); lv2_CVPort = 0;
103 lilv_node_free(lv2_Optional); lv2_Optional = 0;
104 lilv_node_free(atom_AtomPort); atom_AtomPort = 0;
105 lilv_node_free(atom_Sequence); atom_Sequence = 0;
106 lilv_node_free(boundedBlockLength); boundedBlockLength = 0;
107 lilv_node_free(fixedBlockLength); fixedBlockLength = 0;
108 lilv_node_free(powerOf2BlockLength); powerOf2BlockLength = 0;
110 delete [] (char *)seq_out; seq_out = 0;
111 uri_table.remove_all_objects();
112 features.remove_all_objects(); ui_features = 0;
117 int PluginLV2::load_lv2(const char *path, char *title)
120 world = lilv_world_new();
122 printf("lv2: lilv_world_new failed\n");
125 lilv_world_load_all(world);
128 LilvNode *uri = lilv_new_uri(world, path);
130 printf("lv2: lilv_new_uri(%s) failed\n", path);
134 const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
135 lilv = lilv_plugins_get_by_uri(all_plugins, uri);
138 printf("lv2: lilv_plugins_get_by_uri (%s) failed\n", path);
143 LilvNode *name = lilv_plugin_get_name(lilv);
144 const char *nm = lilv_node_as_string(name);
145 sprintf(title, "L2_%s", nm);
146 lilv_node_free(name);
151 int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate, int bfrsz)
154 double bps = 2. * sample_rate / bfrsz;
155 if( bps > refreshrate ) refreshrate = bps;
157 lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
158 lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
159 lv2_CVPort = lilv_new_uri(world, LV2_CORE__CVPort);
160 lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
161 lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
162 lv2_Optional = lilv_new_uri(world, LV2_CORE__connectionOptional);
163 atom_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort);
164 atom_Sequence = lilv_new_uri(world, LV2_ATOM__Sequence);
165 powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
166 fixedBlockLength = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
167 boundedBlockLength = lilv_new_uri(world, LV2_BUF_SIZE__boundedBlockLength);
168 seq_out = (LV2_Atom_Sequence *) new char[sizeof(LV2_Atom_Sequence) + LV2_SEQ_SIZE];
170 conf.init_lv2(lilv, this);
171 nb_inputs = nb_outputs = 0;
173 for( int i=0; i<conf.nb_ports; ++i ) {
174 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
176 int is_input = lilv_port_is_a(lilv, lp, lv2_InputPort);
177 if( !is_input && !lilv_port_is_a(lilv, lp, lv2_OutputPort) &&
178 !lilv_port_has_property(lilv, lp, lv2_Optional) ) {
179 printf("lv2: not input, not output, and not optional: %s\n", conf.names[i]);
182 if( is_input && lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
183 conf.append(new PluginLV2Client_Opt(&conf, i));
186 if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
187 lilv_port_is_a(lilv, lp, lv2_CVPort ) ) {
188 if( is_input ) ++nb_inputs; else ++nb_outputs;
193 if( !nb_inputs || !nb_outputs ) {
194 printf(": Unsupported lv2 plugin, missing audio input or output\n");
199 uri_map.handle = (LV2_URID_Map_Handle)this;
200 uri_map.map = map_uri;
201 features.append(new Lv2Feature(LV2_URID__map, &uri_map));
202 uri_unmap.handle = (LV2_URID_Unmap_Handle)this;
203 uri_unmap.unmap = unmap_uri;
204 features.append(new Lv2Feature(LV2_URID__unmap, &uri_unmap));
205 features.append(new Lv2Feature(LV2_BUF_SIZE__powerOf2BlockLength, 0));
206 features.append(new Lv2Feature(LV2_BUF_SIZE__fixedBlockLength, 0));
207 features.append(new Lv2Feature(LV2_BUF_SIZE__boundedBlockLength, 0));
208 features.append(new Lv2Feature(LV2_WORKER__schedule, &schedule));
210 if( sample_rate < 64 ) sample_rate = samplerate;
212 atom_int = uri_table.map(LV2_ATOM__Int);
213 atom_float = uri_table.map(LV2_ATOM__Float);
214 param_sampleRate = uri_table.map(LV2_PARAMETERS__sampleRate);
215 bufsz_minBlockLength = uri_table.map(LV2_BUF_SIZE__minBlockLength);
216 bufsz_maxBlockLength = uri_table.map(LV2_BUF_SIZE__maxBlockLength);
217 bufsz_sequenceSize = uri_table.map(LV2_BUF_SIZE__sequenceSize);
218 ui_updateRate = uri_table.map(LV2_UI__updateRate);
220 samplerate = sample_rate;
221 options.add(param_sampleRate, sizeof(float), atom_float, &samplerate);
222 if( min_block_length > bfrsz ) min_block_length = bfrsz;
223 options.add(bufsz_minBlockLength, sizeof(int), atom_int, &min_block_length);
224 block_length = bfrsz;
225 options.add(bufsz_maxBlockLength, sizeof(int), atom_int, &block_length);
226 options.add(bufsz_sequenceSize, sizeof(int), atom_int, &midi_buf_size);
227 options.add(ui_updateRate, sizeof(float), atom_float, &refreshrate);
228 options.add(0, 0, 0, 0);
230 features.append(new Lv2Feature(LV2_OPTIONS__options, &options[0]));
233 inst = lilv_plugin_instantiate(lilv, sample_rate, features);
235 printf("lv2: lilv_plugin_instantiate failed\n");
239 // After instantiate, some plugins require fields to be filled in before
240 // activate is called. This is done via ConnectPort, which connects a
241 // port to a data structure in the host (CinGG). So these have to be
245 connect_ports(conf, PORTS_ALL);
247 const LV2_Descriptor *lilv_desc = inst->lv2_descriptor;
248 worker_iface = !lilv_desc->extension_data ? 0 :
249 (LV2_Worker_Interface*)lilv_desc->extension_data(LV2_WORKER__interface);
253 lilv_instance_activate(inst);
254 // not sure what to do with these
255 max_bufsz = nb_inputs &&
256 (lilv_plugin_has_feature(lilv, powerOf2BlockLength) ||
257 lilv_plugin_has_feature(lilv, fixedBlockLength) ||
258 lilv_plugin_has_feature(lilv, boundedBlockLength)) ? 4096 : 0;
263 uint32_t PluginLV2::map_uri(LV2_URID_Map_Handle handle, const char *uri)
265 PluginLV2 *the = (PluginLV2 *)handle;
266 return the->uri_table.map(uri);
269 const char *PluginLV2::unmap_uri(LV2_URID_Unmap_Handle handle, LV2_URID urid)
271 PluginLV2 *the = (PluginLV2 *)handle;
272 return the->uri_table.unmap(urid);
275 void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int ports)
277 int ich = 0, och = 0;
278 for( int i=0; i<conf.nb_ports; ++i ) {
279 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
281 int port = conf.ports[i];
282 if( !(port & ports) ) continue;
283 if( (port & PORTS_CONTROL) ) {
284 lilv_instance_connect_port(inst, i, &conf.ctls[i]);
287 if( (port & PORTS_AUDIO) ) {
288 if( (port & PORTS_INPUT) ) {
289 lilv_instance_connect_port(inst, i, in_buffers[ich]);
292 else if( (port & PORTS_OUTPUT) ) {
293 lilv_instance_connect_port(inst, i, out_buffers[och]);
298 if( (port & PORTS_ATOM) ) {
299 if( (port & PORTS_INPUT) )
300 lilv_instance_connect_port(inst, i, &seq_in);
302 lilv_instance_connect_port(inst, i, seq_out);
307 seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body);
308 seq_in[0].atom.type = uri_table.map(LV2_ATOM__Sequence);
309 seq_in[1].atom.size = 0;
310 seq_in[1].atom.type = 0;
311 seq_out->atom.size = LV2_SEQ_SIZE;
312 seq_out->atom.type = uri_table.map(LV2_ATOM__Chunk);
315 void PluginLV2::del_buffer()
320 delete [] in_buffers; in_buffers = 0;
321 delete [] out_buffers; out_buffers = 0;
324 void PluginLV2::new_buffer(int64_t sz)
327 if( use_shm ) { // currently, always uses shm
328 shmid = shmget(IPC_PRIVATE, sz, IPC_CREAT | 0777);
330 bp = (unsigned char*)shmat(shmid, NULL, 0);
331 if( bp == (void *) -1 ) { perror("shmat"); bp = 0; }
332 shmctl(shmid, IPC_RMID, 0); // delete when last ref gone
335 perror("PluginLV2::allocate_buffer: shmget failed\n");
336 BC_Trace::dump_shm_stats(stdout);
340 shm_bfr = (shm_bfr_t *) bp;
341 if( shm_bfr ) shm_bfr->sz = sz;
344 shm_bfr_t *PluginLV2::shm_buffer(int shmid)
346 if( this->shmid != shmid ) {
347 if( this->shmid >= 0 ) {
348 shmdt(shm_bfr); this->shmid = -1;
352 shm_bfr = (shm_bfr_t *)shmat(shmid, NULL, 0);
353 if( shm_bfr == (void *)-1 ) { perror("shmat"); shm_bfr = 0; }
354 this->shmid = shm_bfr ? shmid : -1;
360 void PluginLV2::init_buffer(int samples)
362 int64_t sz = sizeof(shm_bfr_t) +
363 sizeof(iport[0])*nb_inputs + sizeof(oport[0])*nb_outputs +
364 sizeof(*in_buffers[0]) *samples * nb_inputs +
365 sizeof(*out_buffers[0])*samples * nb_outputs;
368 if( shm_bfr->sz < sz ||
369 shm_bfr->nb_inputs != nb_inputs ||
370 shm_bfr->nb_outputs != nb_outputs )
377 shm_bfr->samples = samples;
379 shm_bfr->nb_inputs = nb_inputs;
380 shm_bfr->nb_outputs = nb_outputs;
388 // int samples, done;
389 // int nb_inputs, nb_outputs;
390 // int iport[nb_inputs],
391 // float in_buffers[samples][nb_inputs];
392 // int oport[nb_outputs];
393 // float out_buffers[samples][nb_outputs];
396 void PluginLV2::map_buffer()
398 uint8_t *bp = (uint8_t *)(shm_bfr + 1);
400 nb_inputs = shm_bfr->nb_inputs;
402 bp += sizeof(iport[0])*nb_inputs;
403 in_buffers = new float*[nb_inputs];
404 int samples = shm_bfr->samples;
405 for(int i=0; i<nb_inputs; ++i ) {
406 in_buffers[i] = (float *)bp;
407 bp += sizeof(*in_buffers[0])*samples;
410 nb_outputs = shm_bfr->nb_outputs;
412 bp += sizeof(oport[0])*nb_outputs;
413 out_buffers = new float*[nb_outputs];
414 for( int i=0; i<nb_outputs; ++i ) {
415 out_buffers[i] = (float *)bp;
416 bp += sizeof(*out_buffers[0])*samples;
423 PluginLV2Work::PluginLV2Work()
430 PluginLV2Work::~PluginLV2Work()
435 void PluginLV2Work::load(const void *vp, unsigned size)
439 data = new char[alloc=size];
441 memcpy(data, vp, used=size);
444 PluginLV2Work *PluginLV2::get_work()
446 // must hold worker_lock
447 if( !work_avail ) return new PluginLV2Work();
448 PluginLV2Work *wp = work_avail;
449 work_avail = wp->next; wp->next = 0;
453 void *PluginLV2::worker_func()
455 pthread_mutex_lock(&worker_lock);
456 pthread_mutex_unlock(&startup_lock);
458 while( !worker_done && !work_input )
459 pthread_cond_wait(&worker_ready, &worker_lock);
460 if( worker_done ) break;
461 PluginLV2Work *wp = work_input; work_input = wp->next;
463 pthread_mutex_unlock(&worker_lock);
464 worker_iface->work(inst, lv2_worker_respond, this, wp->used, wp->data);
465 pthread_mutex_lock(&worker_lock);
466 wp->next = work_avail; work_avail = wp;
468 pthread_mutex_unlock(&worker_lock);
471 void *PluginLV2::worker_func(void* vp)
473 PluginLV2 *the = (PluginLV2 *)vp;
474 return the->worker_func();
477 void PluginLV2::worker_start()
479 pthread_create(&worker_thread, 0, worker_func, this);
480 pthread_mutex_lock(&startup_lock);
483 void PluginLV2::worker_stop()
487 pthread_mutex_lock(&worker_lock);
488 pthread_cond_signal(&worker_ready);
489 pthread_mutex_unlock(&worker_lock);
490 pthread_join(worker_thread, 0);
493 work_stop(work_avail);
494 work_stop(work_input);
495 work_stop(work_output);
496 work_tail = &work_output;
499 void PluginLV2::work_stop(PluginLV2Work *&work)
502 PluginLV2Work *wp = work;
508 LV2_Worker_Status PluginLV2::worker_schedule(uint32_t inp_size, const void *inp_data)
511 if( !pthread_mutex_trylock(&worker_lock) ) {
512 PluginLV2Work *wp = get_work();
513 wp->load(inp_data, inp_size);
514 wp->next = work_input; work_input = wp;
515 pthread_cond_signal(&worker_ready);
516 pthread_mutex_unlock(&worker_lock);
519 else if( worker_iface )
520 worker_iface->work(inst, lv2_worker_respond, this, inp_size, inp_data);
521 return LV2_WORKER_SUCCESS;
523 LV2_Worker_Status PluginLV2::lv2_worker_schedule(LV2_Worker_Schedule_Handle vp,
524 uint32_t inp_size, const void *inp_data)
526 PluginLV2 *the = (PluginLV2 *)vp;
527 return the->worker_schedule(inp_size, inp_data);
530 LV2_Worker_Status PluginLV2::worker_respond(uint32_t out_size, const void *out_data)
532 pthread_mutex_lock(&worker_lock);
533 PluginLV2Work *wp = get_work();
534 wp->load(out_data, out_size);
535 *work_tail = wp; work_tail = &wp->next;
536 pthread_mutex_unlock(&worker_lock);
537 return LV2_WORKER_SUCCESS;
539 LV2_Worker_Status PluginLV2::lv2_worker_respond(LV2_Worker_Respond_Handle vp,
540 uint32_t out_size, const void *out_data)
542 PluginLV2 *the = (PluginLV2 *)vp;
543 return the->worker_respond(out_size, out_data);
546 void PluginLV2::worker_responses()
548 pthread_mutex_lock(&worker_lock);
549 while( work_output ) {
550 PluginLV2Work *rp = work_output;
551 if( !(work_output=rp->next) ) work_tail = &work_output;
552 pthread_mutex_unlock(&worker_lock);
553 worker_iface->work_response(inst, rp->used, rp->data);
554 pthread_mutex_lock(&worker_lock);
555 rp->next = work_avail; work_avail = rp;
557 pthread_mutex_unlock(&worker_lock);
561 #include "pluginlv2ui.h"
563 PluginLV2ChildUI::PluginLV2ChildUI()
571 PluginLV2ChildUI::~PluginLV2ChildUI()
576 void PluginLV2ChildUI::run()
578 ArrayList<char *> av;
579 av.set_array_delete();
581 const char *exec_path = File::get_cinlib_path();
582 snprintf(arg, sizeof(arg), "%s/%s", exec_path, "lv2ui");
583 av.append(cstrdup(arg));
584 sprintf(arg, "%d", child_fd);
585 av.append(cstrdup(arg));
586 sprintf(arg, "%d", parent_fd);
587 av.append(cstrdup(arg));
588 sprintf(arg, "%d", ppid);
589 av.append(cstrdup(arg));
591 execv(av[0], &av.values[0]);
592 fprintf(stderr, "execv failed: %s\n %m\n", av.values[0]);
593 av.remove_all_objects();
597 #define LV2_EXTERNAL_UI_URI__KX__Widget "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget"
599 PluginLV2UI::PluginLV2UI()
610 memset(&uri_map, 0, sizeof(uri_map));
611 memset(&uri_unmap, 0, sizeof(uri_unmap));
612 memset(&extui_host, 0, sizeof(extui_host));
613 wgt_type = LV2_EXTERNAL_UI_URI__KX__Widget;
614 gtk_type = LV2_UI__GtkUI;
618 PluginLV2UI::~PluginLV2UI ()