fix errors in manual conflict resolution
[ardour.git] / libs / ardour / lv2_plugin.cc
index 6d4a71869f0c9105bd02060d3ed39dca8e02a0f7..33b02a76e3b2174958448b4e16505c2b7c293ebe 100644 (file)
 #include <cstdlib>
 #include <cstring>
 
-#include <giomm/file.h>
+#include <glib/gstdio.h>
 #include <glib/gprintf.h>
 #include <glibmm.h>
 
 #include <boost/utility.hpp>
 
+#include "pbd/clear_dir.h"
 #include "pbd/pathscanner.h"
 #include "pbd/compose.h"
 #include "pbd/error.h"
@@ -47,7 +48,7 @@
 #include "ardour/types.h"
 #include "ardour/utils.h"
 #include "ardour/worker.h"
-#include "ardour/lv2_bundled_search_path.h"
+#include "ardour/search_paths.h"
 
 #include "i18n.h"
 #include <locale.h>
@@ -142,6 +143,9 @@ public:
        LilvNode* time_Position;
        LilvNode* ui_GtkUI;
        LilvNode* ui_external;
+       LilvNode* ui_externalkx;
+       LilvNode* units_unit;
+       LilvNode* units_midiNote;
 
 private:
        bool _bundle_checked;
@@ -289,7 +293,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        _latency_control_port   = 0;
        _next_cycle_start       = std::numeric_limits<framepos_t>::max();
        _next_cycle_speed       = 1.0;
-       _block_length           = _engine.frames_per_cycle();
+       _block_length           = _engine.samples_per_cycle();
        _seq_size               = _engine.raw_buffer_size(DataType::MIDI);
        _state_version          = 0;
        _was_activated          = false;
@@ -561,11 +565,15 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                if (!_impl->ui) {
                        LILV_FOREACH(uis, i, uis) {
                                const LilvUI* ui = lilv_uis_get(uis, i);
-                               if (lilv_ui_is_a(ui, _world.ui_external)) {
+                               if (lilv_ui_is_a(ui, _world.ui_externalkx)) {
                                        _impl->ui      = ui;
                                        _impl->ui_type = _world.ui_external;
                                        break;
                                }
+                               if (lilv_ui_is_a(ui, _world.ui_external)) {
+                                       _impl->ui      = ui;
+                                       _impl->ui_type = _world.ui_external;
+                               }
                        }
                }
        }
@@ -613,7 +621,16 @@ LV2Plugin::is_external_ui() const
        if (!_impl->ui) {
                return false;
        }
-       return lilv_ui_is_a(_impl->ui, _world.ui_external);
+       return lilv_ui_is_a(_impl->ui, _world.ui_external) || lilv_ui_is_a(_impl->ui, _world.ui_externalkx);
+}
+
+bool
+LV2Plugin::is_external_kx() const
+{
+       if (!_impl->ui) {
+               return false;
+       }
+       return lilv_ui_is_a(_impl->ui, _world.ui_externalkx);
 }
 
 bool
@@ -864,27 +881,6 @@ LV2Plugin::lv2_state_make_path(LV2_State_Make_Path_Handle handle,
        return g_strndup(abs_path.c_str(), abs_path.length());
 }
 
-static void
-remove_directory(const std::string& path)
-{
-       if (!Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
-               warning << string_compose("\"%1\" is not a directory", path) << endmsg;
-               return;
-       }
-
-       Glib::RefPtr<Gio::File>           dir = Gio::File::create_for_path(path);
-       Glib::RefPtr<Gio::FileEnumerator> e   = dir->enumerate_children();
-       Glib::RefPtr<Gio::FileInfo>       fi;
-       while ((fi = e->next_file())) {
-               if (fi->get_type() == Gio::FILE_TYPE_DIRECTORY) {
-                       remove_directory(fi->get_name());
-               } else {
-                       dir->get_child(fi->get_name())->remove();
-               }
-       }
-       dir->remove();
-}
-
 void
 LV2Plugin::add_state(XMLNode* root) const
 {
@@ -936,7 +932,7 @@ LV2Plugin::add_state(XMLNode* root) const
                } else {
                        // State is identical, decrement version and nuke directory
                        lilv_state_free(state);
-                       remove_directory(new_dir);
+                       PBD::remove_directory(new_dir);
                        --_state_version;
                }
 
