add lv2 plugin interface
authorGood Guy <good1.2guy@gmail.com>
Mon, 7 May 2018 21:28:26 +0000 (15:28 -0600)
committerGood Guy <good1.2guy@gmail.com>
Mon, 7 May 2018 21:28:26 +0000 (15:28 -0600)
15 files changed:
cinelerra-5.1/bld_scripts/bld_prepare.sh
cinelerra-5.1/cinelerra/Makefile
cinelerra-5.1/cinelerra/awindowgui.C
cinelerra-5.1/cinelerra/mwindow.C
cinelerra-5.1/cinelerra/mwindow.h
cinelerra-5.1/cinelerra/mwindow.inc
cinelerra-5.1/cinelerra/pluginaclientlad.C
cinelerra-5.1/cinelerra/pluginfclient.C
cinelerra-5.1/cinelerra/pluginlv2client.C [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginlv2client.h [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginlv2client.inc [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginserver.C
cinelerra-5.1/cinelerra/pluginserver.h
cinelerra-5.1/cinelerra/pluginserver.inc
cinelerra-5.1/configure.ac

index 028a0071746f2c2f1fe13a4d82defcb5cfd97071..929095bc042165eed3a7f31cdef274424a4fe8f0 100755 (executable)
@@ -1,4 +1,6 @@
 #!/bin/bash
+# add lilv-devel for lv2 support
+#  also need lv2 plugins (eg. lv2-calf-plugin)
 
 if [ `id -u` -ne 0 ]; then
   echo "you must be root"
@@ -11,6 +13,7 @@ fi
 
 dir="$1"
 
+
 case "$dir" in
 "centos")
   yum -y install nasm libavc1394-devel libusb-devel flac-devel \
@@ -33,6 +36,7 @@ case "$dir" in
     rm -f /tmp/$yasm
   ;;
 "fedora")
+  dnf install groups "Development Tools"
   dnf -y --best --allowerasing \
     install nasm yasm libavc1394-devel libusb-devel flac-devel \
     libjpeg-devel libdv-devel libdvdnav-devel libdvdread-devel \
@@ -76,7 +80,7 @@ case "$dir" in
   ;;
 #"ub16-10")
 #  apt-get -y install libx264-dev libx265-dev libvpx-dev libmjpegtools-dev
-"ubuntu" | "mint" | "ub14" | "ub15" | "ub16" | "ub17" )
+"ubuntu" | "mint" | "ub14" | "ub15" | "ub16" | "ub17" | "ub18" )
   apt-get -y install apt-file sox nasm yasm g++ build-essential libz-dev \
     texinfo libpng-dev freeglut3-dev libxv-dev libasound2-dev libbz2-dev \
     libncurses5-dev libxinerama-dev libfreetype6-dev libxft-dev libgif-dev \
index b9d23b7d54a60bab411d7eeeaf7bf51adec25ef4..ee779981f7f909bf950c6a4a67f3fd7e80224e05 100644 (file)
@@ -223,6 +223,7 @@ OBJS = \
        $(OBJDIR)/pluginclient.o \
        $(OBJDIR)/plugindialog.o \
        $(OBJDIR)/pluginfclient.o \
+       $(OBJDIR)/pluginlv2client.o \
        $(OBJDIR)/plugin.o \
        $(OBJDIR)/pluginpopup.o \
        $(OBJDIR)/pluginserver.o \
