1ea3bffb9554fbc830a9ccbabbd872aff5d850fb
[goodguy/history.git] / cinelerra-5.1 / cinelerra / pluginlv2client.C
1 #ifdef HAVE_LV2
2
3 /*
4  * CINELERRA
5  * Copyright (C) 2018 GG
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include "clip.h"
24 #include "cstrdup.h"
25 #include "bchash.h"
26 #include "filexml.h"
27 #include "language.h"
28 #include "mwindow.h"
29 #include "pluginlv2client.h"
30 #include "pluginserver.h"
31 #include "samples.h"
32
33 #include <ctype.h>
34 #include <string.h>
35
36 #define LV2_SEQ_SIZE  9624
37
38 PluginLV2UriTable::PluginLV2UriTable()
39 {
40         set_array_delete();
41 }
42
43 PluginLV2UriTable::~PluginLV2UriTable()
44 {
45         remove_all_objects();
46 }
47
48 LV2_URID PluginLV2UriTable::map(const char *uri)
49 {
50         for( int i=0; i<size(); ++i )
51                 if( !strcmp(uri, get(i)) ) return i+1;
52         append(cstrdup(uri));
53         return size();
54 }
55
56 const char *PluginLV2UriTable::unmap(LV2_URID urid)
57 {
58         int idx = urid - 1;
59         return idx>=0 && idx<size() ? get(idx) : 0;
60 }
61
62 PluginLV2Client_OptName:: PluginLV2Client_OptName(PluginLV2Client_Opt *opt)
63 {
64         this->opt = opt;
65         set_text(opt->get_name());
66 }
67
68 PluginLV2Client_OptValue::PluginLV2Client_OptValue(PluginLV2Client_Opt *opt)
69 {
70         this->opt = opt;
71         update();
72 }
73
74 int PluginLV2Client_OptValue::update()
75 {
76         char val[BCSTRLEN];
77         sprintf(val, "%f", opt->get_value());
78         if( !strcmp(val, get_text()) ) return 0;
79         set_text(val);
80         return 1;
81 }
82
83
84 PluginLV2Client_Opt::PluginLV2Client_Opt(PluginLV2ClientConfig *conf, const char *sym, int idx)
85 {
86         this->conf = conf;
87         this->idx = idx;
88         this->sym = cstrdup(sym);
89         item_name = new PluginLV2Client_OptName(this);
90         item_value = new PluginLV2Client_OptValue(this);
91 }
92
93 PluginLV2Client_Opt::~PluginLV2Client_Opt()
94 {
95         delete [] sym;
96         delete item_name;
97         delete item_value;
98 }
99
100 float PluginLV2Client_Opt::get_value()
101 {
102         return conf->ctls[idx];
103 }
104
105 void PluginLV2Client_Opt::set_value(float v)
106 {
107         conf->ctls[idx] = v;
108 }
109
110 int PluginLV2Client_Opt::update(float v)
111 {
112         set_value(v);
113         return item_value->update();
114 }
115
116 const char *PluginLV2Client_Opt::get_name()
117 {
118         return conf->names[idx];
119 }
120
121 PluginLV2ClientConfig::PluginLV2ClientConfig()
122 {
123         names = 0;
124         mins = 0;
125         maxs = 0;
126         ctls = 0;
127         nb_ports = 0;
128 }
129
130 PluginLV2ClientConfig::~PluginLV2ClientConfig()
131 {
132         reset();
133         remove_all_objects();
134 }
135
136 void PluginLV2ClientConfig::reset()
137 {
138         for( int i=0; i<nb_ports; ++i ) delete [] names[i];
139         delete [] names; names = 0;
140         delete [] mins;  mins = 0;
141         delete [] maxs;  maxs = 0;
142         delete [] ctls;  ctls = 0;
143         nb_ports = 0;
144 }
145
146
147 int PluginLV2ClientConfig::equivalent(PluginLV2ClientConfig &that)
148 {
149         PluginLV2ClientConfig &conf = *this;
150         for( int i=0; i<that.size(); ++i ) {
151                 PluginLV2Client_Opt *topt = conf[i], *vopt = that[i];
152                 if( !EQUIV(topt->get_value(), vopt->get_value()) ) return 0;
153         }
154         return 1;
155 }
156
157 void PluginLV2ClientConfig::copy_from(PluginLV2ClientConfig &that)
158 {
159         if( nb_ports != that.nb_ports ) {
160                 reset();
161                 nb_ports = that.nb_ports;
162                 names = new const char *[nb_ports];
163                 for( int i=0; i<nb_ports; ++i ) names[i] = 0;
164                 mins  = new float[nb_ports];
165                 maxs  = new float[nb_ports];
166                 ctls  = new float[nb_ports];
167         }
168         for( int i=0; i<nb_ports; ++i ) {
169                 delete [] names[i];
170                 names[i] = cstrdup(that.names[i]);
171                 mins[i] = that.mins[i];
172                 maxs[i] = that.maxs[i];
173                 ctls[i] = that.ctls[i];
174         }
175         remove_all_objects();
176         for( int i=0; i<that.size(); ++i ) {
177                 append(new PluginLV2Client_Opt(this, that[i]->sym, that[i]->idx));
178         }
179 }
180
181 void PluginLV2ClientConfig::interpolate(PluginLV2ClientConfig &prev, PluginLV2ClientConfig &next,
182         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
183 {
184         copy_from(prev);
185 }
186
187 void PluginLV2ClientConfig::init_lv2(const LilvPlugin *lilv)
188 {
189         reset();
190         nb_ports = lilv_plugin_get_num_ports(lilv);
191         names = new const char *[nb_ports];
192         mins  = new float[nb_ports];
193         maxs  = new float[nb_ports];
194         ctls  = new float[nb_ports];
195         lilv_plugin_get_port_ranges_float(lilv, mins, maxs, ctls);
196         for( int i=0; i<nb_ports; ++i ) {
197                 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
198                 LilvNode *pnm = lilv_port_get_name(lilv, lp);
199                 names[i] = cstrdup(lilv_node_as_string(pnm));
200                 lilv_node_free(pnm);
201         }
202 }
203
204 int PluginLV2ClientConfig::update()
205 {
206         int ret = 0;
207         PluginLV2ClientConfig &conf = *this;
208         for( int i=0; i<size(); ++i ) {
209                 if( conf[i]->item_value->update() ) ++ret;
210         }
211         return ret;
212 }
213
214 PluginLV2ClientReset::
215 PluginLV2ClientReset(PluginLV2ClientWindow *gui, int x, int y)
216  : BC_GenericButton(x, y, _("Reset"))
217 {
218         this->gui = gui;
219 }
220
221 PluginLV2ClientReset::
222 ~PluginLV2ClientReset()
223 {
224 }
225
226 int PluginLV2ClientReset::handle_event()
227 {
228         PluginLV2Client *plugin = gui->plugin;
229         plugin->init_lv2();
230         gui->selected = 0;
231         gui->update_selected();
232         gui->panel->update();
233         plugin->send_configure_change();
234         return 1;
235 }
236
237 PluginLV2ClientText::
238 PluginLV2ClientText(PluginLV2ClientWindow *gui, int x, int y, int w)
239  : BC_TextBox(x, y, w, 1, (char *)"")
240 {
241         this->gui = gui;
242 }
243
244 PluginLV2ClientText::
245 ~PluginLV2ClientText()
246 {
247 }
248
249 int PluginLV2ClientText::handle_event()
250 {
251         return 0;
252 }
253
254
255 PluginLV2ClientApply::
256 PluginLV2ClientApply(PluginLV2ClientWindow *gui, int x, int y)
257  : BC_GenericButton(x, y, _("Apply"))
258 {
259         this->gui = gui;
260 }
261
262 PluginLV2ClientApply::
263 ~PluginLV2ClientApply()
264 {
265 }
266
267 int PluginLV2ClientApply::handle_event()
268 {
269         const char *text = gui->text->get_text();
270         if( text && gui->selected ) {
271                 gui->selected->update(atof(text));
272                 gui->update_selected();
273                 gui->plugin->send_configure_change();
274         }
275         return 1;
276 }
277
278
279 PluginLV2Client_OptPanel::
280 PluginLV2Client_OptPanel(PluginLV2ClientWindow *gui, int x, int y, int w, int h)
281  : BC_ListBox(x, y, w, h, LISTBOX_TEXT), opts(items[0]), vals(items[1])
282 {
283         this->gui = gui;
284         update();  // init col/wid/columns
285 }
286
287 PluginLV2Client_OptPanel::
288 ~PluginLV2Client_OptPanel()
289 {
290 }
291
292 int PluginLV2Client_OptPanel::selection_changed()
293 {
294         PluginLV2Client_Opt *opt = 0;
295         BC_ListBoxItem *item = get_selection(0, 0);
296         if( item ) {
297                 PluginLV2Client_OptName *opt_name = (PluginLV2Client_OptName *)item;
298                 opt = opt_name->opt;
299         }
300         gui->update(opt);
301         return 1;
302 }
303
304 void PluginLV2Client_OptPanel::update()
305 {
306         opts.remove_all();
307         vals.remove_all();
308         PluginLV2ClientConfig &conf = gui->plugin->config;
309         for( int i=0; i<conf.size(); ++i ) {
310                 PluginLV2Client_Opt *opt = conf[i];
311                 opts.append(opt->item_name);
312                 vals.append(opt->item_value);
313         }
314         const char *cols[] = { "option", "value", };
315         const int col1_w = 150;
316         int wids[] = { col1_w, get_w()-col1_w };
317         BC_ListBox::update(&items[0], &cols[0], &wids[0], sizeof(items)/sizeof(items[0]));
318 }
319
320 PluginLV2ClientWindow::PluginLV2ClientWindow(PluginLV2Client *plugin)
321  : PluginClientWindow(plugin, 500, 300, 500, 300, 1)
322 {
323         this->plugin = plugin;
324         selected = 0;
325 }
326
327 PluginLV2ClientWindow::~PluginLV2ClientWindow()
328 {
329 }
330
331
332 void PluginLV2ClientWindow::create_objects()
333 {
334         BC_Title *title;
335         int x = 10, y = 10;
336         add_subwindow(title = new BC_Title(x, y, plugin->title));
337         y += title->get_h() + 10;
338         add_subwindow(varbl = new BC_Title(x, y, ""));
339         add_subwindow(range = new BC_Title(x+160, y, ""));
340         int x1 = get_w() - BC_GenericButton::calculate_w(this, _("Reset")) - 8;
341         add_subwindow(reset = new PluginLV2ClientReset(this, x1, y));
342         y += title->get_h() + 10;
343         x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - 8;
344         add_subwindow(apply = new PluginLV2ClientApply(this, x1, y));
345         add_subwindow(text = new PluginLV2ClientText(this, x, y, x1-x - 8));
346         y += title->get_h() + 10;
347         add_subwindow(pot = new PluginLV2ClientPot(this, x, y));
348         x1 = x + pot->get_w() + 10;
349         add_subwindow(slider = new PluginLV2ClientSlider(this, x1, y+10));
350         y += pot->get_h() + 10;
351
352         plugin->init_lv2();
353
354         int panel_x = x, panel_y = y;
355         int panel_w = get_w()-10 - panel_x;
356         int panel_h = get_h()-10 - panel_y;
357         panel = new PluginLV2Client_OptPanel(this, panel_x, panel_y, panel_w, panel_h);
358         add_subwindow(panel);
359         panel->update();
360         show_window(1);
361 }
362
363 int PluginLV2ClientWindow::resize_event(int w, int h)
364 {
365         int x1 = w - reset->get_w() - 8;
366         reset->reposition_window(x1, reset->get_y());
367         x1 = w - apply->get_w() - 8;
368         apply->reposition_window(x1, apply->get_y());
369         text->reposition_window(text->get_x(), text->get_y(), x1-text->get_x() - 8);
370         x1 = pot->get_x() + pot->get_w() + 10;
371         int w1 = w - slider->get_x() - 20;
372         slider->set_pointer_motion_range(w1);
373         slider->reposition_window(x1, slider->get_y(), w1, slider->get_h());
374         int panel_x = panel->get_x(), panel_y = panel->get_y();
375         panel->reposition_window(panel_x, panel_y, w-10-panel_x, h-10-panel_y);
376         return 1;
377 }
378
379 PluginLV2ClientPot::PluginLV2ClientPot(PluginLV2ClientWindow *gui, int x, int y)
380  : BC_FPot(x, y, 0.f, 0.f, 0.f)
381 {
382         this->gui = gui;
383 }
384
385 int PluginLV2ClientPot::handle_event()
386 {
387         if( gui->selected ) {
388                 gui->selected->update(get_value());
389                 gui->update_selected();
390                 gui->plugin->send_configure_change();
391         }
392         return 1;
393 }
394
395 PluginLV2ClientSlider::PluginLV2ClientSlider(PluginLV2ClientWindow *gui, int x, int y)
396  : BC_FSlider(x, y, 0, gui->get_w()-x-20, gui->get_w()-x-20, 0.f, 0.f, 0.f)
397 {
398         this->gui = gui;
399 }
400
401 int PluginLV2ClientSlider::handle_event()
402 {
403         if( gui->selected ) {
404                 gui->selected->update(get_value());
405                 gui->update_selected();
406                 gui->plugin->send_configure_change();
407         }
408         return 1;
409 }
410
411 void PluginLV2ClientWindow::update_selected()
412 {
413         update(selected);
414 }
415
416 int PluginLV2ClientWindow::scalar(float f, char *rp)
417 {
418         const char *cp = 0;
419              if( f == FLT_MAX ) cp = "FLT_MAX";
420         else if( f == FLT_MIN ) cp = "FLT_MIN";
421         else if( f == -FLT_MAX ) cp = "-FLT_MAX";
422         else if( f == -FLT_MIN ) cp = "-FLT_MIN";
423         else if( f == 0 ) cp = signbit(f) ? "-0" : "0";
424         else if( isnan(f) ) cp = signbit(f) ? "-NAN" : "NAN";
425         else if( isinf(f) ) cp = signbit(f) ? "-INF" : "INF";
426         else return sprintf(rp, "%g", f);
427         return sprintf(rp, "%s", cp);
428 }
429
430 void PluginLV2ClientWindow::update(PluginLV2Client_Opt *opt)
431 {
432         if( selected != opt ) {
433                 if( selected ) selected->item_name->set_selected(0);
434                 selected = opt;
435                 if( selected ) selected->item_name->set_selected(1);
436         }
437         char var[BCSTRLEN];  var[0] = 0;
438         char val[BCSTRLEN];  val[0] = 0;
439         char rng[BCTEXTLEN]; rng[0] = 0;
440         if( opt ) {
441                 sprintf(var,"%s:", opt->conf->names[opt->idx]);
442                 char *cp = rng;
443                 cp += sprintf(cp,"( ");
444                 float min = opt->conf->mins[opt->idx];
445                 cp += scalar(min, cp);
446                 cp += sprintf(cp, " .. ");
447                 float max = opt->conf->maxs[opt->idx];
448                 cp += scalar(max, cp);
449                 cp += sprintf(cp, " )");
450                 float v = opt->get_value();
451                 sprintf(val, "%f", v);
452                 slider->update(slider->get_w(), v, min, max);
453                 pot->update(v, min, max);
454         }
455         else {
456                 slider->update(slider->get_w(), 0.f, 0.f, 0.f);
457                 pot->update(0.f, 0.f, 0.f);
458         }
459         varbl->update(var);
460         range->update(rng);
461         text->update(val);
462         panel->update();
463 }
464
465
466 PluginLV2Client::PluginLV2Client(PluginServer *server)
467  : PluginAClient(server)
468 {
469         in_buffers = 0;
470         out_buffers = 0;
471         nb_in_bfrs = 0;
472         nb_out_bfrs = 0;
473         bfrsz = 0;
474         nb_inputs = 0;
475         nb_outputs = 0;
476         max_bufsz = 0;
477
478         world = 0;
479         instance = 0;
480         lv2_InputPort = 0;
481         lv2_OutputPort = 0;
482         lv2_AudioPort = 0;
483         lv2_CVPort = 0;
484         lv2_ControlPort = 0;
485         lv2_Optional = 0;
486         atom_AtomPort = 0;
487         atom_Sequence = 0;
488         urid_map = 0;
489         powerOf2BlockLength = 0;
490         fixedBlockLength = 0;
491         boundedBlockLength = 0;
492         seq_out = 0;
493 }
494
495 PluginLV2Client::~PluginLV2Client()
496 {
497         reset_lv2();
498         lilv_world_free(world);
499 }
500
501 void PluginLV2Client::reset_lv2()
502 {
503         if( instance ) lilv_instance_deactivate(instance);
504         lilv_instance_free(instance);         instance = 0;
505         lilv_node_free(powerOf2BlockLength);  powerOf2BlockLength = 0;
506         lilv_node_free(fixedBlockLength);     fixedBlockLength = 0;
507         lilv_node_free(boundedBlockLength);   boundedBlockLength = 0;
508         lilv_node_free(urid_map);             urid_map = 0;
509         lilv_node_free(atom_Sequence);        atom_Sequence = 0;
510         lilv_node_free(atom_AtomPort);        atom_AtomPort = 0;
511         lilv_node_free(lv2_Optional);         lv2_Optional = 0;
512         lilv_node_free(lv2_ControlPort);      lv2_ControlPort = 0;
513         lilv_node_free(lv2_AudioPort);        lv2_AudioPort = 0;
514         lilv_node_free(lv2_CVPort);           lv2_CVPort = 0;
515         lilv_node_free(lv2_OutputPort);       lv2_OutputPort = 0;
516         lilv_node_free(lv2_InputPort);        lv2_InputPort = 0;
517         delete [] (char *)seq_out;            seq_out = 0;
518         uri_table.remove_all_objects();
519         delete_buffers();
520         nb_inputs = 0;
521         nb_outputs = 0;
522         max_bufsz = 0;
523         config.reset();
524         config.remove_all_objects();
525 }
526
527 int PluginLV2Client::load_lv2(const char *path)
528 {
529         if( !world ) {
530                 world = lilv_world_new();
531                 if( !world ) {
532                         printf("lv2: lilv_world_new failed");
533                         return 1;
534                 }
535                 lilv_world_load_all(world);
536         }
537
538         LilvNode *uri = lilv_new_uri(world, path);
539         if( !uri ) {
540                 printf("lv2: lilv_new_uri(%s) failed", path);
541                 return 1;
542         }
543
544         const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
545         lilv = lilv_plugins_get_by_uri(all_plugins, uri);
546         lilv_node_free(uri);
547         if( !lilv ) {
548                 printf("lv2: lilv_plugins_get_by_uriPlugin(%s) failed", path);
549                 return 1;
550         }
551
552         LilvNode *name = lilv_plugin_get_name(lilv);
553         const char *nm = lilv_node_as_string(name);
554         snprintf(title,sizeof(title),"L2_%s",nm);
555         lilv_node_free(name);
556         return 0;
557 }
558
559 int PluginLV2Client::init_lv2()
560 {
561         reset_lv2();
562
563         lv2_InputPort       = lilv_new_uri(world, LV2_CORE__InputPort);
564         lv2_OutputPort      = lilv_new_uri(world, LV2_CORE__OutputPort);
565         lv2_AudioPort       = lilv_new_uri(world, LV2_CORE__AudioPort);
566         lv2_ControlPort     = lilv_new_uri(world, LV2_CORE__ControlPort);
567         lv2_CVPort          = lilv_new_uri(world, LV2_CORE__CVPort);
568         lv2_Optional        = lilv_new_uri(world, LV2_CORE__connectionOptional);
569         atom_AtomPort       = lilv_new_uri(world, LV2_ATOM__AtomPort);
570         atom_Sequence       = lilv_new_uri(world, LV2_ATOM__Sequence);
571         urid_map            = lilv_new_uri(world, LV2_URID__map);
572         powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
573         fixedBlockLength    = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
574         boundedBlockLength  = lilv_new_uri(world, LV2_BUF_SIZE__boundedBlockLength);
575         seq_out = (LV2_Atom_Sequence *) new char[sizeof(LV2_Atom_Sequence) + LV2_SEQ_SIZE];
576
577         config.init_lv2(lilv);
578         nb_inputs = nb_outputs = 0;
579
580         for( int i=0; i<config.nb_ports; ++i ) {
581                 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
582                 int is_input = lilv_port_is_a(lilv, lp, lv2_InputPort);
583                 if( !is_input && !lilv_port_is_a(lilv, lp, lv2_OutputPort) &&
584                     !lilv_port_has_property(lilv, lp, lv2_Optional) ) {
585                         printf("lv2: not input, not output, and not optional: %s\n", config.names[i]);
586                         continue;
587                 }
588                 if( is_input && lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
589                         const char *sym = lilv_node_as_string(lilv_port_get_symbol(lilv, lp));
590                         config.append(new PluginLV2Client_Opt(&config, sym, i));
591                         continue;
592                 }
593                 if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
594                     lilv_port_is_a(lilv, lp, lv2_CVPort ) ) {
595                         if( is_input ) ++nb_inputs; else ++nb_outputs;
596                         continue;
597                 }
598         }
599
600         map.handle = (void*)&uri_table;
601         map.map = uri_table_map;
602         map_feature.URI = LV2_URID_MAP_URI;
603         map_feature.data = &map;
604         unmap.handle = (void*)&uri_table;
605         unmap.unmap  = uri_table_unmap;
606         unmap_feature.URI = LV2_URID_UNMAP_URI;
607         unmap_feature.data = &unmap;
608         features[0] = &map_feature;
609         features[1] = &unmap_feature;
610         static const LV2_Feature buf_size_features[3] = {
611                 { LV2_BUF_SIZE__powerOf2BlockLength, NULL },
612                 { LV2_BUF_SIZE__fixedBlockLength,    NULL },
613                 { LV2_BUF_SIZE__boundedBlockLength,  NULL },
614         };
615         features[2] = &buf_size_features[0];
616         features[3] = &buf_size_features[1];
617         features[4] = &buf_size_features[2];
618         features[5] = 0;
619
620         instance = lilv_plugin_instantiate(lilv, sample_rate, features);
621         if( !instance ) {
622                 printf("lv2: lilv_plugin_instantiate failed: %s\n", server->title);
623                 return 1;
624         }
625         lilv_instance_activate(instance);
626 // not sure what to do with these
627         max_bufsz = nb_inputs &&
628                 (lilv_plugin_has_feature(lilv, powerOf2BlockLength) ||
629                  lilv_plugin_has_feature(lilv, fixedBlockLength) ||
630                  lilv_plugin_has_feature(lilv, boundedBlockLength)) ? 4096 : 0;
631         return 0;
632 }
633
634 LV2_URID PluginLV2Client::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
635 {
636         return ((PluginLV2UriTable *)handle)->map(uri);
637 }
638
639 const char *PluginLV2Client::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
640 {
641         return ((PluginLV2UriTable *)handle)->unmap(urid);
642 }
643
644 NEW_WINDOW_MACRO(PluginLV2Client, PluginLV2ClientWindow)
645
646 int PluginLV2Client::load_configuration()
647 {
648         int64_t src_position =  get_source_position();
649         KeyFrame *prev_keyframe = get_prev_keyframe(src_position);
650         PluginLV2ClientConfig curr_config;
651         curr_config.copy_from(config);
652         read_data(prev_keyframe);
653         int ret = !config.equivalent(curr_config) ? 1 : 0;
654         return ret;
655 }
656
657 void PluginLV2Client::update_gui()
658 {
659         PluginClientThread *thread = get_thread();
660         if( !thread ) return;
661         PluginLV2ClientWindow *window = (PluginLV2ClientWindow*)thread->get_window();
662         window->lock_window("PluginFClient::update_gui");
663         load_configuration();
664         if( config.update() > 0 )
665                 window->update_selected();
666         window->unlock_window();
667 }
668
669 int PluginLV2Client::is_realtime() { return 1; }
670 int PluginLV2Client::is_multichannel() { return nb_inputs > 1 || nb_outputs > 1 ? 1 : 0; }
671 const char* PluginLV2Client::plugin_title() { return title; }
672 int PluginLV2Client::uses_gui() { return 1; }
673 int PluginLV2Client::is_synthesis() { return 1; }
674
675 char* PluginLV2Client::to_string(char *string, const char *input)
676 {
677         char *bp = string;
678         for( const char *cp=input; *cp; ++cp )
679                 *bp++ = isalnum(*cp) ? *cp : '_';
680         *bp = 0;
681         return string;
682 }
683
684 void PluginLV2Client::save_data(KeyFrame *keyframe)
685 {
686         FileXML output;
687         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
688         char name[BCTEXTLEN];  to_string(name, plugin_title());
689         output.tag.set_title(name);
690         for( int i=0; i<config.size(); ++i ) {
691                 PluginLV2Client_Opt *opt = config[i];
692                 output.tag.set_property(opt->sym, opt->get_value());
693         }
694         output.append_tag();
695         output.terminate_string();
696 }
697
698 void PluginLV2Client::read_data(KeyFrame *keyframe)
699 {
700         FileXML input;
701         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
702         char name[BCTEXTLEN];  to_string(name, plugin_title());
703
704         while( !input.read_tag() ) {
705                 if( !input.tag.title_is(name) ) continue;
706                 for( int i=0; i<config.size(); ++i ) {
707                         PluginLV2Client_Opt *opt = config[i];
708                         float value = input.tag.get_property(opt->sym, 0.);
709                         opt->set_value(value);
710                 }
711         }
712 }
713
714 void PluginLV2Client::connect_ports()
715 {
716         int ich = 0, och = 0;
717         for( int i=0; i<config.nb_ports; ++i ) {
718                 const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
719                 if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
720                     lilv_port_is_a(lilv, lp, lv2_CVPort) ) {
721                         if( lilv_port_is_a(lilv, lp, lv2_InputPort) )
722                                 lilv_instance_connect_port(instance, i, in_buffers[ich++]);
723                         else if( lilv_port_is_a(lilv, lp, lv2_OutputPort))
724                                 lilv_instance_connect_port(instance, i, out_buffers[och++]);
725                         continue;
726                 }
727                 if( lilv_port_is_a(lilv, lp, atom_AtomPort) ) {
728                         if( lilv_port_is_a(lilv, lp, lv2_InputPort) )
729                                 lilv_instance_connect_port(instance, i, &seq_in);
730                         else
731                                 lilv_instance_connect_port(instance, i, seq_out);
732                         continue;
733                 }
734                 if( lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
735                         lilv_instance_connect_port(instance, i, &config.ctls[i]);
736                         continue;
737                 }
738         }
739
740         seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body);
741         seq_in[0].atom.type = uri_table.map(LV2_ATOM__Sequence);
742         seq_in[1].atom.size = 0;
743         seq_in[1].atom.type = 0;
744         seq_out->atom.size  = LV2_SEQ_SIZE;
745         seq_out->atom.type  = uri_table.map(LV2_ATOM__Chunk);
746 }
747
748 void PluginLV2Client::init_plugin(int size)
749 {
750         if( !instance )
751                 init_lv2();
752
753         load_configuration();
754
755         if( bfrsz < size )
756                 delete_buffers();
757
758         bfrsz = MAX(size, bfrsz);
759         if( !in_buffers ) {
760                 in_buffers = new float*[nb_in_bfrs=nb_inputs];
761                 for(int i=0; i<nb_in_bfrs; ++i )
762                         in_buffers[i] = new float[bfrsz];
763         }
764         if( !out_buffers ) {
765                 out_buffers = new float*[nb_out_bfrs=nb_outputs];
766                 for( int i=0; i<nb_out_bfrs; ++i )
767                         out_buffers[i] = new float[bfrsz];
768         }
769 }
770
771 void PluginLV2Client::delete_buffers()
772 {
773         if( in_buffers ) {
774                 for( int i=0; i<nb_in_bfrs; ++i ) delete [] in_buffers[i];
775                 delete [] in_buffers;  in_buffers = 0;  nb_in_bfrs = 0;
776         }
777         if( out_buffers ) {
778                 for( int i=0; i<nb_out_bfrs; ++i ) delete [] out_buffers[i];
779                 delete [] out_buffers;  out_buffers = 0;  nb_out_bfrs = 0;
780         }
781         bfrsz = 0;
782 }
783
784 int PluginLV2Client::process_realtime(int64_t size,
785         Samples *input_ptr, Samples *output_ptr)
786 {
787         init_plugin(size);
788
789         for( int i=0; i<nb_in_bfrs; ++i ) {
790                 double *inp = input_ptr->get_data();
791                 float *ip = in_buffers[i];
792                 for( int j=size; --j>=0; *ip++=*inp++ );
793         }
794         for( int i=0; i<nb_out_bfrs; ++i )
795                 bzero(out_buffers[i], size*sizeof(float));
796
797         connect_ports();
798         lilv_instance_run(instance, size);
799
800         double *outp = output_ptr->get_data();
801         float *op = out_buffers[0];
802         for( int i=size; --i>=0; *outp++=*op++ );
803         return size;
804 }
805
806 int PluginLV2Client::process_realtime(int64_t size,
807         Samples **input_ptr, Samples **output_ptr)
808 {
809         init_plugin(size);
810
811         for( int i=0; i<nb_in_bfrs; ++i ) {
812                 int k = i < PluginClient::total_in_buffers ? i : 0;
813                 double *inp = input_ptr[k]->get_data();
814                 float *ip = in_buffers[i];
815                 for( int j=size; --j>=0; *ip++=*inp++ );
816         }
817         for( int i=0; i<nb_out_bfrs; ++i )
818                 bzero(out_buffers[i], size*sizeof(float));
819
820         connect_ports();
821         lilv_instance_run(instance, size);
822
823         int nbfrs = PluginClient::total_out_buffers;
824         if( nb_out_bfrs < nbfrs ) nbfrs = nb_out_bfrs;
825         for( int i=0; i<nbfrs; ++i ) {
826                 double *outp = output_ptr[i]->get_data();
827                 float *op = out_buffers[i];
828                 for( int j=size; --j>=0; *outp++=*op++ );
829         }
830         return size;
831 }
832
833 PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name)
834 {
835         return new PluginServer(mwindow, name, PLUGIN_TYPE_LV2);
836 }
837
838 PluginClient *PluginServer::new_lv2_plugin()
839 {
840         PluginLV2Client *client = new PluginLV2Client(this);
841         if( client->load_lv2(path) ) { delete client;  client = 0; }
842         else client->init_lv2();
843         return client;
844 }
845
846 int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp)
847 {
848         printf("init lv2 index:\n");
849         LilvWorld *world = lilv_world_new();
850         lilv_world_load_all(world);
851         const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
852
853         LILV_FOREACH(plugins, i, all_plugins) {
854                 const LilvPlugin *lilv = lilv_plugins_get(all_plugins, i);
855                 const char *uri = lilv_node_as_uri(lilv_plugin_get_uri(lilv));
856                 PluginServer server(mwindow, uri, PLUGIN_TYPE_LV2);
857                 int result = server.open_plugin(1, preferences, 0, 0);
858                 if( !result ) {
859                         server.write_table(fp, uri, PLUGIN_LV2_ID, 0);
860                         server.close_plugin();
861                 }
862         }
863
864         lilv_world_free(world);
865         return 0;
866 }
867
868 #else
869 #include "mwindow.h"
870 #include "pluginserver.h"
871
872 PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name) { return 0; }
873 PluginClient *PluginServer::new_lv2_plugin() { return 0; }
874 int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp) { return 0; }
875
876 #endif /* HAVE_LV2 */