From 32294ae14f17c867a39f638112cbec12d59b32d6 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Mon, 7 May 2018 15:28:26 -0600 Subject: [PATCH] add lv2 plugin interface --- cinelerra-5.1/bld_scripts/bld_prepare.sh | 6 +- cinelerra-5.1/cinelerra/Makefile | 1 + cinelerra-5.1/cinelerra/awindowgui.C | 11 +- cinelerra-5.1/cinelerra/mwindow.C | 23 +- cinelerra-5.1/cinelerra/mwindow.h | 5 +- cinelerra-5.1/cinelerra/mwindow.inc | 2 +- cinelerra-5.1/cinelerra/pluginaclientlad.C | 35 +- cinelerra-5.1/cinelerra/pluginfclient.C | 2 +- cinelerra-5.1/cinelerra/pluginlv2client.C | 814 ++++++++++++++++++++ cinelerra-5.1/cinelerra/pluginlv2client.h | 226 ++++++ cinelerra-5.1/cinelerra/pluginlv2client.inc | 37 + cinelerra-5.1/cinelerra/pluginserver.C | 49 +- cinelerra-5.1/cinelerra/pluginserver.h | 15 +- cinelerra-5.1/cinelerra/pluginserver.inc | 14 +- cinelerra-5.1/configure.ac | 16 +- 15 files changed, 1197 insertions(+), 59 deletions(-) create mode 100644 cinelerra-5.1/cinelerra/pluginlv2client.C create mode 100644 cinelerra-5.1/cinelerra/pluginlv2client.h create mode 100644 cinelerra-5.1/cinelerra/pluginlv2client.inc diff --git a/cinelerra-5.1/bld_scripts/bld_prepare.sh b/cinelerra-5.1/bld_scripts/bld_prepare.sh index 028a0071..929095bc 100755 --- a/cinelerra-5.1/bld_scripts/bld_prepare.sh +++ b/cinelerra-5.1/bld_scripts/bld_prepare.sh @@ -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 \ diff --git a/cinelerra-5.1/cinelerra/Makefile b/cinelerra-5.1/cinelerra/Makefile index b9d23b7d..ee779981 100644 --- a/cinelerra-5.1/cinelerra/Makefile +++ b/cinelerra-5.1/cinelerra/Makefile @@ -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 \ diff --git a/cinelerra-5.1/cinelerra/awindowgui.C b/cinelerra-5.1/cinelerra/awindowgui.C index f33b9cbc..7e976569 100644 --- a/cinelerra-5.1/cinelerra/awindowgui.C +++ b/cinelerra-5.1/cinelerra/awindowgui.C @@ -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; isize(); ++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") diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index 6ad64376..243f29a9 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -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) { diff --git a/cinelerra-5.1/cinelerra/mwindow.h b/cinelerra-5.1/cinelerra/mwindow.h index 24210e41..8c251e28 100644 --- a/cinelerra-5.1/cinelerra/mwindow.h +++ b/cinelerra-5.1/cinelerra/mwindow.h @@ -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(); diff --git a/cinelerra-5.1/cinelerra/mwindow.inc b/cinelerra-5.1/cinelerra/mwindow.inc index ee6b8ab0..bf90324e 100644 --- a/cinelerra-5.1/cinelerra/mwindow.inc +++ b/cinelerra-5.1/cinelerra/mwindow.inc @@ -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 diff --git a/cinelerra-5.1/cinelerra/pluginaclientlad.C b/cinelerra-5.1/cinelerra/pluginaclientlad.C index f6228c3b..403ec7a8 100644 --- a/cinelerra-5.1/cinelerra/pluginaclientlad.C +++ b/cinelerra-5.1/cinelerra/pluginaclientlad.C @@ -21,8 +21,10 @@ #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 +#include + +#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=0 && idxopt = 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; iget_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; isym, 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; iitem_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; iitem_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; ititle); + 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; isym, 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; isym, 0.); + opt->set_value(value); + } + } +} + +void PluginLV2Client::connect_ports() +{ + int ich = 0, och = 0; + for( int i=0; iatom.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; iget_data(); + float *ip = in_buffers[i]; + for( int j=size; --j>=0; *ip++=*inp++ ); + } + for( int i=0; iget_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; iget_data(); + float *ip = in_buffers[i]; + for( int j=size; --j>=0; *ip++=*inp++ ); + } + for( int i=0; iget_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 index 00000000..a724ca77 --- /dev/null +++ b/cinelerra-5.1/cinelerra/pluginlv2client.h @@ -0,0 +1,226 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * 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 +#include +#include + +class PluginLV2UriTable : public ArrayList +{ +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 +{ +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 items[2]; + ArrayList &opts; + ArrayList &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 index 00000000..9a72a7e6 --- /dev/null +++ b/cinelerra-5.1/cinelerra/pluginlv2client.inc @@ -0,0 +1,37 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * 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 diff --git a/cinelerra-5.1/cinelerra/pluginserver.C b/cinelerra-5.1/cinelerra/pluginserver.C index 8feb6ed6..6e42e947 100644 --- a/cinelerra-5.1/cinelerra/pluginserver.C +++ b/cinelerra-5.1/cinelerra/pluginserver.C @@ -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; diff --git a/cinelerra-5.1/cinelerra/pluginserver.h b/cinelerra-5.1/cinelerra/pluginserver.h index da8e8bd1..f2011af2 100644 --- a/cinelerra-5.1/cinelerra/pluginserver.h +++ b/cinelerra-5.1/cinelerra/pluginserver.h @@ -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); diff --git a/cinelerra-5.1/cinelerra/pluginserver.inc b/cinelerra-5.1/cinelerra/pluginserver.inc index d75cf820..8a93cca0 100644 --- a/cinelerra-5.1/cinelerra/pluginserver.inc +++ b/cinelerra-5.1/cinelerra/pluginserver.inc @@ -25,15 +25,17 @@ 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 diff --git a/cinelerra-5.1/configure.ac b/cinelerra-5.1/configure.ac index f9dd58c4..84a983d7 100644 --- a/cinelerra-5.1/configure.ac +++ b/cinelerra-5.1/configure.ac @@ -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) -- 2.26.2