index f33b9cbc1eb3f96eecdb44677167f7904aaa55da..7e97656929ae6787fd8e37d0c8d13de183502c8d 100644 (file)
@@ -2467,10 +2467,14 @@ AddTools::AddTools(MWindow *mwindow, AWindowGUI *gui, int x, int y, const char *
 void AddTools::create_objects()
 {
        uint64_t vis = 0;
-       add_item(new AddPluginItem(this, "ladspa", PLUGIN_LADSPA_ID));
-       vis |= 1 << PLUGIN_LADSPA_ID;
        add_item(new AddPluginItem(this, "ffmpeg", PLUGIN_FFMPEG_ID));
        vis |= 1 << PLUGIN_FFMPEG_ID;
+       add_item(new AddPluginItem(this, "ladspa", PLUGIN_LADSPA_ID));
+       vis |= 1 << PLUGIN_LADSPA_ID;
+#ifdef HAVE_LV2
+       add_item(new AddPluginItem(this, "lv2", PLUGIN_LV2_ID));
+       vis |= 1 << PLUGIN_LV2_ID;
+#endif
        for( int i=0; i<MWindow::plugindb->size(); ++i ) {
                PluginServer *plugin = MWindow::plugindb->get(i);
                if( !plugin->audio && !plugin->video ) continue;
@@ -2489,8 +2493,9 @@ void AddTools::create_objects()
 
 #if 0
 // plugin_dirs list from toplevel makefile include plugin_defs
-N_("ladspa")
 N_("ffmpeg")
+N_("ladspa")
+N_("lv2")
 N_("audio_tools")
 N_("audio_transitions")
 N_("blending")
index 6ad64376e6b3e47839d20d5adae6fdd49d495d3a..243f29a99afc00d58607321154c8275dfc7caac2 100644 (file)
@@ -562,6 +562,9 @@ int MWindow::load_plugin_index(MWindow *mwindow, const char *index_path, const c
                case PLUGIN_TYPE_FFMPEG: {
                        server = new_ffmpeg_server(mwindow, path);
                        break; }
+               case PLUGIN_TYPE_LV2: {
+                       server = new_lv2_server(mwindow, path);
+                       break; }
                }
                if( !server ) continue;
                plugins.append(server);
@@ -630,6 +633,7 @@ int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences)
        fprintf(fp, "%s\n", plugin_path);
        init_plugin_index(mwindow, preferences, fp, plugin_path);
        init_ffmpeg_index(mwindow, preferences, fp);
+       init_lv2_index(mwindow, preferences, fp);
        fclose(fp);
        return load_plugin_index(mwindow, index_path, plugin_path);
 }
@@ -676,25 +680,6 @@ void MWindow::init_plugin_index(MWindow *mwindow, Preferences *preferences,
        scan_plugin_index(mwindow, preferences, fp, plugin_dir, ".", idx);
 }
 
-int MWindow::init_ladspa_index(MWindow *mwindow, Preferences *preferences,
-       const char *index_path, const char *plugin_dir)
-{
-       char plugin_path[BCTEXTLEN], *path = FileSystem::basepath(plugin_dir);
-       strcpy(plugin_path, path);  delete [] path;
-       printf("init ladspa index: %s\n", plugin_dir);
-       FILE *fp = fopen(index_path,"w");
-       if( !fp ) {
-               fprintf(stderr,_("MWindow::init_ladspa_index: "
-                       "can't create plugin index: %s\n"), index_path);
-               return 1;
-       }
-       fprintf(fp, "%d\n", PLUGIN_FILE_VERSION);
-       fprintf(fp, "%s\n", plugin_dir);
-       init_plugin_index(mwindow, preferences, fp, plugin_path);
-       fclose(fp);
-       return 0;
-}
-
 void MWindow::scan_plugin_index(MWindow *mwindow, Preferences *preferences, FILE *fp,
        const char *plug_dir, const char *plug_path, int &idx)
 {
index 24210e41e9d776aceae95ff96bbad291891a50ac..8c251e28b33af49078af7b31e018909efc40865b 100644 (file)
@@ -688,7 +688,10 @@ public:
        static void init_ffmpeg_index(MWindow *mwindow, Preferences *preferences, FILE *fp);
        static int load_plugin_index(MWindow *mwindow, const char *index_path,
                const char *plugin_dir);
-       static PluginServer* new_ffmpeg_server(MWindow *mwindow, const char *name);
+       static PluginServer *new_ffmpeg_server(MWindow *mwindow, const char *name);
+       static int init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp);
+       static PluginServer *new_lv2_server(MWindow *mwindow, const char *name);
+
        void init_preferences();
        void init_signals();
        void init_theme();
index ee6b8ab0eb5cec660a02735b4723e176b1b326b0..bf90324e35712ffae30bc3b537794d1dd13ca8e1 100644 (file)
@@ -34,7 +34,7 @@
 #define PICTURE_FILE "Cinelerra_picture"
 #define PLUGIN_FILE "Cinelerra_plugins"
 #define LADSPA_FILE "ladspa_plugins."
-#define PLUGIN_FILE_VERSION 3
+#define PLUGIN_FILE_VERSION 4
 
 // Behavior of region selections
 #define SELECTION_SAMPLES 0
index f6228c3b96d354d1f10559512449aad6160ab336..403ec7a874b0766935bd50a94b0287de3059dc50 100644 (file)
 
 #include "clip.h"
 #include "bchash.h"
+#include "filesystem.h"
 #include "filexml.h"
 #include "language.h"
+#include "mwindow.h"
 #include "pluginaclientlad.h"
 #include "pluginserver.h"
 #include "samples.h"
@@ -505,12 +507,14 @@ void PluginAClientLAD::read_data(KeyFrame *keyframe)
 
 void PluginAClientLAD::delete_buffers()
 {
-       if(in_buffers)
-               for(int i = 0; i < total_inbuffers; i++) delete [] in_buffers[i];
-       if(out_buffers)
-               for(int i = 0; i < total_outbuffers; i++) delete [] out_buffers[i];
-       in_buffers = 0;
-       out_buffers = 0;
+       if( in_buffers ) {
+               for( int i=0; i<total_inbuffers; ++i ) delete [] in_buffers[i];
+               delete [] in_buffers;  in_buffers = 0;
+       }
+       if( out_buffers ) {
+               for( int i=0; i<total_outbuffers; ++i ) delete [] out_buffers[i];
+               delete [] out_buffers;  out_buffers = 0;
+       }
        total_inbuffers = 0;
        total_outbuffers = 0;
        buffer_allocation = 0;
@@ -650,5 +654,22 @@ int PluginAClientLAD::process_realtime(int64_t size,
        return size;
 }
 
-
+int MWindow::init_ladspa_index(MWindow *mwindow, Preferences *preferences,
+       const char *index_path, const char *plugin_dir)
+{
+       char plugin_path[BCTEXTLEN], *path = FileSystem::basepath(plugin_dir);
+       strcpy(plugin_path, path);  delete [] path;
+       printf("init ladspa index: %s\n", plugin_dir);
+       FILE *fp = fopen(index_path,"w");
+       if( !fp ) {
+               fprintf(stderr,_("MWindow::init_ladspa_index: "
+                       "can't create plugin index: %s\n"), index_path);
+               return 1;
+       }
+       fprintf(fp, "%d\n", PLUGIN_FILE_VERSION);
+       fprintf(fp, "%s\n", plugin_dir);
+       init_plugin_index(mwindow, preferences, fp, plugin_path);
+       fclose(fp);
+       return 0;
+}
 
index 9f570526ec4fe4f6cef91035ad7746fe13d414c7..114d64e547d4559280abfa246c7936ae6da6306b 100644 (file)
@@ -1169,7 +1169,7 @@ PluginServer* MWindow::new_ffmpeg_server(MWindow *mwindow, const char *name)
        PluginFFilter *ffilt = PluginFFilter::new_ffilter(name);
        if( !ffilt ) return 0;
        delete ffilt;
-       return new PluginServer(mwindow, (char*)name, PLUGIN_TYPE_FFMPEG);
+       return new PluginServer(mwindow, name, PLUGIN_TYPE_FFMPEG);
 }
 
 void MWindow::init_ffmpeg_index(MWindow *mwindow, Preferences *preferences, FILE *fp)
diff --git a/cinelerra-5.1/cinelerra/pluginlv2client.C b/cinelerra-5.1/cinelerra/pluginlv2client.C
new file mode 100644 (file)
index 0000000..7ef9486
--- /dev/null
@@ -0,0 +1,814 @@
+#ifdef HAVE_LV2
+
+/*
+ * CINELERRA
+ * Copyright (C) 2018 GG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "clip.h"
+#include "cstrdup.h"
+#include "bchash.h"
+#include "filexml.h"
+#include "language.h"
+#include "mwindow.h"
+#include "pluginlv2client.h"
+#include "pluginserver.h"
+#include "samples.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#define LV2_SEQ_SIZE  9624
+
+PluginLV2UriTable::PluginLV2UriTable()
+{
+       set_array_delete();
+}
+
+PluginLV2UriTable::~PluginLV2UriTable()
+{
+       remove_all_objects();
+}
+
+LV2_URID PluginLV2UriTable::map(const char *uri)
+{
+       for( int i=0; i<size(); ++i )
+               if( !strcmp(uri, get(i)) ) return i+1;
+       append(cstrdup(uri));
+       return size();
+}
+
+const char *PluginLV2UriTable::unmap(LV2_URID urid)
+{
+       int idx = urid - 1;
+       return idx>=0 && idx<size() ? get(idx) : 0;
+}
+
+PluginLV2Client_OptName:: PluginLV2Client_OptName(PluginLV2Client_Opt *opt)
+{
+       this->opt = opt;
+       set_text(opt->get_name());
+}
+
+PluginLV2Client_OptValue::PluginLV2Client_OptValue(PluginLV2Client_Opt *opt)
+{
+       this->opt = opt;
+       update();
+}
+
+int PluginLV2Client_OptValue::update()
+{
+       char val[BCSTRLEN];
+       sprintf(val, "%f", opt->get_value());
+       if( !strcmp(val, get_text()) ) return 0;
+       set_text(val);
+       return 1;
+}
+
+
+PluginLV2Client_Opt::PluginLV2Client_Opt(PluginLV2ClientConfig *conf, const char *sym, int idx)
+{
+       this->conf = conf;
+       this->idx = idx;
+       this->sym = cstrdup(sym);
+       item_name = new PluginLV2Client_OptName(this);
+       item_value = new PluginLV2Client_OptValue(this);
+}
+
+PluginLV2Client_Opt::~PluginLV2Client_Opt()
+{
+       delete [] sym;
+       delete item_name;
+       delete item_value;
+}
+
+float PluginLV2Client_Opt::get_value()
+{
+       return conf->ctls[idx];
+}
+
+void PluginLV2Client_Opt::set_value(float v)
+{
+       conf->ctls[idx] = v;
+}
+
+int PluginLV2Client_Opt::update(float v)
+{
+       set_value(v);
+       return item_value->update();
+}
+
+const char *PluginLV2Client_Opt::get_name()
+{
+       return conf->names[idx];
+}
+
+PluginLV2ClientConfig::PluginLV2ClientConfig()
+{
+       names = 0;
+       mins = 0;
+       maxs = 0;
+       ctls = 0;
+       nb_ports = 0;
+}
+
+PluginLV2ClientConfig::~PluginLV2ClientConfig()
+{
+       reset();
+       remove_all_objects();
+}
+
+void PluginLV2ClientConfig::reset()
+{
+       for( int i=0; i<nb_ports; ++i ) delete [] names[i];
+       delete [] names; names = 0;
+       delete [] mins;  mins = 0;
+       delete [] maxs;  maxs = 0;
+       delete [] ctls;  ctls = 0;
+       nb_ports = 0;
+}
+
+
+int PluginLV2ClientConfig::equivalent(PluginLV2ClientConfig &that)
+{
+       PluginLV2ClientConfig &conf = *this;
+       for( int i=0; i<that.size(); ++i ) {
+               PluginLV2Client_Opt *topt = conf[i], *vopt = that[i];
+               if( !EQUIV(topt->get_value(), vopt->get_value()) ) return 0;
+       }
+       return 1;
+}
+
+void PluginLV2ClientConfig::copy_from(PluginLV2ClientConfig &that)
+{
+        if( nb_ports != that.nb_ports ) {
+                reset();
+               nb_ports = that.nb_ports;
+               names = new const char *[nb_ports];
+               for( int i=0; i<nb_ports; ++i ) names[i] = 0;
+               mins  = new float[nb_ports];
+               maxs  = new float[nb_ports];
+               ctls  = new float[nb_ports];
+        }
+        for( int i=0; i<nb_ports; ++i ) {
+               delete [] names[i];
+               names[i] = cstrdup(that.names[i]);
+                mins[i] = that.mins[i];
+                maxs[i] = that.maxs[i];
+                ctls[i] = that.ctls[i];
+        }
+       remove_all_objects();
+       for( int i=0; i<that.size(); ++i ) {
+               append(new PluginLV2Client_Opt(this, that[i]->sym, that[i]->idx));
+       }
+}
+
+void PluginLV2ClientConfig::interpolate(PluginLV2ClientConfig &prev, PluginLV2ClientConfig &next,
+       int64_t prev_frame, int64_t next_frame, int64_t current_frame)
+{
+       copy_from(prev);
+}
+
+void PluginLV2ClientConfig::init_lv2(const LilvPlugin *lilv)
+{
+       reset();
+       nb_ports = lilv_plugin_get_num_ports(lilv);
+       names = new const char *[nb_ports];
+       mins  = new float[nb_ports];
+       maxs  = new float[nb_ports];
+       ctls  = new float[nb_ports];
+       lilv_plugin_get_port_ranges_float(lilv, mins, maxs, ctls);
+               for( int i=0; i<nb_ports; ++i ) {
+               const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
+               LilvNode *pnm = lilv_port_get_name(lilv, lp);
+               names[i] = cstrdup(lilv_node_as_string(pnm));
+               lilv_node_free(pnm);
+       }
+}
+
+int PluginLV2ClientConfig::update()
+{
+       int ret = 0;
+       PluginLV2ClientConfig &conf = *this;
+       for( int i=0; i<size(); ++i ) {
+               if( conf[i]->item_value->update() ) ++ret;
+       }
+       return ret;
+}
+
+PluginLV2ClientReset::
+PluginLV2ClientReset(PluginLV2ClientWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+       this->gui = gui;
+}
+
+PluginLV2ClientReset::
+~PluginLV2ClientReset()
+{
+}
+
+int PluginLV2ClientReset::handle_event()
+{
+       PluginLV2Client *plugin = gui->plugin;
+       plugin->init_lv2();
+       gui->selected = 0;
+       gui->update_selected();
+       gui->panel->update();
+        plugin->send_configure_change();
+        return 1;
+}
+
+PluginLV2ClientText::
+PluginLV2ClientText(PluginLV2ClientWindow *gui, int x, int y, int w)
+ : BC_TextBox(x, y, w, 1, (char *)"")
+{
+        this->gui = gui;
+}
+
+PluginLV2ClientText::
+~PluginLV2ClientText()
+{
+}
+
+int PluginLV2ClientText::handle_event()
+{
+        return 0;
+}
+
+
+PluginLV2ClientApply::
+PluginLV2ClientApply(PluginLV2ClientWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Apply"))
+{
+       this->gui = gui;
+}
+
+PluginLV2ClientApply::
+~PluginLV2ClientApply()
+{
+}
+
+int PluginLV2ClientApply::handle_event()
+{
+       const char *text = gui->text->get_text();
+       if( text && gui->selected ) {
+               gui->selected->update(atof(text));
+               gui->update_selected();
+               gui->plugin->send_configure_change();
+       }
+       return 1;
+}
+
+
+PluginLV2Client_OptPanel::
+PluginLV2Client_OptPanel(PluginLV2ClientWindow *gui, int x, int y, int w, int h)
+ : BC_ListBox(x, y, w, h, LISTBOX_TEXT), opts(items[0]), vals(items[1])
+{
+       this->gui = gui;
+       update();  // init col/wid/columns
+}
+
+PluginLV2Client_OptPanel::
+~PluginLV2Client_OptPanel()
+{
+}
+
+int PluginLV2Client_OptPanel::selection_changed()
+{
+       PluginLV2Client_Opt *opt = 0;
+       BC_ListBoxItem *item = get_selection(0, 0);
+       if( item ) {
+               PluginLV2Client_OptName *opt_name = (PluginLV2Client_OptName *)item;
+               opt = opt_name->opt;
+       }
+       gui->update(opt);
+       return 1;
+}
+
+void PluginLV2Client_OptPanel::update()
+{
+       opts.remove_all();
+       vals.remove_all();
+       PluginLV2ClientConfig &conf = gui->plugin->config;
+       for( int i=0; i<conf.size(); ++i ) {
+               PluginLV2Client_Opt *opt = conf[i];
+               opts.append(opt->item_name);
+               vals.append(opt->item_value);
+       }
+       const char *cols[] = { "option", "value", };
+       const int col1_w = 150;
+       int wids[] = { col1_w, get_w()-col1_w };
+       BC_ListBox::update(&items[0], &cols[0], &wids[0], sizeof(items)/sizeof(items[0]));
+}
+
+PluginLV2ClientWindow::PluginLV2ClientWindow(PluginLV2Client *plugin)
+ : PluginClientWindow(plugin, 500, 300, 500, 300, 0)
+{
+       this->plugin = plugin;
+       selected = 0;
+}
+
+PluginLV2ClientWindow::~PluginLV2ClientWindow()
+{
+}
+
+
+void PluginLV2ClientWindow::create_objects()
+{
+       BC_Title *title;
+       int x = 10, y = 10;
+       add_subwindow(title = new BC_Title(x, y, plugin->title));
+       y += title->get_h() + 10;
+       add_subwindow(varbl = new BC_Title(x, y, ""));
+       add_subwindow(range = new BC_Title(x+160, y, ""));
+       int x1 = get_w() - BC_GenericButton::calculate_w(this, _("Reset")) - 8;
+       add_subwindow(reset = new PluginLV2ClientReset(this, x1, y));
+       y += title->get_h() + 10;
+       x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - 8;
+       add_subwindow(apply = new PluginLV2ClientApply(this, x1, y));
+       add_subwindow(text = new PluginLV2ClientText(this, x, y, x1-x - 8));
+       y += title->get_h() + 10;
+       plugin->init_lv2();
+
+       int panel_x = x, panel_y = y;
+       int panel_w = get_w()-10 - panel_x;
+       int panel_h = get_h()-10 - panel_y;
+       panel = new PluginLV2Client_OptPanel(this, panel_x, panel_y, panel_w, panel_h);
+       add_subwindow(panel);
+       panel->update();
+       show_window(1);
+}
+
+void PluginLV2ClientWindow::update_selected()
+{
+       update(selected);
+}
+
+int PluginLV2ClientWindow::scalar(float f, char *rp)
+{
+        const char *cp = 0;
+             if( f == FLT_MAX ) cp = "FLT_MAX";
+        else if( f == FLT_MIN ) cp = "FLT_MIN";
+        else if( f == -FLT_MAX ) cp = "-FLT_MAX";
+        else if( f == -FLT_MIN ) cp = "-FLT_MIN";
+        else if( f == 0 ) cp = signbit(f) ? "-0" : "0";
+        else if( isnan(f) ) cp = signbit(f) ? "-NAN" : "NAN";
+        else if( isinf(f) ) cp = signbit(f) ? "-INF" : "INF";
+        else return sprintf(rp, "%g", f);
+        return sprintf(rp, "%s", cp);
+}
+
+void PluginLV2ClientWindow::update(PluginLV2Client_Opt *opt)
+{
+       if( selected != opt ) {
+               if( selected ) selected->item_name->set_selected(0);
+               selected = opt;
+               if( selected ) selected->item_name->set_selected(1);
+       }
+       char var[BCSTRLEN];  var[0] = 0;
+       char val[BCSTRLEN];  val[0] = 0;
+       char rng[BCTEXTLEN]; rng[0] = 0;
+       if( opt ) {
+               sprintf(var,"%s:", opt->conf->names[opt->idx]);
+               char *cp = rng;
+               cp += sprintf(cp,"( ");
+               cp += scalar(opt->conf->mins[opt->idx], cp);
+               cp += sprintf(cp, " .. ");
+               cp += scalar(opt->conf->maxs[opt->idx], cp);
+               cp += sprintf(cp, " )");
+               sprintf(val, "%f", opt->get_value());
+       }
+       varbl->update(var);
+       range->update(rng);
+       text->update(val);
+       panel->update();
+}
+
+
+PluginLV2Client::PluginLV2Client(PluginServer *server)
+ : PluginAClient(server)
+{
+       in_buffers = 0;
+       out_buffers = 0;
+       nb_in_bfrs = 0;
+       nb_out_bfrs = 0;
+        bfrsz = 0;
+       nb_inputs = 0;
+       nb_outputs = 0;
+       max_bufsz = 0;
+
+       world = 0;
+       instance = 0;
+       lv2_InputPort = 0;
+       lv2_OutputPort = 0;
+       lv2_AudioPort = 0;
+       lv2_CVPort = 0;
+       lv2_ControlPort = 0;
+       lv2_Optional = 0;
+       atom_AtomPort = 0;
+       atom_Sequence = 0;
+       urid_map = 0;
+       powerOf2BlockLength = 0;
+       fixedBlockLength = 0;
+       boundedBlockLength = 0;
+       seq_out = 0;
+}
+
+PluginLV2Client::~PluginLV2Client()
+{
+       reset_lv2();
+       lilv_world_free(world);
+}
+
+void PluginLV2Client::reset_lv2()
+{
+       if( instance ) lilv_instance_deactivate(instance);
+       lilv_instance_free(instance);         instance = 0;
+       lilv_node_free(powerOf2BlockLength);  powerOf2BlockLength = 0;
+       lilv_node_free(fixedBlockLength);     fixedBlockLength = 0;
+       lilv_node_free(boundedBlockLength);   boundedBlockLength = 0;
+       lilv_node_free(urid_map);             urid_map = 0;
+       lilv_node_free(atom_Sequence);        atom_Sequence = 0;
+       lilv_node_free(atom_AtomPort);        atom_AtomPort = 0;
+       lilv_node_free(lv2_Optional);         lv2_Optional = 0;
+       lilv_node_free(lv2_ControlPort);      lv2_ControlPort = 0;
+       lilv_node_free(lv2_AudioPort);        lv2_AudioPort = 0;
+       lilv_node_free(lv2_CVPort);           lv2_CVPort = 0;
+       lilv_node_free(lv2_OutputPort);       lv2_OutputPort = 0;
+       lilv_node_free(lv2_InputPort);        lv2_InputPort = 0;
+       delete [] (char *)seq_out;            seq_out = 0;
+       uri_table.remove_all_objects();
+       delete_buffers();
+       nb_inputs = 0;
+       nb_outputs = 0;
+       max_bufsz = 0;
+       config.reset();
+       config.remove_all_objects();
+}
+
+int PluginLV2Client::load_lv2(const char *path)
+{
+       if( !world ) {
+               world = lilv_world_new();
+               if( !world ) {
+                       printf("lv2: lilv_world_new failed");
+                       return 1;
+               }
+               lilv_world_load_all(world);
+       }
+
+       LilvNode *uri = lilv_new_uri(world, path);
+       if( !uri ) {
+               printf("lv2: lilv_new_uri(%s) failed", path);
+               return 1;
+       }
+
+       const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
+       lilv = lilv_plugins_get_by_uri(all_plugins, uri);
+       lilv_node_free(uri);
+       if( !lilv ) {
+               printf("lv2: lilv_plugins_get_by_uriPlugin(%s) failed", path);
+               return 1;
+       }
+
+       LilvNode *name = lilv_plugin_get_name(lilv);
+       const char *nm = lilv_node_as_string(name);
+       snprintf(title,sizeof(title),"L2_%s",nm);
+       lilv_node_free(name);
+       return 0;
+}
+
+int PluginLV2Client::init_lv2()
+{
+       reset_lv2();
+
+       lv2_InputPort       = lilv_new_uri(world, LV2_CORE__InputPort);
+       lv2_OutputPort      = lilv_new_uri(world, LV2_CORE__OutputPort);
+       lv2_AudioPort       = lilv_new_uri(world, LV2_CORE__AudioPort);
+       lv2_ControlPort     = lilv_new_uri(world, LV2_CORE__ControlPort);
+       lv2_CVPort          = lilv_new_uri(world, LV2_CORE__CVPort);
+       lv2_Optional        = lilv_new_uri(world, LV2_CORE__connectionOptional);
+       atom_AtomPort       = lilv_new_uri(world, LV2_ATOM__AtomPort);
+       atom_Sequence       = lilv_new_uri(world, LV2_ATOM__Sequence);
+       urid_map            = lilv_new_uri(world, LV2_URID__map);
+       powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
+       fixedBlockLength    = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
+       boundedBlockLength  = lilv_new_uri(world, LV2_BUF_SIZE__boundedBlockLength);
+       seq_out = (LV2_Atom_Sequence *) new char[sizeof(LV2_Atom_Sequence) + LV2_SEQ_SIZE];
+
+       config.init_lv2(lilv);
+       nb_inputs = nb_outputs = 0;
+
+        for( int i=0; i<config.nb_ports; ++i ) {
+               const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
+               int is_input = lilv_port_is_a(lilv, lp, lv2_InputPort);
+               if( !is_input && !lilv_port_is_a(lilv, lp, lv2_OutputPort) &&
+                   !lilv_port_has_property(lilv, lp, lv2_Optional) ) {
+                       printf("lv2: not input, not output, and not optional: %s\n", config.names[i]);
+                       continue;
+               }
+               if( is_input && lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
+                       const char *sym = lilv_node_as_string(lilv_port_get_symbol(lilv, lp));
+                       config.append(new PluginLV2Client_Opt(&config, sym, i));
+                       continue;
+               }
+               if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
+                   lilv_port_is_a(lilv, lp, lv2_CVPort ) ) {
+                       if( is_input ) ++nb_inputs; else ++nb_outputs;
+                       continue;
+               }
+       }
+
+       map.handle = (void*)&uri_table;
+       map.map = uri_table_map;
+       map_feature.URI = LV2_URID_MAP_URI;
+       map_feature.data = &map;
+       unmap.handle = (void*)&uri_table;
+       unmap.unmap  = uri_table_unmap;
+       unmap_feature.URI = LV2_URID_UNMAP_URI;
+       unmap_feature.data = &unmap;
+       features[0] = &map_feature;
+       features[1] = &unmap_feature;
+       static const LV2_Feature buf_size_features[3] = {
+               { LV2_BUF_SIZE__powerOf2BlockLength, NULL },
+               { LV2_BUF_SIZE__fixedBlockLength,    NULL },
+               { LV2_BUF_SIZE__boundedBlockLength,  NULL },
+       };
+       features[2] = &buf_size_features[0];
+       features[3] = &buf_size_features[1];
+       features[4] = &buf_size_features[2];
+       features[5] = 0;
+
+       instance = lilv_plugin_instantiate(lilv, sample_rate, features);
+       if( !instance ) {
+               printf("lv2: lilv_plugin_instantiate failed: %s\n", server->title);
+               return 1;
+       }
+       lilv_instance_activate(instance);
+// not sure what to do with these
+       max_bufsz = nb_inputs &&
+               (lilv_plugin_has_feature(lilv, powerOf2BlockLength) ||
+                lilv_plugin_has_feature(lilv, fixedBlockLength) ||
+                lilv_plugin_has_feature(lilv, boundedBlockLength)) ? 4096 : 0;
+       return 0;
+}
+
+LV2_URID PluginLV2Client::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
+{
+       return ((PluginLV2UriTable *)handle)->map(uri);
+}
+
+const char *PluginLV2Client::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
+{
+       return ((PluginLV2UriTable *)handle)->unmap(urid);
+}
+
+NEW_WINDOW_MACRO(PluginLV2Client, PluginLV2ClientWindow)
+
+int PluginLV2Client::load_configuration()
+{
+       int64_t src_position =  get_source_position();
+       KeyFrame *prev_keyframe = get_prev_keyframe(src_position);
+       PluginLV2ClientConfig curr_config;
+       curr_config.copy_from(config);
+       read_data(prev_keyframe);
+       int ret = !config.equivalent(curr_config) ? 1 : 0;
+       return ret;
+}
+
+void PluginLV2Client::update_gui()
+{
+       PluginClientThread *thread = get_thread();
+       if( !thread ) return;
+       PluginLV2ClientWindow *window = (PluginLV2ClientWindow*)thread->get_window();
+       window->lock_window("PluginFClient::update_gui");
+       load_configuration();
+       if( config.update() > 0 )
+               window->update_selected();
+       window->unlock_window();
+}
+
+int PluginLV2Client::is_realtime() { return 1; }
+int PluginLV2Client::is_multichannel() { return nb_inputs > 1 || nb_outputs > 1 ? 1 : 0; }
+const char* PluginLV2Client::plugin_title() { return title; }
+int PluginLV2Client::uses_gui() { return 1; }
+int PluginLV2Client::is_synthesis() { return 1; }
+
+char* PluginLV2Client::to_string(char *string, const char *input)
+{
+       char *bp = string;
+       for( const char *cp=input; *cp; ++cp )
+               *bp++ = isalnum(*cp) ? *cp : '_';
+       *bp = 0;
+       return string;
+}
+
+void PluginLV2Client::save_data(KeyFrame *keyframe)
+{
+       FileXML output;
+       output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+       char name[BCTEXTLEN];  to_string(name, plugin_title());
+       output.tag.set_title(name);
+       for( int i=0; i<config.size(); ++i ) {
+               PluginLV2Client_Opt *opt = config[i];
+               output.tag.set_property(opt->sym, opt->get_value());
+       }
+       output.append_tag();
+       output.terminate_string();
+}
+
+void PluginLV2Client::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+       char name[BCTEXTLEN];  to_string(name, plugin_title());
+
+       while( !input.read_tag() ) {
+               if( !input.tag.title_is(name) ) continue;
+               for( int i=0; i<config.size(); ++i ) {
+                       PluginLV2Client_Opt *opt = config[i];
+                       float value = input.tag.get_property(opt->sym, 0.);
+                       opt->set_value(value);
+               }
+       }
+}
+
+void PluginLV2Client::connect_ports()
+{
+       int ich = 0, och = 0;
+       for( int i=0; i<config.nb_ports; ++i ) {
+               const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
+               if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
+                   lilv_port_is_a(lilv, lp, lv2_CVPort) ) {
+                       if( lilv_port_is_a(lilv, lp, lv2_InputPort) )
+                               lilv_instance_connect_port(instance, i, in_buffers[ich++]);
+                       else if( lilv_port_is_a(lilv, lp, lv2_OutputPort))
+                               lilv_instance_connect_port(instance, i, out_buffers[och++]);
+                       continue;
+               }
+               if( lilv_port_is_a(lilv, lp, atom_AtomPort) ) {
+                       if( lilv_port_is_a(lilv, lp, lv2_InputPort) )
+                               lilv_instance_connect_port(instance, i, &seq_in);
+                       else
+                               lilv_instance_connect_port(instance, i, seq_out);
+                       continue;
+               }
+               if( lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
+                       lilv_instance_connect_port(instance, i, &config.ctls[i]);
+                       continue;
+               }
+       }
+
+       seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body);
+       seq_in[0].atom.type = uri_table.map(LV2_ATOM__Sequence);
+       seq_in[1].atom.size = 0;
+       seq_in[1].atom.type = 0;
+       seq_out->atom.size  = LV2_SEQ_SIZE;
+       seq_out->atom.type  = uri_table.map(LV2_ATOM__Chunk);
+}
+
+void PluginLV2Client::init_plugin(int size)
+{
+       if( !instance )
+               init_lv2();
+
+       load_configuration();
+
+       if( bfrsz < size )
+               delete_buffers();
+
+       bfrsz = MAX(size, bfrsz);
+       if( !in_buffers ) {
+               in_buffers = new float*[nb_in_bfrs=nb_inputs];
+               for(int i=0; i<nb_in_bfrs; ++i )
+                       in_buffers[i] = new float[bfrsz];
+       }
+       if( !out_buffers ) {
+               out_buffers = new float*[nb_out_bfrs=nb_outputs];
+               for( int i=0; i<nb_out_bfrs; ++i )
+                       out_buffers[i] = new float[bfrsz];
+       }
+}
+
+void PluginLV2Client::delete_buffers()
+{
+       if( in_buffers ) {
+               for( int i=0; i<nb_in_bfrs; ++i ) delete [] in_buffers[i];
+               delete [] in_buffers;  in_buffers = 0;  nb_in_bfrs = 0;
+       }
+       if( out_buffers ) {
+                for( int i=0; i<nb_out_bfrs; ++i ) delete [] out_buffers[i];
+               delete [] out_buffers;  out_buffers = 0;  nb_out_bfrs = 0;
+       }
+        bfrsz = 0;
+}
+
+int PluginLV2Client::process_realtime(int64_t size,
+       Samples *input_ptr, Samples *output_ptr)
+{
+       init_plugin(size);
+
+       for( int i=0; i<nb_in_bfrs; ++i ) {
+               double *inp = input_ptr->get_data();
+               float *ip = in_buffers[i];
+               for( int j=size; --j>=0; *ip++=*inp++ );
+       }
+       for( int i=0; i<nb_out_bfrs; ++i )
+               bzero(out_buffers[i], size*sizeof(float));
+
+       connect_ports();
+       lilv_instance_run(instance, size);
+
+       double *outp = output_ptr->get_data();
+       float *op = out_buffers[0];
+       for( int i=size; --i>=0; *outp++=*op++ );
+       return size;
+}
+
+int PluginLV2Client::process_realtime(int64_t size,
+       Samples **input_ptr, Samples **output_ptr)
+{
+       init_plugin(size);
+
+       for( int i=0; i<nb_in_bfrs; ++i ) {
+               int k = i < PluginClient::total_in_buffers ? i : 0;
+               double *inp = input_ptr[k]->get_data();
+               float *ip = in_buffers[i];
+               for( int j=size; --j>=0; *ip++=*inp++ );
+       }
+       for( int i=0; i<nb_out_bfrs; ++i )
+               bzero(out_buffers[i], size*sizeof(float));
+
+       connect_ports();
+       lilv_instance_run(instance, size);
+
+       int nbfrs = PluginClient::total_out_buffers;
+       if( nb_out_bfrs < nbfrs ) nbfrs = nb_out_bfrs;
+       for( int i=0; i<nbfrs; ++i ) {
+               double *outp = output_ptr[i]->get_data();
+               float *op = out_buffers[i];
+               for( int j=size; --j>=0; *outp++=*op++ );
+       }
+       return size;
+}
+
+PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name)
+{
+       return new PluginServer(mwindow, name, PLUGIN_TYPE_LV2);
+}
+
+PluginClient *PluginServer::new_lv2_plugin()
+{
+       PluginLV2Client *client = new PluginLV2Client(this);
+       if( client->load_lv2(path) ) { delete client;  client = 0; }
+       else client->init_lv2();
+       return client;
+}
+
+int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp)
+{
+       printf("init lv2 index:\n");
+       LilvWorld *world = lilv_world_new();
+       lilv_world_load_all(world);
+       const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
+
+       LILV_FOREACH(plugins, i, all_plugins) {
+               const LilvPlugin *lilv = lilv_plugins_get(all_plugins, i);
+               const char *uri = lilv_node_as_uri(lilv_plugin_get_uri(lilv));
+               PluginServer server(mwindow, uri, PLUGIN_TYPE_LV2);
+               int result = server.open_plugin(1, preferences, 0, 0);
+               if( !result ) {
+                       server.write_table(fp, uri, PLUGIN_LV2_ID, 0);
+                       server.close_plugin();
+               }
+       }
+
+       lilv_world_free(world);
+       return 0;
+}
+
+#else
+#include "mwindow.h"
+#include "pluginserver.h"
+
+PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name) { return 0; }
+PluginClient *PluginServer::new_lv2_plugin() { return 0; }
+int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp) { return 0; }
+
+#endif /* HAVE_LV2 */
diff --git a/cinelerra-5.1/cinelerra/pluginlv2client.h b/cinelerra-5.1/cinelerra/pluginlv2client.h
new file mode 100644 (file)
index 0000000..a724ca7
--- /dev/null
@@ -0,0 +1,226 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef PLUGINLV2CLIENT_H
+#define PLUGINLV2CLIENT_H
+
+#include "bcdisplayinfo.h"
+#include "guicast.h"
+#include "pluginaclient.h"
+#include "pluginlv2client.inc"
+#include "samples.inc"
+
+#include <lilv/lilv.h>
+#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
+#include <lv2/lv2plug.in/ns/ext/buf-size/buf-size.h>
+
+class PluginLV2UriTable : public ArrayList<const char *>
+{
+public:
+       PluginLV2UriTable();
+       ~PluginLV2UriTable();
+       LV2_URID map(const char *uri);
+       const char *unmap(LV2_URID urid);
+};
+
+class PluginLV2Client_OptName : public BC_ListBoxItem
+{
+public:
+       PluginLV2Client_Opt *opt;
+       PluginLV2Client_OptName(PluginLV2Client_Opt *opt);
+};
+
+class PluginLV2Client_OptValue : public BC_ListBoxItem
+{
+public:
+       PluginLV2Client_Opt *opt;
+       PluginLV2Client_OptValue(PluginLV2Client_Opt *opt);
+       int update();
+};
+
+class PluginLV2Client_Opt
+{
+public:
+       int idx;
+       const char *sym;
+       PluginLV2ClientConfig *conf;
+       PluginLV2Client_OptName *item_name;
+       PluginLV2Client_OptValue *item_value;
+       float get_value();
+       void set_value(float v);
+       int update(float v);
+       const char *get_name();
+
+       PluginLV2Client_Opt(PluginLV2ClientConfig *conf, const char *sym, int idx);
+       ~PluginLV2Client_Opt();
+};
+
+
+class PluginLV2ClientConfig : public ArrayList<PluginLV2Client_Opt *>
+{
+public:
+       PluginLV2ClientConfig();
+       ~PluginLV2ClientConfig();
+
+       int equivalent(PluginLV2ClientConfig &that);
+       void copy_from(PluginLV2ClientConfig &that);
+       void interpolate(PluginLV2ClientConfig &prev, PluginLV2ClientConfig &next,
+               int64_t prev_frame, int64_t next_frame, int64_t current_frame);
+       void reset();
+       void init_lv2(const LilvPlugin *lilv);
+       int update();
+
+       int nb_ports;
+       const char **names;
+       float *mins, *maxs, *ctls;
+};
+
+class PluginLV2Client_OptPanel : public BC_ListBox
+{
+public:
+       PluginLV2Client_OptPanel(PluginLV2ClientWindow *gui, int x, int y, int w, int h);
+       ~PluginLV2Client_OptPanel();
+
+       PluginLV2ClientWindow *gui;
+       ArrayList<BC_ListBoxItem*> items[2];
+       ArrayList<BC_ListBoxItem*> &opts;
+       ArrayList<BC_ListBoxItem*> &vals;
+
+       int selection_changed();
+       void update();
+};
+
+class PluginLV2ClientText : public BC_TextBox {
+public:
+        PluginLV2ClientWindow *gui;
+
+        PluginLV2ClientText(PluginLV2ClientWindow *gui, int x, int y, int w);
+        ~PluginLV2ClientText();
+        int handle_event();
+};
+
+class PluginLV2ClientReset : public BC_GenericButton
+{
+public:
+       PluginLV2ClientWindow *gui;
+
+       PluginLV2ClientReset(PluginLV2ClientWindow *gui, int x, int y);
+       ~PluginLV2ClientReset();
+       int handle_event();
+};
+
+class PluginLV2ClientApply : public BC_GenericButton {
+public:
+        PluginLV2ClientWindow *gui;
+
+        PluginLV2ClientApply(PluginLV2ClientWindow *gui, int x, int y);
+        ~PluginLV2ClientApply();
+        int handle_event();
+};
+
+class PluginLV2ClientWindow : public PluginClientWindow
+{
+public:
+       PluginLV2ClientWindow(PluginLV2Client *plugin);
+       ~PluginLV2ClientWindow();
+
+       void create_objects();
+       void update_selected();
+       int scalar(float f, char *rp);
+       void update(PluginLV2Client_Opt *opt);
+
+       PluginLV2Client *plugin;
+       PluginLV2ClientReset *reset;
+       PluginLV2ClientApply *apply;
+       PluginLV2ClientText *text;
+       BC_Title *varbl, *range;
+       PluginLV2Client_OptPanel *panel;
+       PluginLV2Client_Opt *selected;
+};
+
+
+class PluginLV2Client : public PluginAClient
+{
+public:
+       PluginLV2Client(PluginServer *server);
+       ~PluginLV2Client();
+
+       int process_realtime(int64_t size,
+               Samples *input_ptr,
+               Samples *output_ptr);
+       int process_realtime(int64_t size,
+               Samples **input_ptr,
+               Samples **output_ptr);
+// Update output pointers as well
+       void update_gui();
+       int is_realtime();
+       int is_multichannel();
+       int is_synthesis();
+       int uses_gui();
+       char* to_string(char *string, const char *input);
+       void save_data(KeyFrame *keyframe);
+       void read_data(KeyFrame *keyframe);
+       void reset_lv2();
+       int load_lv2(const char *path);
+       int init_lv2();
+
+       PLUGIN_CLASS_MEMBERS(PluginLV2ClientConfig)
+       char title[BCSTRLEN];
+       int bfrsz, nb_in_bfrs, nb_out_bfrs;
+       float **in_buffers, **out_buffers;
+
+       void delete_buffers();
+       void init_plugin(int size);
+       void connect_ports();
+       static LV2_URID uri_table_map(LV2_URID_Map_Handle handle, const char *uri);
+       static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid);
+
+// lv2
+       LilvWorld         *world;
+       const LilvPlugin  *lilv;
+       int nb_inputs, nb_outputs;
+       int max_bufsz;
+
+       PluginLV2UriTable  uri_table;
+       LV2_URID_Map       map;
+       LV2_Feature        map_feature;
+       LV2_URID_Unmap     unmap;
+       LV2_Feature        unmap_feature;
+       const LV2_Feature  *features[6];
+       LV2_Atom_Sequence  seq_in[2];
+       LV2_Atom_Sequence  *seq_out;
+
+       LilvInstance *instance;
+       LilvNode *atom_AtomPort;
+       LilvNode *atom_Sequence;
+       LilvNode *lv2_AudioPort;
+       LilvNode *lv2_CVPort;
+       LilvNode *lv2_ControlPort;
+       LilvNode *lv2_Optional;
+       LilvNode *lv2_InputPort;
+       LilvNode *lv2_OutputPort;
+       LilvNode *urid_map;
+       LilvNode *powerOf2BlockLength;
+       LilvNode *fixedBlockLength;
+       LilvNode *boundedBlockLength;
+};
+
+#endif
diff --git a/cinelerra-5.1/cinelerra/pluginlv2client.inc b/cinelerra-5.1/cinelerra/pluginlv2client.inc
new file mode 100644 (file)
index 0000000..9a72a7e
--- /dev/null
@@ -0,0 +1,37 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef PLUGINLV2CLIENT_INC
+#define PLUGINLV2CLIENT_INC
+
+class PluginLV2UriTable;
+class PluginLV2Client_OptName;
+class PluginLV2Client_OptValue;
+class PluginLV2Client_Opt;
+class PluginLV2ClientConfig;
+class PluginLV2Client_OptPanel;
+class PluginLV2ClientText;
+class PluginLV2ClientReset;
+class PluginLV2ClientApply;
+class PluginLV2ClientWindow;
+class PluginLV2Client;
+
+#endif
index 8feb6ed612ce35dfab061837d629aafb19915125..6e42e947a4a10b3d51e5acc34ab54f4ed78e52b6 100644 (file)
@@ -87,7 +87,7 @@ PluginServer::PluginServer()
        init();
 }
 