@@ -970,7 +966,7 @@ LV2Plugin::find_presets()
                                                               lilv_node_as_string(name))));
                } else {
                        warning << string_compose(
-                           _("Plugin \"%1\% preset \"%2%\" is missing a label\n"),
+                           _("Plugin \"%1\" preset \"%2\" is missing a label\n"),
                            lilv_node_as_string(lilv_plugin_get_uri(_impl->plugin)),
                            lilv_node_as_string(preset)) << endmsg;
                }
@@ -1010,6 +1006,7 @@ LV2Plugin::load_preset(PresetRecord r)
        if (state) {
                lilv_state_restore(state, _impl->instance, set_port_value, this, 0, NULL);
                lilv_state_free(state);
+               Plugin::load_preset(r);
        }
 
        lilv_node_free(pset);
@@ -1077,7 +1074,14 @@ LV2Plugin::do_save_preset(string name)
 
        lilv_state_free(state);
 
-       return Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
+       std::string uri = Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
+       LilvNode *node_bundle = lilv_new_uri(_world.world, Glib::filename_to_uri(Glib::build_filename(bundle, "/")).c_str());
+       LilvNode *node_preset = lilv_new_uri(_world.world, uri.c_str());
+       lilv_world_load_bundle(_world.world, node_bundle);
+       lilv_world_load_resource(_world.world, node_preset);
+       lilv_node_free(node_bundle);
+       lilv_node_free(node_preset);
+       return uri;
 }
 
 void
@@ -1090,7 +1094,7 @@ LV2Plugin::do_remove_preset(string name)
                        name + ".ttl"
                )
        );
-       unlink(preset_file.c_str());
+       ::g_unlink(preset_file.c_str());
 }
 
 bool
@@ -1118,16 +1122,16 @@ LV2Plugin::write_to(RingBuffer<uint8_t>* dest,
                     uint32_t             size,
                     const uint8_t*       body)
 {
-       const uint32_t buf_size = sizeof(UIMessage) + size;
-       uint8_t        buf[buf_size];
+       const uint32_t  buf_size = sizeof(UIMessage) + size;
+       vector<uint8_t> buf(buf_size);
 
-       UIMessage* msg = (UIMessage*)buf;
+       UIMessage* msg = (UIMessage*)&buf[0];
        msg->index    = index;
        msg->protocol = protocol;
        msg->size     = size;
        memcpy(msg + 1, body, size);
 
-       return (dest->write(buf, buf_size) == buf_size);
+       return (dest->write(&buf[0], buf_size) == buf_size);
 }
 
 bool
@@ -1137,8 +1141,24 @@ LV2Plugin::write_from_ui(uint32_t       index,
                          const uint8_t* body)
 {
        if (!_from_ui) {
-               _from_ui = new RingBuffer<uint8_t>(
-                       _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS);
+               size_t rbs = _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS;
+               /* buffer data communication from plugin UI to plugin instance.
+                * this buffer needs to potentially hold
+                *   (port's minimumSize) * (audio-periods) / (UI-periods)
+                * bytes.
+                *
+                *  e.g 48kSPS / 128fpp -> audio-periods = 375 Hz
+                *  ui-periods = 25 Hz (SuperRapidScreenUpdate)
+                *  default minimumSize = 32K (see LV2Plugin::allocate_atom_event_buffers()
+                *
+                * it is NOT safe to overflow (msg.size will be misinterpreted)
+                */
+               uint32_t bufsiz = 32768;
+               if (_atom_ev_buffers && _atom_ev_buffers[0]) {
+                       bufsiz =  lv2_evbuf_get_capacity(_atom_ev_buffers[0]);
+               }
+               rbs = max((size_t) bufsiz * 8, rbs);
+               _from_ui = new RingBuffer<uint8_t>(rbs);
        }
 
        if (!write_to(_from_ui, index, protocol, size, body)) {
@@ -1165,8 +1185,14 @@ void
 LV2Plugin::enable_ui_emmission()
 {
        if (!_to_ui) {
-               _to_ui = new RingBuffer<uint8_t>(
-                       _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS);
+               /* see note in LV2Plugin::write_from_ui() */
+               uint32_t bufsiz = 32768;
+               if (_atom_ev_buffers && _atom_ev_buffers[0]) {
+                       bufsiz =  lv2_evbuf_get_capacity(_atom_ev_buffers[0]);
+               }
+               size_t rbs = _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS;
+               rbs = max((size_t) bufsiz * 8, rbs);
+               _to_ui = new RingBuffer<uint8_t>(rbs);
        }
 }
 
@@ -1184,13 +1210,13 @@ LV2Plugin::emit_to_ui(void* controller, UIMessageSink sink)
                        error << "Error reading from Plugin=>UI RingBuffer" << endmsg;
                        break;
                }
-               uint8_t body[msg.size];
-               if (_to_ui->read(body, msg.size) != msg.size) {
+               vector<uint8_t> body(msg.size);
+               if (_to_ui->read(&body[0], msg.size) != msg.size) {
                        error << "Error reading from Plugin=>UI RingBuffer" << endmsg;
                        break;
                }
 
-               sink(controller, msg.index, msg.size, msg.protocol, body);
+               sink(controller, msg.index, msg.size, msg.protocol, &body[0]);
 
                read_space -= sizeof(msg) + msg.size;
        }
@@ -1233,6 +1259,8 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                return -1;
        }
 
