outline a "NoSampleAccurateControl" LV2 feature:
[ardour.git] / libs / ardour / lv2_plugin.cc
index 13241f2a8bea8392ab2e9a58df5a888fea468c7f..940ec8ae0389ac49a47057a89da98f5550fb2f0a 100644 (file)
@@ -25,7 +25,7 @@
 #include <cstdlib>
 #include <cstring>
 
-#include <glib/gstdio.h>
+#include "pbd/gstdio_compat.h"
 #include <glib/gprintf.h>
 #include <glibmm.h>
 
@@ -155,6 +155,7 @@ public:
        LilvNode* units_midiNote;
        LilvNode* patch_writable;
        LilvNode* patch_Message;
+       LilvNode* lv2_noSampleAccurateCtrl;
 #ifdef HAVE_LV2_1_2_0
        LilvNode* bufz_powerOf2BlockLength;
        LilvNode* bufz_fixedBlockLength;
@@ -239,9 +240,14 @@ log_printf(LV2_Log_Handle handle,
 struct LV2Plugin::Impl {
        Impl() : plugin(0), ui(0), ui_type(0), name(0), author(0), instance(0)
               , work_iface(0)
+#ifdef HAVE_LV2_1_2_0
               , opts_iface(0)
+#endif
               , state(0)
               , block_length(0)
+#ifdef HAVE_LV2_1_2_0
+              , options(0)
+#endif
        {}
 
        /** Find the LV2 input port with the given designation.
@@ -256,11 +262,16 @@ struct LV2Plugin::Impl {
        LilvNode*                    author;
        LilvInstance*                instance;
        const LV2_Worker_Interface*  work_iface;
+#ifdef HAVE_LV2_1_2_0
        const LV2_Options_Interface* opts_iface;
+#endif
        LilvState*                   state;
        LV2_Atom_Forge               forge;
        LV2_Atom_Forge               ui_forge;
        int32_t                      block_length;
+#ifdef HAVE_LV2_1_2_0
+       LV2_Options_Option*          options;
+#endif
 };
 
 LV2Plugin::LV2Plugin (AudioEngine& engine,
@@ -276,6 +287,7 @@ LV2Plugin::LV2Plugin (AudioEngine& engine,
        , _patch_port_in_index((uint32_t)-1)
        , _patch_port_out_index((uint32_t)-1)
        , _uri_map(URIMap::instance())
+       , _no_sample_accurate_ctrl (false)
 {
        init(c_plugin, rate);
 }
@@ -290,6 +302,7 @@ LV2Plugin::LV2Plugin (const LV2Plugin& other)
        , _patch_port_in_index((uint32_t)-1)
        , _patch_port_out_index((uint32_t)-1)
        , _uri_map(URIMap::instance())
+       , _no_sample_accurate_ctrl (false)
 {
        init(other._impl->plugin, other._sample_rate);
 
@@ -385,8 +398,11 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, NULL }
        };
 
+       _impl->options = (LV2_Options_Option*) malloc (sizeof (options));
+       memcpy ((void*) _impl->options, (void*) options, sizeof (options));
+
        _options_feature.URI    = LV2_OPTIONS__options;
-       _options_feature.data   = options;
+       _options_feature.data   = _impl->options;
        _features[n_features++] = &_options_feature;
 #endif
 
@@ -436,12 +452,14 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        lilv_node_free(worker_iface_uri);
 
 
+#ifdef HAVE_LV2_1_2_0
        LilvNode* options_iface_uri = lilv_new_uri(_world.world, LV2_OPTIONS__interface);
        if (lilv_plugin_has_extension_data(plugin, options_iface_uri)) {
                _impl->opts_iface = (const LV2_Options_Interface*)extension_data(
                        LV2_OPTIONS__interface);
        }
        lilv_node_free(options_iface_uri);
+#endif
 
        if (lilv_plugin_has_feature(plugin, _world.lv2_inPlaceBroken)) {
                error << string_compose(
@@ -466,6 +484,12 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                throw failed_constructor();
        }
        lilv_nodes_free(required_features);
+
+       LilvNodes* optional_features = lilv_plugin_get_optional_features (plugin);
+       if (lilv_nodes_contains (optional_features, _world.lv2_noSampleAccurateCtrl)) {
+               _no_sample_accurate_ctrl = true;
+       }
+       lilv_nodes_free(optional_features);
 #endif
 
 #ifdef HAVE_LILV_0_16_0
@@ -475,6 +499,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        if (state && _has_state_interface) {
                lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL);
        }
+       lilv_state_free(state);
 #endif
 
        _sample_rate = rate;
@@ -669,6 +694,25 @@ LV2Plugin::set_block_size (pframes_t nframes)
        return 0;
 }
 
+bool
+LV2Plugin::requires_fixed_sized_buffers () const
+{
+       /* This controls if Ardour will split the plugin's run()
+        * on automation events in order to pass sample-accurate automation
+        * via standard control-ports.
+        *
+        * When returning true Ardour will *not* sub-divide the process-cycle.
+        * Automation events that happen between cycle-start and cycle-end will be
+        * ignored (ctrl values are interpolated to cycle-start).
+        * NB. Atom Sequences are still sample accurate.
+        *
+        * Note: This does not guarantee a fixed block-size.
+        * e.g The process cycle may be split when looping, also
+        * the period-size may change any time: see set_block_size()
+        */
+       return _no_sample_accurate_ctrl;
+}
+
 LV2Plugin::~LV2Plugin ()
 {
        DEBUG_TRACE(DEBUG::LV2, string_compose("%1 destroy\n", name()));
@@ -677,8 +721,12 @@ LV2Plugin::~LV2Plugin ()
        cleanup();
 
        lilv_instance_free(_impl->instance);
+       lilv_state_free(_impl->state);
        lilv_node_free(_impl->name);
        lilv_node_free(_impl->author);
+#ifdef HAVE_LV2_1_2_0
+       free(_impl->options);
+#endif
 
        free(_features);
        free(_make_path_feature.data);
@@ -699,6 +747,7 @@ LV2Plugin::~LV2Plugin ()
 
        delete [] _control_data;
        delete [] _shadow_data;
+       delete [] _defaults;
        delete [] _ev_buffers;
 }
 
@@ -974,7 +1023,7 @@ LV2Plugin::add_state(XMLNode* root) const
        assert(_insert_id != PBD::ID("0"));
 
        XMLNode*    child;
-       char        buf[16];
+       char        buf[32];
        LocaleGuard lg(X_("C"));
 
        for (uint32_t i = 0; i < parameter_count(); ++i) {
@@ -1689,6 +1738,8 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                        _world.world, _uri_map.urid_map(), NULL, state_file.c_str());
 
                lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL);