-PluginServer::PluginServer(MWindow *mwindow, char *path, int type)
+PluginServer::PluginServer(MWindow *mwindow, const char *path, int type)
 {
        char fpath[BCTEXTLEN];
        init();
@@ -98,7 +98,7 @@ PluginServer::PluginServer(MWindow *mwindow, char *path, int type)
                sprintf(fpath, "ff_%s", path);
                path = fpath;
        }
-        set_path(path);
+       set_path(path);
 }
 
 PluginServer::PluginServer(PluginServer &that)
@@ -154,18 +154,14 @@ int PluginServer::reset_parameters()
        prompt = 0;
        cleanup_plugin();
 
-       lad_index = -1;
-       lad_descriptor_function = 0;
-       lad_descriptor = 0;
-
        plugin_obj = 0;
        client = 0; 
        new_plugin = 0;
        lad_index = -1;
        lad_descriptor_function = 0;
        lad_descriptor = 0;
-       use_opengl = 0;
        ff_name = 0;
+       use_opengl = 0;
        vdevice = 0;
        plugin_type = 0;
        start_auto = end_auto = 0;
@@ -242,6 +238,21 @@ int PluginServer::get_lad_index()
        return this->lad_index;
 }
 
+int PluginServer::is_unknown()
+{
+       return plugin_type == PLUGIN_TYPE_UNKNOWN ? 1 : 0;
+}
+
+int PluginServer::is_executable()
+{
+       return  plugin_type == PLUGIN_TYPE_EXECUTABLE ? 1 : 0;
+}
+
+int PluginServer::is_builtin()
+{
+       return plugin_type == PLUGIN_TYPE_BUILTIN ? 1 : 0;
+}
+
 int PluginServer::is_ladspa()
 {
        return plugin_type == PLUGIN_TYPE_LADSPA ? 1 : 0;
@@ -252,6 +263,11 @@ int PluginServer::is_ffmpeg()
        return plugin_type == PLUGIN_TYPE_FFMPEG ? 1 : 0;
 }
 
