NO-OP: whitespace
[ardour.git] / libs / ardour / lv2_plugin.cc
index 46c80d56580c1210e5fa1a2e334046eef807ab47..974ed87c2d9f7bd925d028fed43d39d6bd077088 100644 (file)
@@ -37,6 +37,7 @@
 #include "pbd/compose.h"
 #include "pbd/error.h"
 #include "pbd/locale_guard.h"
+#include "pbd/pthread_utils.h"
 #include "pbd/replace_all.h"
 #include "pbd/xml++.h"
 
 #include "pbd/windows_special_dirs.h"
 #endif
 
+#ifdef WAF_BUILD
 #include "libardour-config.h"
+#endif
 
 #include "ardour/audio_buffer.h"
 #include "ardour/audioengine.h"
+#include "ardour/directory_names.h"
 #include "ardour/debug.h"
 #include "ardour/lv2_plugin.h"
 #include "ardour/midi_patch_manager.h"
@@ -367,6 +371,7 @@ LV2Plugin::LV2Plugin (AudioEngine& engine,
        , _no_sample_accurate_ctrl (false)
 {
        init(c_plugin, rate);
+       latency_compute_run();
 }
 
 LV2Plugin::LV2Plugin (const LV2Plugin& other)
@@ -384,10 +389,16 @@ LV2Plugin::LV2Plugin (const LV2Plugin& other)
 {
        init(other._impl->plugin, other._sample_rate);
 
+       XMLNode root (other.state_node_name ());
+       other.add_state (&root);
+       set_state (root, Stateful::loading_state_version);
+
        for (uint32_t i = 0; i < parameter_count(); ++i) {
                _control_data[i] = other._shadow_data[i];
                _shadow_data[i]  = other._shadow_data[i];
        }
+
+       latency_compute_run();
 }
 
 void
@@ -414,7 +425,9 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
        _was_activated          = false;
        _has_state_interface    = false;
        _can_write_automation   = false;
+#ifdef LV2_EXTENDED
        _inline_display_in_gui  = false;
+#endif
        _max_latency            = 0;
        _current_latency        = 0;
        _impl->block_length     = _session.get_block_size();
@@ -490,6 +503,8 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
        LV2_URID atom_Int = _uri_map.uri_to_id(LV2_ATOM__Int);
        static const int32_t _min_block_length = 1;   // may happen during split-cycles
        static const int32_t _max_block_length = 8192; // max possible (with all engines and during export)
+       static const int32_t rt_policy = PBD_SCHED_FIFO;
+       static const int32_t rt_priority = pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority () - 2);
        /* Consider updating max-block-size whenever the buffersize changes.
         * It requires re-instantiating the plugin (which is a non-realtime operation),
         * so it should be done lightly and only for plugins that require it.
@@ -506,6 +521,10 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
                  sizeof(int32_t), atom_Int, &_seq_size },
                { LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id("http://lv2plug.in/ns/ext/buf-size#nominalBlockLength"),
                  sizeof(int32_t), atom_Int, &_impl->block_length },
+               { LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id("http://ardour.org/lv2/threads/#schedPolicy"),
+                 sizeof(int32_t), atom_Int, &rt_policy },
+               { LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id("http://ardour.org/lv2/threads/#schedPriority"),
+                 sizeof(int32_t), atom_Int, &rt_priority },
                { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, NULL }
        };
 
@@ -641,7 +660,6 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
        lilv_nodes_free(optional_features);
 #endif
 
-#ifdef HAVE_LILV_0_16_0
        // Load default state
        if (_worker) {
                /* immediately schedule any work,
@@ -656,7 +674,6 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
                lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL);
        }
        lilv_state_free(state);
-#endif
 
        _sample_rate = rate;
 
@@ -807,6 +824,8 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
                                if (params[i]) {
                                        *params[i] = (void*)&_shadow_data[i];
                                }
+                       } else {
+                               _shadow_data[i] = 0;
                        }
                } else {
                        _defaults[i] = 0.0f;
@@ -863,7 +882,6 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
 
        load_supported_properties(_property_descriptors);
        allocate_atom_event_buffers();
-       latency_compute_run();
 }
 
 int
@@ -1376,13 +1394,20 @@ LV2Plugin::add_state(XMLNode* root) const
                unsigned int saved_state = _state_version;;
                g_mkdir_with_parents(new_dir.c_str(), 0744);
 
+               std::string xternal_dir = _session.externals_dir ();
+
+               if (!_plugin_state_dir.empty()) {
+                       xternal_dir = Glib::build_filename (_plugin_state_dir, externals_dir_name);
+                       g_mkdir_with_parents(xternal_dir.c_str(), 0744);
+               }
+
                LilvState* state = lilv_state_new_from_instance(
                        _impl->plugin,
                        _impl->instance,
                        _uri_map.urid_map(),
                        scratch_dir().c_str(),
                        file_dir().c_str(),
-                       _session.externals_dir().c_str(),
+                       xternal_dir.c_str(),
                        new_dir.c_str(),
                        NULL,
                        const_cast<LV2Plugin*>(this),
@@ -1412,6 +1437,7 @@ LV2Plugin::add_state(XMLNode* root) const
                        } else {
                                // template save (dedicated state-dir)
                                lilv_state_free(state);
+                               g_rmdir (xternal_dir.c_str()); // try remove unused dir
                                --_state_version;
                        }
                } else {
@@ -1426,38 +1452,39 @@ LV2Plugin::add_state(XMLNode* root) const
        }
 }
 
-// TODO: Once we can rely on lilv 0.16.0, lilv_world_get can replace this
 static LilvNode*
 get_value(LilvWorld* world, const LilvNode* subject, const LilvNode* predicate)
 {
-       LilvNodes* vs = lilv_world_find_nodes(world, subject, predicate, NULL);
-       if (vs) {
-               LilvNode* node = lilv_node_duplicate(lilv_nodes_get_first(vs));
-               lilv_nodes_free(vs);
-               return node;
-       }
-       return NULL;
+       return lilv_world_get(world, subject, predicate, NULL);
 }
 
 void
 LV2Plugin::find_presets()
 {
+       /* see also LV2PluginInfo::get_presets */
        LilvNode* lv2_appliesTo = lilv_new_uri(_world.world, LV2_CORE__appliesTo);
        LilvNode* pset_Preset   = lilv_new_uri(_world.world, LV2_PRESETS__Preset);
        LilvNode* rdfs_label    = lilv_new_uri(_world.world, LILV_NS_RDFS "label");