+               lilv_state_free(_impl->state);
+               _impl->state = state;
        }
 
        latency_compute_run();
@@ -2377,7 +2428,7 @@ LV2Plugin::Impl::designated_input (const char* uri, void** bufptrs[], void** buf
 static bool lv2_filter (const string& str, void* /*arg*/)
 {
        /* Not a dotfile, has a prefix before a period, suffix is "lv2" */
-       
+
        return str[0] != '.' && (str.length() > 3 && str.find (".lv2") == (str.length() - 4));
 }
 
@@ -2425,6 +2476,7 @@ LV2World::LV2World()
        units_db           = lilv_new_uri(world, LV2_UNITS__db);
        patch_writable     = lilv_new_uri(world, LV2_PATCH__writable);
        patch_Message      = lilv_new_uri(world, LV2_PATCH__Message);
+       lv2_noSampleAccurateCtrl = lilv_new_uri(world, LV2_CORE_PREFIX "NoSampleAccurateCtrl"); // XXX
 #ifdef HAVE_LV2_1_2_0
        bufz_powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
        bufz_fixedBlockLength    = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
@@ -2440,6 +2492,7 @@ LV2World::~LV2World()
        lilv_node_free(bufz_fixedBlockLength);
        lilv_node_free(bufz_powerOf2BlockLength);
 #endif
+       lilv_node_free(lv2_noSampleAccurateCtrl);
        lilv_node_free(patch_Message);
        lilv_node_free(patch_writable);
        lilv_node_free(units_hz);
@@ -2538,6 +2591,17 @@ LV2PluginInfo::load(Session& session)
        return PluginPtr();
 }
 
+bool
+LV2PluginInfo::in_category (const std::string &c) const
+{
+       // TODO use untranslated lilv_plugin_get_class()
+       // match gtk2_ardour/plugin_selector.cc
+       if (category == c) {
+               return true;
+       }
+       return false;
+}
+
 PluginInfoList*
 LV2PluginInfo::discover()
 {