+int PluginServer::is_lv2()
+{
+       return plugin_type == PLUGIN_TYPE_LV2 ? 1 : 0;
+}
+
 void PluginServer::set_path(const char *path)
 {
        delete [] this->path;
@@ -332,20 +348,20 @@ int PluginServer::open_plugin(int master,
        this->preferences = preferences;
        this->plugin = plugin;
        this->edl = edl;
-       if( plugin_type != PLUGIN_TYPE_FFMPEG && plugin_type != PLUGIN_TYPE_EXECUTABLE && !load_obj() ) {
-// If the load failed, can't use error to detect executable
-//  because locale and language selection change the load_error()
+       if( !is_ffmpeg() && !is_lv2() && !is_executable() && !load_obj() ) {
+// If the load failed, can't use error string to detect executable
+//  because locale and language selection changes the load_error() message
 //     if( !strstr(string, "executable") ) { set_title(path); plugin_type = PLUGIN_TYPE_EXECUTABLE; }
                eprintf("PluginServer::open_plugin: load_obj %s = %s\n", path, load_error());
                return PLUGINSERVER_NOT_RECOGNIZED;
        }
-       if( plugin_type == PLUGIN_TYPE_UNKNOWN || plugin_type == PLUGIN_TYPE_BUILTIN ) {
+       if( is_unknown() || is_builtin() ) {
                new_plugin =
                        (PluginClient* (*)(PluginServer*)) get_sym("new_plugin");
                if( new_plugin )
                        plugin_type = PLUGIN_TYPE_BUILTIN;
        }
-       if( plugin_type == PLUGIN_TYPE_UNKNOWN || plugin_type == PLUGIN_TYPE_LADSPA ) {
+       if( is_unknown() || is_ladspa() ) {
                lad_descriptor_function =
                        (LADSPA_Descriptor_Function) get_sym("ladspa_descriptor");
                if( lad_descriptor_function ) {
@@ -356,7 +372,7 @@ int PluginServer::open_plugin(int master,
                        plugin_type = PLUGIN_TYPE_LADSPA;
                }
        }
-       if( plugin_type == PLUGIN_TYPE_UNKNOWN ) {
+       if( is_unknown() ) {
                fprintf(stderr, "PluginServer::open_plugin "
                        " %d: plugin undefined in %s\n", __LINE__, path);
                return PLUGINSERVER_NOT_RECOGNIZED;
@@ -367,11 +383,14 @@ int PluginServer::open_plugin(int master,
        case PLUGIN_TYPE_BUILTIN:
                client = new_plugin(this);
                break;
+       case PLUGIN_TYPE_FFMPEG:
+               client = new_ffmpeg_plugin();
+               break;
        case PLUGIN_TYPE_LADSPA:
                client = new PluginAClientLAD(this);
                break;
-       case PLUGIN_TYPE_FFMPEG:
-               client = new_ffmpeg_plugin();
+       case PLUGIN_TYPE_LV2:
+               client = new_lv2_plugin();
                break;
        default:
                client = 0;
index da8e8bd1aa7e3c481bf28a3cf6cb47a49863220b..f2011af2488701440baefa5f278e0f3c1cf6c934 100644 (file)
@@ -95,6 +95,7 @@ class PluginServer
        int lad_index;
        LADSPA_Descriptor_Function lad_descriptor_function;
        const LADSPA_Descriptor *lad_descriptor;
+
        int use_opengl;
 // FFMPEG support
        const char *ff_name;
@@ -102,7 +103,7 @@ class PluginServer
        VideoDevice *vdevice;
 public:
        PluginServer();
-       PluginServer(MWindow *mwindow, char *path, int type);
+       PluginServer(MWindow *mwindow, const char *path, int type);
        PluginServer(PluginServer &);
        virtual ~PluginServer();
 
@@ -164,13 +165,19 @@ public:
        VFrame *get_picon();
        VFrame *get_plugin_images();
 
+       int is_unknown();
+       int is_executable();
+       int is_builtin();
+// ffmpeg
+       int is_ffmpeg();
+       PluginClient *new_ffmpeg_plugin();
 // ladspa
        void set_lad_index(int i);
        int get_lad_index();
        int is_ladspa();
-// ffmpeg
-       int is_ffmpeg();
-       PluginClient *new_ffmpeg_plugin();
+// lv2
+       int is_lv2();
+       PluginClient *new_lv2_plugin();
 // =============================== for realtime plugins
 // save configuration of plugin
        void save_data(KeyFrame *keyframe);
index d75cf8209ab7d6ee838441a46ea304bbc25c426d..8a93cca0e45ed737c4a5cba6f90881b458b77876 100644 (file)
 class PluginObj;
 class PluginServer;
 
-#define PLUGIN_LADSPA_ID 0
-#define PLUGIN_FFMPEG_ID 1
-#define PLUGIN_IDS 2
+#define PLUGIN_FFMPEG_ID 0
+#define PLUGIN_LADSPA_ID 1
+#define PLUGIN_LV2_ID 2
+#define PLUGIN_IDS 3
 
 #define PLUGIN_TYPE_UNKNOWN -1
 #define PLUGIN_TYPE_EXECUTABLE 0
 #define PLUGIN_TYPE_BUILTIN 1
-#define PLUGIN_TYPE_LADSPA 2
-#define PLUGIN_TYPE_FFMPEG 3
-#define PLUGIN_TYPES 4
+#define PLUGIN_TYPE_FFMPEG 2
+#define PLUGIN_TYPE_LADSPA 3
+#define PLUGIN_TYPE_LV2 4
+#define PLUGIN_TYPES 5
 
 #endif
index f9dd58c440d21691f35f159822abf0ed0015d764..84a983d7005266037a13f797932eeba6779d3b93 100644 (file)
@@ -32,6 +32,7 @@ CHECK_WITH([jobs],[parallel build jobs],[JOBS],[auto])
 CHECK_WITH([exec-name],[binary executable name],[CIN],[cin])
 CHECK_WITH([single-user],[to install cin in bin],[CINBIN_BUILD],[no])
 CHECK_WITH([ladspa-build],[build ladspa library],[LADSPA_BUILD],[yes])
+CHECK_WITH([lv2],[lv2 library support],[LV2],[yes])
 CHECK_WITH([cinlib],[cinelerra library path],[CINLIB_DIR],[auto])
 CHECK_WITH([cindat],[cinelerra share path],[CINDAT_DIR],[auto])
 CHECK_WITH([plugin-dir],[plugin install dir],[PLUGIN_DIR],[auto])
@@ -547,6 +548,16 @@ CHECK_WANT([LIBOPUS], [auto], [use libopus], [
  CHECK_LIB([opus], [opus], [opus_multistream_decoder_create])
  CHECK_HEADERS([opus], [libopus headers], [opus/opus_multistream.h])])
 
+CHECK_WANT([LV2], [auto], [use lv2], [
+ CHECK_LIB([lv2], [lilv-0], [lilv_world_new])
+ CHECK_LIB([sord], [sord-0], [sord_world_new])
+ CHECK_LIB([serd], [serd-0], [serd_reader_new])
+ CHECK_LIB([sratom], [sratom-0], [sratom_new])
+ saved_CFLAGS="$CXXFLAGS"
+ CFLAGS="-I/usr/include/lilv-0"
+ CHECK_HEADERS([lv2], [lilv headers], [lilv/lilv.h])
+ CFLAGS="$saved_CXXFLAGS"])
+
 CHECK_WANT([DL], [auto], [system has libdl], [
  CHECK_LIB([DL], [dl], [dlopen])])
 
@@ -695,7 +706,7 @@ AC_SUBST(SYSTEM_LIBS)
 
 echo ""
 for v in GL XFT XXF86VM OSS ALSA FIREWIRE DV DVB \
-        VIDEO4LINUX2 ESOUND PACTL OPENEXR; do
+        VIDEO4LINUX2 ESOUND PACTL OPENEXR LV2; do
   eval vv="\$WANT_$v"
   if test "x$vv" != "xno"; then
     CFG_CFLAGS+=" -DHAVE_$v"
@@ -741,6 +752,9 @@ if test "x$HAVE_opus" = "xyes"; then
   CFG_CFLAGS+=' -I/usr/include/opus'
   FFMPEG_EXTRA_CFG+=' --enable-libopus'
 fi
+if test "x$HAVE_lv2" = "xyes"; then
+  CFG_CFLAGS+=' -I/usr/include/lilv-0'
+fi
 
 AC_SUBST(EXTRA_LIBS)
 AC_SUBST(FFMPEG_EXTRA_CFG)