+       LilvNode* rdfs_comment  = lilv_new_uri(_world.world, LILV_NS_RDFS "comment");
 
        LilvNodes* presets = lilv_plugin_get_related(_impl->plugin, pset_Preset);
        LILV_FOREACH(nodes, i, presets) {
                const LilvNode* preset = lilv_nodes_get(presets, i);
                lilv_world_load_resource(_world.world, preset);
                LilvNode* name = get_value(_world.world, preset, rdfs_label);
-               bool userpreset = true; // TODO
+               LilvNode* comment = get_value(_world.world, preset, rdfs_comment);
+               /* TODO properly identify user vs factory presets.
+                * here's an indirect condition: only factory presets can have comments
+                */
+               bool userpreset = comment ? false : true;
                if (name) {
                        _presets.insert(std::make_pair(lilv_node_as_string(preset),
                                                       Plugin::PresetRecord(
                                                               lilv_node_as_string(preset),
                                                               lilv_node_as_string(name),
-                                                              userpreset)));
+                                                              userpreset,
+                                                              comment ? lilv_node_as_string (comment) : ""
+                                                      )));
                        lilv_node_free(name);
                } else {
                        warning << string_compose(
@@ -1465,9 +1492,13 @@ LV2Plugin::find_presets()
                            lilv_node_as_string(lilv_plugin_get_uri(_impl->plugin)),
                            lilv_node_as_string(preset)) << endmsg;
                }
+               if (comment) {
+                       lilv_node_free(comment);
+               }
        }
        lilv_nodes_free(presets);
 
+       lilv_node_free(rdfs_comment);
        lilv_node_free(rdfs_label);
        lilv_node_free(pset_Preset);
        lilv_node_free(lv2_appliesTo);
@@ -1571,7 +1602,6 @@ LV2Plugin::do_save_preset(string name)
                Glib::build_filename(".lv2", prefix + "_" + base_name + ".lv2"));
 #endif
 
-#ifdef HAVE_LILV_0_21_3
        /* delete reference to old preset (if any) */
        const PresetRecord* r = preset_by_label(name);
        if (r) {
@@ -1581,7 +1611,6 @@ LV2Plugin::do_save_preset(string name)
                        lilv_node_free(pset);
                }
        }
