remove incorrectly named
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / pluginlv2.C
1 #ifdef HAVE_LV2
2
3 #include "bctrace.h"
4 #include "bcwindowbase.h"
5 #include "pluginlv2.h"
6 #include "samples.h"
7
8 #include <sys/shm.h>
9 #include <sys/mman.h>
10
11 PluginLV2::PluginLV2()
12 {
13         shm_bfr = 0;
14         use_shm = 1;
15         shmid = -1;
16         in_buffers = 0;   iport = 0;
17         out_buffers = 0;  oport = 0;
18         nb_inputs = 0;
19         nb_outputs = 0;
20         max_bufsz = 0;
21         ui_features = 0;
22
23         samplerate = 44100;
24         refreshrate = 30.;
25         min_block_length = 1;
26         block_length = 4096;
27         midi_buf_size = 8192;
28
29         world = 0;
30         lilv = 0;
31         lilv_uis = 0;
32         inst = 0;
33         sinst = 0;
34         ui_host = 0;
35
36         lv2_InputPort = 0;
37         lv2_OutputPort = 0;
38         lv2_AudioPort = 0;
39         lv2_ControlPort = 0;
40         lv2_CVPort = 0;
41         lv2_Optional = 0;
42         atom_AtomPort = 0;
43         atom_Sequence = 0;
44         powerOf2BlockLength = 0;
45         fixedBlockLength = 0;
46         boundedBlockLength = 0;
47         seq_out = 0;
48
49         worker_thread = 0;
50         memset(&schedule, 0, sizeof(schedule));
51         schedule.handle = (LV2_Worker_Schedule_Handle)this;
52         schedule.schedule_work = lv2_worker_schedule;
53         worker_iface = 0;  worker_done = -1;
54         pthread_mutex_init(&worker_lock, 0);
55         pthread_mutex_init(&startup_lock, 0);
56         pthread_mutex_lock(&startup_lock);
57         pthread_cond_init(&worker_ready, 0);
58         work_avail = 0;   work_input = 0;
59         work_output = 0;  work_tail = &work_output;
60 }
61
62 PluginLV2::~PluginLV2()
63 {
64         reset_lv2();
65         if( world )     lilv_world_free(world);
66         pthread_mutex_destroy(&worker_lock);
67         pthread_cond_destroy(&worker_ready);
68 }
69
70 void PluginLV2::reset_lv2()
71 {
72         worker_stop();
73         if( inst ) lilv_instance_deactivate(inst);
74         lilv_instance_free(inst);             inst = 0;
75         lilv_uis_free(lilv_uis);              lilv_uis = 0;
76
77         lilv_node_free(lv2_InputPort);        lv2_InputPort = 0;
78         lilv_node_free(lv2_OutputPort);       lv2_OutputPort = 0;
79         lilv_node_free(lv2_AudioPort);        lv2_AudioPort = 0;
80         lilv_node_free(lv2_ControlPort);      lv2_ControlPort = 0;
81         lilv_node_free(lv2_CVPort);           lv2_CVPort = 0;
82
83         lilv_node_free(lv2_Optional);         lv2_Optional = 0;
84         lilv_node_free(atom_AtomPort);        atom_AtomPort = 0;
85         lilv_node_free(atom_Sequence);        atom_Sequence = 0;
86         lilv_node_free(boundedBlockLength);   boundedBlockLength = 0;
87         lilv_node_free(fixedBlockLength);     fixedBlockLength = 0;
88         lilv_node_free(powerOf2BlockLength);  powerOf2BlockLength = 0;
89
90         delete [] (char *)seq_out;            seq_out = 0;
91         uri_table.remove_all_objects();
92         features.remove_all_objects();        ui_features = 0;
93         del_buffer();
94 }
95
96
97 int PluginLV2::load_lv2(const char *path, char *title)
98 {
99         if( !world ) {
100                 world = lilv_world_new();
101                 if( !world ) {
102                         printf("lv2: lilv_world_new failed\n");
103                         return 1;
104                 }
105                 lilv_world_load_all(world);
106         }
107
108         LilvNode *uri = lilv_new_uri(world, path);
109         if( !uri ) {
110                 printf("lv2: lilv_new_uri(%s) failed\n", path);
111                 return 1;
112         }
113
114         const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
115         lilv = lilv_plugins_get_by_uri(all_plugins, uri);
116         lilv_node_free(uri);
117         if( !lilv ) {
118                 printf("lv2: lilv_plugins_get_by_uri (%s) failed\n", path);
119                 return 1;
120         }
121
122         if( title ) {
123                 LilvNode *name = lilv_plugin_get_name(lilv);
124                 const char *nm = lilv_node_as_string(name);
125                 sprintf(title, "L2_%s", nm);
126                 lilv_node_free(name);
127         }
128         return 0;
129 }
130
131 int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate, int bfrsz)
132 {
133         reset_lv2();
134         double bps = 2. * sample_rate / bfrsz;
135         if( bps > refreshrate ) refreshrate = bps;
136
137         lv2_AudioPort       = lilv_new_uri(world, LV2_CORE__AudioPort);
138         lv2_ControlPort     = lilv_new_uri(world, LV2_CORE__ControlPort);
139         lv2_CVPort          = lilv_new_uri(world, LV2_CORE__CVPort);
140         lv2_InputPort       = lilv_new_uri(world, LV2_CORE__InputPort);
141         lv2_OutputPort      = lilv_new_uri(world, LV2_CORE__OutputPort);
142         lv2_Optional        = lilv_new_uri(world, LV2_CORE__connectionOptional);
143         atom_AtomPort       = lilv_new_uri(world, LV2_ATOM__AtomPort);
144         atom_Sequence       = lilv_new_uri(world, LV2_ATOM__Sequence);
145         powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
146         fixedBlockLength    = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
147         boundedBlockLength  = lilv_new_uri(world, LV2_BUF_SIZE__boundedBlockLength);
148         seq_out = (LV2_Atom_Sequence *) new char[sizeof(LV2_Atom_Sequence) + LV2_SEQ_SIZE];
149
150         conf.init_lv2(lilv, this);
151         nb_inputs = nb_outputs = 0;
152
153         for( int i=0; i<conf.nb_ports; ++i ) {
154                 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
155                 if( !lp ) continue;
156                 int is_input = lilv_port_is_a(lilv, lp, lv2_InputPort);
157                 if( !is_input && !lilv_port_is_a(lilv, lp, lv2_OutputPort) &&
158                     !lilv_port_has_property(lilv, lp, lv2_Optional) ) {
159                         printf("lv2: not input, not output, and not optional: %s\n", conf.names[i]);
160                         continue;
161                 }
162                 if( is_input && lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
163                         conf.append(new PluginLV2Client_Opt(&conf, i));
164                         continue;
165                 }
166                 if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
167                     lilv_port_is_a(lilv, lp, lv2_CVPort ) ) {
168                         if( is_input ) ++nb_inputs; else ++nb_outputs;
169                         continue;
170                 }
171         }
172
173         if( !nb_inputs || !nb_outputs ) {
174                 printf(": Unsupported lv2 plugin, missing audio input or output\n");
175                 reset_lv2();
176                 return 1;
177         }
178
179         uri_map.handle = (LV2_URID_Map_Handle)this;
180         uri_map.map = map_uri;
181         features.append(new Lv2Feature(LV2_URID__map, &uri_map));
182         uri_unmap.handle = (LV2_URID_Unmap_Handle)this;
183         uri_unmap.unmap = unmap_uri;
184         features.append(new Lv2Feature(LV2_URID__unmap, &uri_unmap));
185         features.append(new Lv2Feature(LV2_BUF_SIZE__powerOf2BlockLength, 0));
186         features.append(new Lv2Feature(LV2_BUF_SIZE__fixedBlockLength,    0));
187         features.append(new Lv2Feature(LV2_BUF_SIZE__boundedBlockLength,  0));
188         features.append(new Lv2Feature(LV2_WORKER__schedule, &schedule));
189
190         if( sample_rate < 64 ) sample_rate = samplerate;
191
192         atom_int   = uri_table.map(LV2_ATOM__Int);
193         atom_float = uri_table.map(LV2_ATOM__Float);
194         param_sampleRate = uri_table.map(LV2_PARAMETERS__sampleRate);
195         bufsz_minBlockLength =  uri_table.map(LV2_BUF_SIZE__minBlockLength);
196         bufsz_maxBlockLength = uri_table.map(LV2_BUF_SIZE__maxBlockLength);
197         bufsz_sequenceSize =  uri_table.map(LV2_BUF_SIZE__sequenceSize);
198         ui_updateRate = uri_table.map(LV2_UI__updateRate);
199
200         samplerate = sample_rate;
201         options.add(param_sampleRate, sizeof(float), atom_float, &samplerate);
202         if( min_block_length > bfrsz ) min_block_length = bfrsz;
203         options.add(bufsz_minBlockLength, sizeof(int), atom_int, &min_block_length);
204         block_length = bfrsz;
205         options.add(bufsz_maxBlockLength, sizeof(int), atom_int, &block_length);
206         options.add(bufsz_sequenceSize, sizeof(int), atom_int, &midi_buf_size);
207         options.add(ui_updateRate, sizeof(float),  atom_float, &refreshrate);
208         options.add(0, 0, 0, 0);
209
210         features.append(new Lv2Feature(LV2_OPTIONS__options,  &options[0]));
211         features.append(0);
212
213         inst = lilv_plugin_instantiate(lilv, sample_rate, features);
214         if( !inst ) {
215                 printf("lv2: lilv_plugin_instantiate failed\n");
216                 return 1;
217         }
218         
219 // After instantiate, some plugins require fields to be filled in before
220 // activate is called. This is done via ConnectPort, which connects a
221 // port to a data structure in the host (CinGG). So these have to be
222 // allocated first.
223
224         init_buffer(bfrsz);
225         connect_ports(conf, PORTS_ALL);
226         
227         const LV2_Descriptor *lilv_desc = inst->lv2_descriptor;
228         worker_iface = !lilv_desc->extension_data ? 0 :
229                 (LV2_Worker_Interface*)lilv_desc->extension_data(LV2_WORKER__interface);
230         if( worker_iface )
231                 worker_start();
232
233         lilv_instance_activate(inst);
234 // not sure what to do with these
235         max_bufsz = nb_inputs &&
236                 (lilv_plugin_has_feature(lilv, powerOf2BlockLength) ||
237                  lilv_plugin_has_feature(lilv, fixedBlockLength) ||
238                  lilv_plugin_has_feature(lilv, boundedBlockLength)) ? 4096 : 0;
239
240         return 0;
241 }
242
243 uint32_t PluginLV2::map_uri(LV2_URID_Map_Handle handle, const char *uri)
244 {
245         PluginLV2 *the = (PluginLV2 *)handle;
246         return the->uri_table.map(uri);
247 }
248
249 const char *PluginLV2::unmap_uri(LV2_URID_Unmap_Handle handle, LV2_URID urid)
250 {
251         PluginLV2 *the = (PluginLV2 *)handle;
252         return the->uri_table.unmap(urid);
253 }
254
255 void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int ports)
256 {
257         int ich = 0, och = 0;
258         for( int i=0; i<conf.nb_ports; ++i ) {
259                 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
260                 if( !lp ) continue;
261                 int port = conf.ports[i];
262                 if( !(port & ports) ) continue;
263                 if( (port & PORTS_CONTROL) ) {
264                         lilv_instance_connect_port(inst, i, &conf.ctls[i]);
265                         continue;
266                 }
267                 if( (port & PORTS_AUDIO) ) {
268                         if( (port & PORTS_INPUT) ) {
269                                 lilv_instance_connect_port(inst, i, in_buffers[ich]);
270                                 iport[ich++] = i;
271                         }
272                         else if( (port & PORTS_OUTPUT) ) {
273                                 lilv_instance_connect_port(inst, i, out_buffers[och]);
274                                 oport[och++] = i;
275                         }
276                         continue;
277                 }
278                 if( (port & PORTS_ATOM) ) {
279                         if( (port & PORTS_INPUT) )
280                                 lilv_instance_connect_port(inst, i, &seq_in);
281                         else
282                                 lilv_instance_connect_port(inst, i, seq_out);
283                         continue;
284                 }
285         }
286
287         seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body);
288         seq_in[0].atom.type = uri_table.map(LV2_ATOM__Sequence);
289         seq_in[1].atom.size = 0;
290         seq_in[1].atom.type = 0;
291         seq_out->atom.size  = LV2_SEQ_SIZE;
292         seq_out->atom.type  = uri_table.map(LV2_ATOM__Chunk);
293 }
294
295 void PluginLV2::del_buffer()
296 {
297         if( shmid >= 0 )
298                 shm_buffer(-1);
299
300         delete [] in_buffers;  in_buffers = 0;
301         delete [] out_buffers;  out_buffers = 0;
302 }
303
304 void PluginLV2::new_buffer(int64_t sz)
305 {
306         uint8_t *bp = 0;
307         if( use_shm ) {  // currently, always uses shm
308                 shmid = shmget(IPC_PRIVATE, sz, IPC_CREAT | 0777);
309                 if( shmid >= 0 ) {
310                         bp = (unsigned char*)shmat(shmid, NULL, 0);
311                         if( bp == (void *) -1 ) { perror("shmat"); bp = 0; }
312                         shmctl(shmid, IPC_RMID, 0); // delete when last ref gone
313                 }
314                 else {
315                         perror("PluginLV2::allocate_buffer: shmget failed\n");
316                         BC_Trace::dump_shm_stats(stdout);
317                 }
318         }
319
320         shm_bfr = (shm_bfr_t *) bp;
321         if( shm_bfr ) shm_bfr->sz = sz;
322 }
323
324 shm_bfr_t *PluginLV2::shm_buffer(int shmid)
325 {
326         if( this->shmid != shmid ) {
327                 if( this->shmid >= 0 ) {
328                         shmdt(shm_bfr);  this->shmid = -1;
329                         shm_bfr = 0;
330                 }
331                 if( shmid >= 0 ) {
332                         shm_bfr = (shm_bfr_t *)shmat(shmid, NULL, 0);
333                         if( shm_bfr == (void *)-1 ) { perror("shmat");  shm_bfr = 0; }
334                         this->shmid = shm_bfr ? shmid : -1;
335                 }
336         }
337         return shm_bfr;
338 }
339
340 void PluginLV2::init_buffer(int samples)
341 {
342         int64_t sz = sizeof(shm_bfr_t) +
343                 sizeof(iport[0])*nb_inputs + sizeof(oport[0])*nb_outputs +
344                 sizeof(*in_buffers[0]) *samples * nb_inputs +
345                 sizeof(*out_buffers[0])*samples * nb_outputs;
346
347         if( shm_bfr ) {
348                 if( shm_bfr->sz < sz ||
349                     shm_bfr->nb_inputs != nb_inputs ||
350                     shm_bfr->nb_outputs != nb_outputs )
351                         del_buffer();
352         }
353
354         if( !shm_bfr )
355                 new_buffer(sz);
356
357         shm_bfr->samples = samples;
358         shm_bfr->done = 0;
359         shm_bfr->nb_inputs = nb_inputs;
360         shm_bfr->nb_outputs = nb_outputs;
361
362         map_buffer();
363 }
364
365 // shm_bfr layout:
366 // struct shm_bfr {
367 //   int64_t sz;
368 //   int samples, done;
369 //   int nb_inputs, nb_outputs;
370 //   int iport[nb_inputs], 
371 //   float in_buffers[samples][nb_inputs];
372 //   int oport[nb_outputs];
373 //   float out_buffers[samples][nb_outputs];
374 // };
375
376 void PluginLV2::map_buffer()
377 {
378         uint8_t *bp = (uint8_t *)(shm_bfr + 1);
379
380         nb_inputs = shm_bfr->nb_inputs;
381         iport = (int *)bp;
382         bp += sizeof(iport[0])*nb_inputs;
383         in_buffers = new float*[nb_inputs];
384         int samples = shm_bfr->samples;
385         for(int i=0; i<nb_inputs; ++i ) {
386                 in_buffers[i] = (float *)bp;
387                 bp += sizeof(*in_buffers[0])*samples;
388         }
389
390         nb_outputs = shm_bfr->nb_outputs;
391         oport = (int *)bp;
392         bp += sizeof(oport[0])*nb_outputs;
393         out_buffers = new float*[nb_outputs];
394         for( int i=0; i<nb_outputs; ++i ) {
395                 out_buffers[i] = (float *)bp;
396                 bp += sizeof(*out_buffers[0])*samples;
397         }
398 }
399
400
401 // LV2 Worker
402
403 PluginLV2Work::PluginLV2Work()
404 {
405         next = 0;
406         alloc = used = 0;
407         data = 0;
408 }
409
410 PluginLV2Work::~PluginLV2Work()
411 {
412         delete [] data;
413 }
414
415 void PluginLV2Work::load(const void *vp, unsigned size)
416 {
417         if( alloc < size ) {
418                 delete [] data;
419                 data = new char[alloc=size];
420         }
421         memcpy(data, vp, used=size);
422 }
423
424 PluginLV2Work *PluginLV2::get_work()
425 {
426 // must hold worker_lock
427         if( !work_avail ) return new PluginLV2Work();
428         PluginLV2Work *wp = work_avail;
429         work_avail = wp->next;  wp->next = 0;
430         return wp;
431 }
432
433 void *PluginLV2::worker_func()
434 {
435         pthread_mutex_lock(&worker_lock);
436         pthread_mutex_unlock(&startup_lock);
437         for(;;) {
438                 while( !worker_done && !work_input )
439                         pthread_cond_wait(&worker_ready, &worker_lock);
440                 if( worker_done ) break;
441                 PluginLV2Work *wp = work_input;  work_input = wp->next;
442
443                 pthread_mutex_unlock(&worker_lock);
444                 worker_iface->work(inst, lv2_worker_respond, this, wp->used, wp->data);
445                 pthread_mutex_lock(&worker_lock);
446                 wp->next = work_avail;  work_avail = wp;
447         }
448         pthread_mutex_unlock(&worker_lock);
449         return NULL;
450 }
451 void *PluginLV2::worker_func(void* vp)
452 {
453         PluginLV2 *the = (PluginLV2 *)vp;
454         return the->worker_func();
455 }
456
457 void PluginLV2::worker_start()
458 {
459         pthread_create(&worker_thread, 0, worker_func, this);
460         pthread_mutex_lock(&startup_lock);
461 }
462
463 void PluginLV2::worker_stop()
464 {
465         if( !worker_done ) {
466                 worker_done = 1;
467                 pthread_mutex_lock(&worker_lock);
468                 pthread_cond_signal(&worker_ready);
469                 pthread_mutex_unlock(&worker_lock);
470                 pthread_join(worker_thread, 0);
471                 worker_thread = 0;
472         }
473         work_stop(work_avail);
474         work_stop(work_input);
475         work_stop(work_output);
476         work_tail = &work_output;
477 }
478
479 void PluginLV2::work_stop(PluginLV2Work *&work)
480 {
481         while( work ) {
482                 PluginLV2Work *wp = work;
483                 work = wp->next;
484                 delete wp;
485         }
486 }
487
488 LV2_Worker_Status PluginLV2::worker_schedule(uint32_t inp_size, const void *inp_data)
489 {
490         if( is_forked() ) {
491                 if( !pthread_mutex_trylock(&worker_lock) ) {
492                         PluginLV2Work *wp = get_work();
493                         wp->load(inp_data, inp_size);
494                         wp->next = work_input;  work_input = wp;
495                         pthread_cond_signal(&worker_ready);
496                         pthread_mutex_unlock(&worker_lock);
497                 }
498         }
499         else if( worker_iface )
500                 worker_iface->work(inst, lv2_worker_respond, this, inp_size, inp_data);
501         return LV2_WORKER_SUCCESS;
502 }
503 LV2_Worker_Status PluginLV2::lv2_worker_schedule(LV2_Worker_Schedule_Handle vp,
504                     uint32_t inp_size, const void *inp_data)
505 {
506         PluginLV2 *the = (PluginLV2 *)vp;
507         return the->worker_schedule(inp_size, inp_data);
508 }
509
510 LV2_Worker_Status PluginLV2::worker_respond(uint32_t out_size, const void *out_data)
511 {
512         pthread_mutex_lock(&worker_lock);
513         PluginLV2Work *wp = get_work();
514         wp->load(out_data, out_size);
515         *work_tail = wp;  work_tail = &wp->next;
516         pthread_mutex_unlock(&worker_lock);
517         return LV2_WORKER_SUCCESS;
518 }
519 LV2_Worker_Status PluginLV2::lv2_worker_respond(LV2_Worker_Respond_Handle vp,
520                 uint32_t out_size, const void *out_data)
521 {
522         PluginLV2 *the = (PluginLV2 *)vp;
523         return the->worker_respond(out_size, out_data);
524 }
525
526 void PluginLV2::worker_responses()
527 {
528         pthread_mutex_lock(&worker_lock);
529         while( work_output ) {
530                 PluginLV2Work *rp = work_output;
531                 if( !(work_output=rp->next) ) work_tail = &work_output;
532                 pthread_mutex_unlock(&worker_lock);
533                 worker_iface->work_response(inst, rp->used, rp->data);
534                 pthread_mutex_lock(&worker_lock);
535                 rp->next = work_avail;  work_avail = rp;
536         }
537         pthread_mutex_unlock(&worker_lock);
538 }
539
540 #include "file.h"
541 #include "pluginlv2ui.h"
542
543 PluginLV2ChildUI::PluginLV2ChildUI()
544 {
545         ac = 0;
546         av = 0;
547         gui = 0;
548         hidden = 1;
549 }
550
551 PluginLV2ChildUI::~PluginLV2ChildUI()
552 {
553         delete gui;
554 }
555
556 void PluginLV2ChildUI::run()
557 {
558         ArrayList<char *> av;
559         av.set_array_delete();
560         char arg[BCTEXTLEN];
561         const char *exec_path = File::get_cinlib_path();
562         snprintf(arg, sizeof(arg), "%s/%s", exec_path, "lv2ui");
563         av.append(cstrdup(arg));
564         sprintf(arg, "%d", child_fd);
565         av.append(cstrdup(arg));
566         sprintf(arg, "%d", parent_fd);
567         av.append(cstrdup(arg));
568         sprintf(arg, "%d", ppid);
569         av.append(cstrdup(arg));
570         av.append(0);
571         execv(av[0], &av.values[0]);
572         fprintf(stderr, "execv failed: %s\n %m\n", av.values[0]);
573         av.remove_all_objects();
574         _exit(1);
575 }
576
577 #define LV2_EXTERNAL_UI_URI__KX__Widget "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget"
578
579 PluginLV2UI::PluginLV2UI()
580 {
581         lilv_ui = 0;
582         lilv_type = 0;
583
584         done = -1;
585         running = 0;
586         updates = 0;
587         hidden = 1;
588         title[0] = 0;
589
590         memset(&uri_map, 0, sizeof(uri_map));
591         memset(&uri_unmap, 0, sizeof(uri_unmap));
592         memset(&extui_host, 0, sizeof(extui_host));
593         wgt_type = LV2_EXTERNAL_UI_URI__KX__Widget;
594         gtk_type = LV2_UI__GtkUI;
595         ui_type = 0;
596 }
597
598 PluginLV2UI::~PluginLV2UI ()
599 {
600 }
601
602 #endif