+#ifndef NO_PLUGIN_STATE
+
        if (version < 3000) {
                nodes = node.children("port");
        } else {
@@ -1288,6 +1316,7 @@ LV2Plugin::set_state(const XMLNode& node, int version)
        }
 
        latency_compute_run();
+#endif
 
        return Plugin::set_state(node, version);
 }
@@ -1297,8 +1326,10 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c
 {
        const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, which);
 
+       LilvNodes* portunits;
        LilvNode *def, *min, *max;
        lilv_port_get_range(_impl->plugin, port, &def, &min, &max);
+       portunits = lilv_port_get_value(_impl->plugin, port, _world.units_unit);
 
        desc.integer_step = lilv_port_has_property(_impl->plugin, port, _world.lv2_integer);
        desc.toggled      = lilv_port_has_property(_impl->plugin, port, _world.lv2_toggled);
@@ -1307,6 +1338,8 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c
        desc.label        = lilv_node_as_string(lilv_port_get_name(_impl->plugin, port));
        desc.lower        = min ? lilv_node_as_float(min) : 0.0f;
        desc.upper        = max ? lilv_node_as_float(max) : 1.0f;
+       desc.midinote     = lilv_nodes_contains(portunits, _world.units_midiNote);
+
        if (desc.sr_dependent) {
                desc.lower *= _session.frame_rate ();
                desc.upper *= _session.frame_rate ();
@@ -1331,6 +1364,7 @@ LV2Plugin::get_parameter_descriptor(uint32_t which, ParameterDescriptor& desc) c
        lilv_node_free(def);
        lilv_node_free(min);
        lilv_node_free(max);
+       lilv_nodes_free(portunits);
 
        return 0;
 }
@@ -1350,11 +1384,6 @@ LV2Plugin::describe_parameter(Evoral::Parameter which)
                        return X_("hidden");
                }
 
-               if (lilv_port_has_property(_impl->plugin,
-                                       lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_sampleRate)) {
-                       return X_("hidden");
-               }
-
                if (lilv_port_has_property(_impl->plugin,
                                        lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_reportsLatency)) {
                        return X_("latency");
@@ -1475,7 +1504,7 @@ LV2Plugin::allocate_atom_event_buffers()
                return;
        }
 
-       DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers\n", total_atom_buffers));
+       DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers of %d bytes\n", total_atom_buffers, minimumSize));
        _atom_ev_buffers = (LV2_Evbuf**) malloc((total_atom_buffers + 1) * sizeof(LV2_Evbuf*));
        for (int i = 0; i < total_atom_buffers; ++i ) {
                _atom_ev_buffers[i] = lv2_evbuf_new(minimumSize, LV2_EVBUF_ATOM,
@@ -1648,7 +1677,10 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                }
                        } else if (!valid) {
                                // Nothing we understand or care about, connect to scratch
-                               _ev_buffers[port_index] = silent_bufs.get_lv2_midi(
+                               // see note for midi-buffer size above
+                               scratch_bufs.ensure_lv2_bufsize((flags & PORT_INPUT),
+                                               0, _port_minimumSize[port_index]);
+                               _ev_buffers[port_index] = scratch_bufs.get_lv2_midi(
                                        (flags & PORT_INPUT), 0, (flags & PORT_EVENT));
                        }
                        buf = lv2_evbuf_get_buffer(_ev_buffers[port_index]);
@@ -1667,15 +1699,15 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
                                break;
                        }