-#endif
 
        LilvState* state = lilv_state_new_from_instance(
                _impl->plugin,
@@ -1613,10 +1642,8 @@ LV2Plugin::do_save_preset(string 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());
-#ifdef HAVE_LILV_0_21_3
        lilv_world_unload_resource(_world.world, node_preset);
        lilv_world_unload_bundle(_world.world, node_bundle);
-#endif
        lilv_world_load_bundle(_world.world, node_bundle);
        lilv_world_load_resource(_world.world, node_preset);
        lilv_node_free(node_bundle);
@@ -1628,7 +1655,6 @@ LV2Plugin::do_save_preset(string name)
 void
 LV2Plugin::do_remove_preset(string name)
 {
-#ifdef HAVE_LILV_0_21_3
        /* Look up preset record by label (FIXME: ick, label as ID) */
        const PresetRecord* r = preset_by_label(name);
        if (!r) {
@@ -1654,11 +1680,6 @@ LV2Plugin::do_remove_preset(string name)
 
        lilv_state_free(state);
        lilv_node_free(pset);
-#endif
-       /* Without lilv_state_delete(), we could delete the preset file, but this
-          would leave a broken bundle/manifest around, so the preset would still
-          be visible, but broken.  Naively deleting a bundle is too dangerous, so
-          we simply do not support preset deletion with older Lilv */
 }
 
 bool
@@ -1979,6 +2000,16 @@ LV2Plugin::load_supported_properties(PropertyDescriptors& descs)
        lilv_nodes_free(properties);
 }
 
+Variant
+LV2Plugin::get_property_value (uint32_t prop_id) const
+{
+       std::map<uint32_t, Variant>::const_iterator it;
+       if ((it = _property_values.find (prop_id)) == _property_values.end()) {
+               return Variant();
+       }
+       return it->second;
+}
+
 void
 LV2Plugin::announce_property_values()
 {
@@ -2166,7 +2197,17 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                set_state_dir ("");
        }
 
-       latency_compute_run();
+       /* Do not call latency_compute_run() concurrently with connect_and_run().
+        * So far this can only guarnteed when the session is loading,
+        * and the plugin has not been added to the processor chain.
+        *
+        * Ideally this would clso be called when copying a plugin from another track,
+        * but NOT when copying the state from a plugin to another (active) plugin
+        * instance.
+        */
+       if (_session.loading ()) {
+               latency_compute_run();
+       }
 #endif
 
        return Plugin::set_state(node, version);
@@ -2321,18 +2362,22 @@ LV2Plugin::describe_parameter(Evoral::Parameter which)
 {
        if (( which.type() == PluginAutomation) && ( which.id() < parameter_count()) ) {
 
-               if (lilv_port_has_property(_impl->plugin,
-                                       lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.ext_notOnGUI)) {
+               const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, which.id());
+
+               if (lilv_port_has_property(_impl->plugin, port, _world.ext_notOnGUI)) {
+                       return X_("hidden");
+               }
+
+               const LilvPort* fwport = lilv_plugin_get_port_by_designation(_impl->plugin, _world.lv2_InputPort, _world.lv2_freewheeling);
+               if (fwport && fwport == port) {
                        return X_("hidden");
                }
 
-               if (lilv_port_has_property(_impl->plugin,
-                                       lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_freewheeling)) {
+               if (lilv_port_has_property(_impl->plugin, port, _world.lv2_freewheeling)) {
                        return X_("hidden");
                }
 
-               if (lilv_port_has_property(_impl->plugin,
-                                       lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_reportsLatency)) {
+               if (lilv_port_has_property(_impl->plugin, port, _world.lv2_reportsLatency)) {
                        return X_("latency");
                }
 
@@ -2353,7 +2398,7 @@ LV2Plugin::max_latency () const
 }
 
 samplecnt_t
-LV2Plugin::signal_latency() const
+LV2Plugin::plugin_latency() const
 {
        if (_latency_control_port) {
                return (samplecnt_t)floor(*_latency_control_port);
@@ -2508,7 +2553,7 @@ write_position(LV2_Atom_Forge*     forge,
        LV2_Atom_Forge_Frame sample;
 #ifdef HAVE_LV2_1_10_0
        lv2_atom_forge_object(forge, &sample, 0, urids.time_Position);
-       lv2_atom_forge_key(forge, urids.time_sample);
+       lv2_atom_forge_key(forge, urids.time_frame);
        lv2_atom_forge_long(forge, position);
        lv2_atom_forge_key(forge, urids.time_speed);
        lv2_atom_forge_float(forge, speed);
@@ -2525,7 +2570,7 @@ write_position(LV2_Atom_Forge*     forge,
        lv2_atom_forge_float(forge, bpm);
 #else
        lv2_atom_forge_blank(forge, &sample, 1, urids.time_Position);
-       lv2_atom_forge_property_head(forge, urids.time_sample, 0);
+       lv2_atom_forge_property_head(forge, urids.time_frame, 0);
        lv2_atom_forge_long(forge, position);
        lv2_atom_forge_property_head(forge, urids.time_speed, 0);
        lv2_atom_forge_float(forge, speed);
@@ -2551,7 +2596,7 @@ write_position(LV2_Atom_Forge*     forge,
 int
 LV2Plugin::connect_and_run(BufferSet& bufs,
                samplepos_t start, samplepos_t end, double speed,
-               ChanMapping in_map, ChanMapping out_map,
+               ChanMapping const& in_map, ChanMapping const& out_map,
                pframes_t nframes, samplecnt_t offset)
 {
        DEBUG_TRACE(DEBUG::LV2, string_compose("%1 run %2 offset %3\n", name(), nframes, offset));
@@ -2927,6 +2972,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                                                // Emit PropertyChanged signal for UI
                                                                // TODO: This should emit the control's Changed signal
                                                                PropertyChanged(prop_id, Variant(Variant::PATH, path));
+                                                               _property_values[prop_id] = Variant(Variant::PATH, path);
                                                        } else {
                                                                std::cerr << "warning: patch:Set for unknown property" << std::endl;
                                                        }
@@ -3030,18 +3076,6 @@ LV2Plugin::designated_bypass_port ()
        return UINT32_MAX;
 }
 
-void
-LV2Plugin::print_parameter(uint32_t param, char* buf, uint32_t len) const
-{
-       if (buf && len) {
-               if (param < parameter_count()) {
-                       snprintf(buf, len, "%.3f", get_parameter(param));
-               } else {
-                       strcat(buf, "0");
-               }
-       }
-}
-
 boost::shared_ptr<ScalePoints>
 LV2Plugin::get_scale_points(uint32_t port_index) const
 {
@@ -3389,19 +3423,28 @@ LV2PluginInfo::get_presets (bool /*user_only*/) const
        LilvNode* lv2_appliesTo = lilv_new_uri(_world.world, LV2_CORE__appliesTo);
        LilvNode* pset_Preset   = lilv_new_uri(_world.world, LV2_PRESETS__Preset);
        LilvNode* rdfs_label    = lilv_new_uri(_world.world, LILV_NS_RDFS "label");
+       LilvNode* rdfs_comment  = lilv_new_uri(_world.world, LILV_NS_RDFS "comment");
 
        LilvNodes* presets = lilv_plugin_get_related(lp, pset_Preset);
        LILV_FOREACH(nodes, i, presets) {
                const LilvNode* preset = lilv_nodes_get(presets, i);
                lilv_world_load_resource(_world.world, preset);
                LilvNode* name = get_value(_world.world, preset, rdfs_label);
-               bool userpreset = true; // TODO
+               LilvNode* comment = get_value(_world.world, preset, rdfs_comment);
+               /* TODO properly identify user vs factory presets.
+                * here's an indirect condition: only factory presets can have comments
+                */
+               bool userpreset = comment ? false : true;
                if (name) {
-                       p.push_back (Plugin::PresetRecord (lilv_node_as_string(preset), lilv_node_as_string(name), userpreset));
+                       p.push_back (Plugin::PresetRecord (lilv_node_as_string(preset), lilv_node_as_string(name), userpreset, comment ? lilv_node_as_string (comment) : ""));
                        lilv_node_free(name);
                }
+               if (comment) {
+                       lilv_node_free(comment);
+               }
        }
        lilv_nodes_free(presets);
+       lilv_node_free(rdfs_comment);
        lilv_node_free(rdfs_label);
        lilv_node_free(pset_Preset);
        lilv_node_free(lv2_appliesTo);
@@ -3409,31 +3452,6 @@ LV2PluginInfo::get_presets (bool /*user_only*/) const
        return p;
 }
 
-bool
-LV2PluginInfo::in_category (const std::string &c) const
-{
-       // TODO use untranslated lilv_plugin_get_class()
-       // match gtk2_ardour/plugin_selector.cc
-       return category == c;
-}
-
-bool
-LV2PluginInfo::is_instrument () const
-{
-       if (category == "Instrument") {
-               return true;
-       }
-#if 1
-       /* until we make sure that category remains untranslated in the lv2.ttl spec
-        * and until most instruments also classify themselves as such, there's a 2nd check:
-        */
-       if (n_inputs.n_midi() > 0 && n_inputs.n_audio() == 0 && n_outputs.n_audio() > 0) {
-               return true;
-       }
-#endif
-       return false;
-}
-
 PluginInfoList*
 LV2PluginInfo::discover()
 {