4 #include "bcwindowbase.h"
11 PluginLV2::PluginLV2()
16 in_buffers = 0; iport = 0;
17 out_buffers = 0; oport = 0;
43 powerOf2BlockLength = 0;
45 boundedBlockLength = 0;
49 memset(&schedule, 0, sizeof(schedule));
50 schedule.handle = (LV2_Worker_Schedule_Handle)this;
51 schedule.schedule_work = lv2_worker_schedule;
52 worker_iface = 0; worker_done = -1;
53 pthread_mutex_init(&worker_lock, 0);
54 pthread_cond_init(&worker_ready, 0);
55 work_avail = 0; work_input = 0;
56 work_output = 0; work_tail = &work_output;
59 PluginLV2::~PluginLV2()
62 if( world ) lilv_world_free(world);
63 pthread_mutex_destroy(&worker_lock);
64 pthread_cond_destroy(&worker_ready);
67 void PluginLV2::reset_lv2()
70 if( inst ) lilv_instance_deactivate(inst);
71 lilv_instance_free(inst); inst = 0;
72 lilv_uis_free(lilv_uis); lilv_uis = 0;
74 lilv_node_free(lv2_InputPort); lv2_InputPort = 0;
75 lilv_node_free(lv2_OutputPort); lv2_OutputPort = 0;
76 lilv_node_free(lv2_AudioPort); lv2_AudioPort = 0;
77 lilv_node_free(lv2_ControlPort); lv2_ControlPort = 0;
78 lilv_node_free(lv2_CVPort); lv2_CVPort = 0;
80 lilv_node_free(lv2_Optional); lv2_Optional = 0;
81 lilv_node_free(atom_AtomPort); atom_AtomPort = 0;
82 lilv_node_free(atom_Sequence); atom_Sequence = 0;
83 lilv_node_free(boundedBlockLength); boundedBlockLength = 0;
84 lilv_node_free(fixedBlockLength); fixedBlockLength = 0;
85 lilv_node_free(powerOf2BlockLength); powerOf2BlockLength = 0;
87 delete [] (char *)seq_out; seq_out = 0;
88 uri_table.remove_all_objects();
89 features.remove_all_objects(); ui_features = 0;
94 int PluginLV2::load_lv2(const char *path, char *title)
97 world = lilv_world_new();
99 printf("lv2: lilv_world_new failed\n");
102 lilv_world_load_all(world);
105 LilvNode *uri = lilv_new_uri(world, path);
107 printf("lv2: lilv_new_uri(%s) failed\n", path);
111 const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
112 lilv = lilv_plugins_get_by_uri(all_plugins, uri);
115 printf("lv2: lilv_plugins_get_by_uri (%s) failed\n", path);
120 LilvNode *name = lilv_plugin_get_name(lilv);
121 const char *nm = lilv_node_as_string(name);
122 sprintf(title, "L2_%s", nm);
123 lilv_node_free(name);
128 int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate)
132 lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
133 lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
134 lv2_CVPort = lilv_new_uri(world, LV2_CORE__CVPort);
135 lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
136 lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
137 lv2_Optional = lilv_new_uri(world, LV2_CORE__connectionOptional);
138 atom_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort);
139 atom_Sequence = lilv_new_uri(world, LV2_ATOM__Sequence);
140 powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
141 fixedBlockLength = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
142 boundedBlockLength = lilv_new_uri(world, LV2_BUF_SIZE__boundedBlockLength);
143 seq_out = (LV2_Atom_Sequence *) new char[sizeof(LV2_Atom_Sequence) + LV2_SEQ_SIZE];
145 conf.init_lv2(lilv, this);
146 nb_inputs = nb_outputs = 0;
148 for( int i=0; i<conf.nb_ports; ++i ) {
149 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
151 int is_input = lilv_port_is_a(lilv, lp, lv2_InputPort);
152 if( !is_input && !lilv_port_is_a(lilv, lp, lv2_OutputPort) &&
153 !lilv_port_has_property(lilv, lp, lv2_Optional) ) {
154 printf("lv2: not input, not output, and not optional: %s\n", conf.names[i]);
157 if( is_input && lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
158 conf.append(new PluginLV2Client_Opt(&conf, i));
161 if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
162 lilv_port_is_a(lilv, lp, lv2_CVPort ) ) {
163 if( is_input ) ++nb_inputs; else ++nb_outputs;
169 uri_map.callback_data = (LV2_URI_Map_Callback_Data)this;
170 uri_map.uri_to_id = uri_to_id;
171 features.append(new Lv2Feature(NS_EXT "uri-map", &uri_map));
172 map.handle = (void*)&uri_table;
173 map.map = uri_table_map;
174 features.append(new Lv2Feature(LV2_URID_MAP_URI, &map));
175 unmap.handle = (void*)&uri_table;
176 unmap.unmap = uri_table_unmap;
177 features.append(new Lv2Feature(LV2_URID_UNMAP_URI, &unmap));
178 features.append(new Lv2Feature(LV2_BUF_SIZE__powerOf2BlockLength, 0));
179 features.append(new Lv2Feature(LV2_BUF_SIZE__fixedBlockLength, 0));
180 features.append(new Lv2Feature(LV2_BUF_SIZE__boundedBlockLength, 0));
181 features.append(new Lv2Feature(LV2_WORKER__schedule, &schedule));
183 if( sample_rate < 64 ) sample_rate = 44100;
185 atom_int = uri_table.map(LV2_ATOM__Int);
186 atom_float = uri_table.map(LV2_ATOM__Float);
187 param_sampleRate = uri_table.map(LV2_PARAMETERS__sampleRate);
188 bufsz_minBlockLength = uri_table.map(LV2_BUF_SIZE__minBlockLength);
189 bufsz_maxBlockLength = uri_table.map(LV2_BUF_SIZE__maxBlockLength);
190 bufsz_sequenceSize = uri_table.map(LV2_BUF_SIZE__sequenceSize);
191 ui_updateRate = uri_table.map(LV2_UI__updateRate);
193 samplerate = sample_rate;
194 options.add(param_sampleRate, sizeof(float), atom_float, &samplerate);
195 options.add(bufsz_minBlockLength, sizeof(int), atom_int, &block_length);
196 options.add(bufsz_maxBlockLength, sizeof(int), atom_int, &block_length);
197 options.add(bufsz_sequenceSize, sizeof(int), atom_int, &midi_buf_size);
198 options.add(ui_updateRate, sizeof(float), atom_float, &refreshrate);
199 options.add(0, 0, 0, 0);
201 features.append(new Lv2Feature(LV2_OPTIONS__options, &options[0]));
204 inst = lilv_plugin_instantiate(lilv, sample_rate, features);
206 printf("lv2: lilv_plugin_instantiate failed\n");
210 const LV2_Descriptor *lilv_desc = inst->lv2_descriptor;
211 worker_iface = !lilv_desc->extension_data ? 0 :
212 (LV2_Worker_Interface*)lilv_desc->extension_data(LV2_WORKER__interface);
216 lilv_instance_activate(inst);
217 // not sure what to do with these
218 max_bufsz = nb_inputs &&
219 (lilv_plugin_has_feature(lilv, powerOf2BlockLength) ||
220 lilv_plugin_has_feature(lilv, fixedBlockLength) ||
221 lilv_plugin_has_feature(lilv, boundedBlockLength)) ? 4096 : 0;
225 LV2_URID PluginLV2::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
227 return ((PluginLV2UriTable *)handle)->map(uri);
230 const char *PluginLV2::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
232 return ((PluginLV2UriTable *)handle)->unmap(urid);
235 uint32_t PluginLV2::uri_to_id(LV2_URI_Map_Callback_Data callback_data,
236 const char *map, const char *uri)
238 PluginLV2 *the = (PluginLV2 *)callback_data;
239 return the->map.map(the->uri_table, uri);
242 void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int ports)
244 int ich = 0, och = 0;
245 for( int i=0; i<conf.nb_ports; ++i ) {
246 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
248 int port = conf.ports[i];
249 if( !(port & ports) ) continue;
250 if( (port & PORTS_CONTROL) ) {
251 lilv_instance_connect_port(inst, i, &conf.ctls[i]);
254 if( (port & PORTS_AUDIO) ) {
255 if( (port & PORTS_INPUT) ) {
256 lilv_instance_connect_port(inst, i, in_buffers[ich]);
259 else if( (port & PORTS_OUTPUT) ) {
260 lilv_instance_connect_port(inst, i, out_buffers[och]);
265 if( (port & PORTS_ATOM) ) {
266 if( (port & PORTS_INPUT) )
267 lilv_instance_connect_port(inst, i, &seq_in);
269 lilv_instance_connect_port(inst, i, seq_out);
274 seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body);
275 seq_in[0].atom.type = uri_table.map(LV2_ATOM__Sequence);
276 seq_in[1].atom.size = 0;
277 seq_in[1].atom.type = 0;
278 seq_out->atom.size = LV2_SEQ_SIZE;
279 seq_out->atom.type = uri_table.map(LV2_ATOM__Chunk);
282 void PluginLV2::del_buffer()
287 delete [] in_buffers; in_buffers = 0;
288 delete [] out_buffers; out_buffers = 0;
291 void PluginLV2::new_buffer(int64_t sz)
294 if( use_shm ) { // currently, always uses shm
295 shmid = shmget(IPC_PRIVATE, sz, IPC_CREAT | 0777);
297 bp = (unsigned char*)shmat(shmid, NULL, 0);
298 if( bp == (void *) -1 ) { perror("shmat"); bp = 0; }
299 shmctl(shmid, IPC_RMID, 0); // delete when last ref gone
302 perror("PluginLV2::allocate_buffer: shmget failed\n");
303 BC_Trace::dump_shm_stats(stdout);
307 shm_bfr = (shm_bfr_t *) bp;
308 if( shm_bfr ) shm_bfr->sz = sz;
311 shm_bfr_t *PluginLV2::shm_buffer(int shmid)
313 if( this->shmid != shmid ) {
314 if( this->shmid >= 0 ) {
315 shmdt(shm_bfr); this->shmid = -1;
319 shm_bfr = (shm_bfr_t *)shmat(shmid, NULL, 0);
320 if( shm_bfr == (void *)-1 ) { perror("shmat"); shm_bfr = 0; }
321 this->shmid = shm_bfr ? shmid : -1;
327 void PluginLV2::init_buffer(int samples)
329 int64_t sz = sizeof(shm_bfr_t) +
330 sizeof(iport[0])*nb_inputs + sizeof(oport[0])*nb_outputs +
331 sizeof(*in_buffers[0]) *samples * nb_inputs +
332 sizeof(*out_buffers[0])*samples * nb_outputs;
335 if( shm_bfr->sz < sz ||
336 shm_bfr->nb_inputs != nb_inputs ||
337 shm_bfr->nb_outputs != nb_outputs )
344 shm_bfr->samples = samples;
346 shm_bfr->nb_inputs = nb_inputs;
347 shm_bfr->nb_outputs = nb_outputs;
355 // int samples, done;
356 // int nb_inputs, nb_outputs;
357 // int iport[nb_inputs],
358 // float in_buffers[samples][nb_inputs];
359 // int oport[nb_outputs];
360 // float out_buffers[samples][nb_outputs];
363 void PluginLV2::map_buffer()
365 uint8_t *bp = (uint8_t *)(shm_bfr + 1);
367 nb_inputs = shm_bfr->nb_inputs;
369 bp += sizeof(iport[0])*nb_inputs;
370 in_buffers = new float*[nb_inputs];
371 int samples = shm_bfr->samples;
372 for(int i=0; i<nb_inputs; ++i ) {
373 in_buffers[i] = (float *)bp;
374 bp += sizeof(*in_buffers[0])*samples;
377 nb_outputs = shm_bfr->nb_outputs;
379 bp += sizeof(oport[0])*nb_outputs;
380 out_buffers = new float*[nb_outputs];
381 for( int i=0; i<nb_outputs; ++i ) {
382 out_buffers[i] = (float *)bp;
383 bp += sizeof(*out_buffers[0])*samples;
390 PluginLV2Work::PluginLV2Work()
397 PluginLV2Work::~PluginLV2Work()
402 void PluginLV2Work::load(const void *vp, unsigned size)
406 data = new char[alloc=size];
408 memcpy(data, vp, used=size);
411 PluginLV2Work *PluginLV2::get_work()
413 // must hold worker_lock
414 if( !work_avail ) return new PluginLV2Work();
415 PluginLV2Work *wp = work_avail;
416 work_avail = wp->next; wp->next = 0;
420 void *PluginLV2::worker_func()
422 pthread_mutex_lock(&worker_lock);
424 while( !worker_done && !work_input )
425 pthread_cond_wait(&worker_ready, &worker_lock);
426 if( worker_done ) break;
427 PluginLV2Work *wp = work_input; work_input = wp->next;
429 pthread_mutex_unlock(&worker_lock);
430 worker_iface->work(inst, lv2_worker_respond, this, wp->used, wp->data);
431 pthread_mutex_lock(&worker_lock);
432 wp->next = work_avail; work_avail = wp;
434 pthread_mutex_unlock(&worker_lock);
437 void *PluginLV2::worker_func(void* vp)
439 PluginLV2 *the = (PluginLV2 *)vp;
440 return the->worker_func();
443 void PluginLV2::worker_start()
445 pthread_create(&worker_thread, 0, worker_func, this);
448 void PluginLV2::worker_stop()
452 pthread_mutex_lock(&worker_lock);
453 pthread_cond_signal(&worker_ready);
454 pthread_mutex_unlock(&worker_lock);
455 pthread_join(worker_thread, 0);
458 work_stop(work_avail);
459 work_stop(work_input);
460 work_stop(work_output);
461 work_tail = &work_output;
464 void PluginLV2::work_stop(PluginLV2Work *&work)
467 PluginLV2Work *wp = work;
473 LV2_Worker_Status PluginLV2::worker_schedule(uint32_t inp_size, const void *inp_data)
476 if( !pthread_mutex_trylock(&worker_lock) ) {
477 PluginLV2Work *wp = get_work();
478 wp->load(inp_data, inp_size);
479 wp->next = work_input; work_input = wp;
480 pthread_cond_signal(&worker_ready);
481 pthread_mutex_unlock(&worker_lock);
484 else if( worker_iface )
485 worker_iface->work(inst, lv2_worker_respond, this, inp_size, inp_data);
486 return LV2_WORKER_SUCCESS;
488 LV2_Worker_Status PluginLV2::lv2_worker_schedule(LV2_Worker_Schedule_Handle vp,
489 uint32_t inp_size, const void *inp_data)
491 PluginLV2 *the = (PluginLV2 *)vp;
492 return the->worker_schedule(inp_size, inp_data);
495 LV2_Worker_Status PluginLV2::worker_respond(uint32_t out_size, const void *out_data)
497 pthread_mutex_lock(&worker_lock);
498 PluginLV2Work *wp = get_work();
499 wp->load(out_data, out_size);
500 *work_tail = wp; work_tail = &wp->next;
501 pthread_mutex_unlock(&worker_lock);
502 return LV2_WORKER_SUCCESS;
504 LV2_Worker_Status PluginLV2::lv2_worker_respond(LV2_Worker_Respond_Handle vp,
505 uint32_t out_size, const void *out_data)
507 PluginLV2 *the = (PluginLV2 *)vp;
508 return the->worker_respond(out_size, out_data);
511 void PluginLV2::worker_responses()
513 pthread_mutex_lock(&worker_lock);
514 while( work_output ) {
515 PluginLV2Work *rp = work_output;
516 if( !(work_output=rp->next) ) work_tail = &work_output;
517 pthread_mutex_unlock(&worker_lock);
518 worker_iface->work_response(inst, rp->used, rp->data);
519 pthread_mutex_lock(&worker_lock);
520 rp->next = work_avail; work_avail = rp;
522 pthread_mutex_unlock(&worker_lock);
526 #include "pluginlv2ui.h"
528 PluginLV2ChildUI::PluginLV2ChildUI()
536 PluginLV2ChildUI::~PluginLV2ChildUI()
541 void PluginLV2ChildUI::run()
543 ArrayList<char *> av;
544 av.set_array_delete();
546 const char *exec_path = File::get_cinlib_path();
547 snprintf(arg, sizeof(arg), "%s/%s", exec_path, "lv2ui");
548 av.append(cstrdup(arg));
549 sprintf(arg, "%d", child_fd);
550 av.append(cstrdup(arg));
551 sprintf(arg, "%d", parent_fd);
552 av.append(cstrdup(arg));
553 sprintf(arg, "%d", ppid);
554 av.append(cstrdup(arg));
556 execv(av[0], &av.values[0]);
557 fprintf(stderr, "execv failed: %s\n %m\n", av.values[0]);
558 av.remove_all_objects();
562 #define LV2_EXTERNAL_UI_URI__KX__Widget "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget"
564 PluginLV2UI::PluginLV2UI()
575 memset(&uri_map, 0, sizeof(uri_map));
576 memset(&extui_host, 0, sizeof(extui_host));
577 wgt_type = LV2_EXTERNAL_UI_URI__KX__Widget;
578 gtk_type = LV2_UI__GtkUI;
582 PluginLV2UI::~PluginLV2UI ()