-                       uint8_t body[msg.size];
-                       if (_from_ui->read(body, msg.size) != msg.size) {
+                       vector<uint8_t> body(msg.size);
+                       if (_from_ui->read(&body[0], msg.size) != msg.size) {
                                error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
                                break;
                        }
                        if (msg.protocol == urids.atom_eventTransfer) {
                                LV2_Evbuf*            buf  = _ev_buffers[msg.index];
                                LV2_Evbuf_Iterator    i    = lv2_evbuf_end(buf);
-                               const LV2_Atom* const atom = (const LV2_Atom*)body;
+                               const LV2_Atom* const atom = (const LV2_Atom*)&body[0];
                                if (!lv2_evbuf_write(&i, nframes, 0, atom->type, atom->size,
                                                (const uint8_t*)(atom + 1))) {
                                        error << "Failed to write data to LV2 event buffer\n";
@@ -1898,7 +1930,7 @@ LV2Plugin::Impl::designated_input (const char* uri, void** bufptrs[], void** buf
        return port;
 }
 
-static bool lv2_filter (const string& str, void *arg)
+static bool lv2_filter (const string& str, void* /*arg*/)
 {
        /* Not a dotfile, has a prefix before a period, suffix is "lv2" */
        
@@ -1938,10 +1970,16 @@ LV2World::LV2World()
        time_Position      = lilv_new_uri(world, LV2_TIME__Position);
        ui_GtkUI           = lilv_new_uri(world, LV2_UI__GtkUI);
        ui_external        = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external");
+       ui_externalkx      = lilv_new_uri(world, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget");
+       units_unit         = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#unit");
+       units_midiNote     = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#midiNote");
 }
 
 LV2World::~LV2World()
 {
+       lilv_node_free(units_midiNote);
+       lilv_node_free(units_unit);
+       lilv_node_free(ui_externalkx);
        lilv_node_free(ui_external);
        lilv_node_free(ui_GtkUI);
        lilv_node_free(time_Position);
@@ -1979,17 +2017,19 @@ LV2World::load_bundled_plugins()
                vector<string *> *plugin_objects = scanner (ARDOUR::lv2_bundled_search_path().to_string(), lv2_filter, 0, true, true);
                if (plugin_objects) {
                        for ( vector<string *>::iterator x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
-#ifdef WINDOWS
-                                       string uri = "file:///" + **x + "/";
+#ifdef PLATFORM_WINDOWS
+                               string uri = "file:///" + **x + "/";
 #else
-                                       string uri = "file://" + **x + "/";
+                               string uri = "file://" + **x + "/";
 #endif
-                                       LilvNode *node = lilv_new_uri(world, uri.c_str());
-                                       lilv_world_load_bundle(world, node);
-                                       lilv_node_free(node);
-                               }
+                               LilvNode *node = lilv_new_uri(world, uri.c_str());
+                               lilv_world_load_bundle(world, node);
+                               lilv_node_free(node);
                        }
+               }
                delete (plugin_objects);
+
+               _bundle_checked = true;
        }
 }
 
@@ -2029,7 +2069,9 @@ LV2PluginInfo::discover()
        PluginInfoList*    plugs   = new PluginInfoList;
        const LilvPlugins* plugins = lilv_world_get_all_plugins(_world.world);
 
-       info << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endmsg;
+       if (!Config->get_show_plugin_scan_window()) {
+               info << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endmsg;
+       }
 
        LILV_FOREACH(plugins, i, plugins) {
                const LilvPlugin* p = lilv_plugins_get(plugins, i);
@@ -2047,6 +2089,7 @@ LV2PluginInfo::discover()
 
                info->name = string(lilv_node_as_string(name));
                lilv_node_free(name);
+               ARDOUR::PluginScanMessage(_("LV2"), info->name, false);
 
                const LilvPluginClass* pclass = lilv_plugin_get_class(p);
                const LilvNode*        label  = lilv_plugin_class_get_label(pclass);