copy LV2 options to heap.
[ardour.git] / libs / ardour / lv2_plugin.cc
index c12e4930d5c5f00df4c35f65b2693a3d1f0cfc08..cd1c190c383b0810fb55a49f66222834d4a5f5f4 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,11 @@ public:
        LilvNode* units_midiNote;
        LilvNode* patch_writable;
        LilvNode* patch_Message;
+#ifdef HAVE_LV2_1_2_0
+       LilvNode* bufz_powerOf2BlockLength;
+       LilvNode* bufz_fixedBlockLength;
+       LilvNode* bufz_nominalBlockLength;
+#endif
 
 private:
        bool _bundle_checked;
@@ -234,7 +239,10 @@ 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)
+              , opts_iface(0)
               , state(0)
+              , block_length(0)
+              , options(0)
        {}
 
        /** Find the LV2 input port with the given designation.
@@ -242,16 +250,19 @@ struct LV2Plugin::Impl {
         */
        const LilvPort* designated_input (const char* uri, void** bufptrs[], void** bufptr);
 
-       const LilvPlugin*           plugin;
-       const LilvUI*               ui;
-       const LilvNode*             ui_type;
-       LilvNode*                   name;
-       LilvNode*                   author;
-       LilvInstance*               instance;
-       const LV2_Worker_Interface* work_iface;
-       LilvState*                  state;
-       LV2_Atom_Forge              forge;
-       LV2_Atom_Forge              ui_forge;
+       const LilvPlugin*            plugin;
+       const LilvUI*                ui;
+       const LilvNode*              ui_type;
+       LilvNode*                    name;
+       LilvNode*                    author;
+       LilvInstance*                instance;
+       const LV2_Worker_Interface*  work_iface;
+       const LV2_Options_Interface* opts_iface;
+       LilvState*                   state;
+       LV2_Atom_Forge               forge;
+       LV2_Atom_Forge               ui_forge;
+       int32_t                      block_length;
+       LV2_Options_Option*          options;
 };
 
 LV2Plugin::LV2Plugin (AudioEngine& engine,
@@ -309,11 +320,11 @@ 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.samples_per_cycle();
        _seq_size               = _engine.raw_buffer_size(DataType::MIDI);
        _state_version          = 0;
        _was_activated          = false;
        _has_state_interface    = false;
+       _impl->block_length     = _session.get_block_size();
 
        _instance_access_feature.URI = "http://lv2plug.in/ns/ext/instance-access";
        _data_access_feature.URI     = "http://lv2plug.in/ns/ext/data-access";
@@ -355,18 +366,32 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
 
 #ifdef HAVE_LV2_1_2_0
        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)
+       /* 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.
+        *
+        * given that the block-size can change at any time (split-cycles) ardour currently
+        * does not support plugins that require bufz_fixedBlockLength.
+        */
        LV2_Options_Option options[] = {
                { LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id(LV2_BUF_SIZE__minBlockLength),
-                 sizeof(int32_t), atom_Int, &_block_length },
+                 sizeof(int32_t), atom_Int, &_min_block_length },
                { LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id(LV2_BUF_SIZE__maxBlockLength),
-                 sizeof(int32_t), atom_Int, &_block_length },
+                 sizeof(int32_t), atom_Int, &_max_block_length },
                { LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id(LV2_BUF_SIZE__sequenceSize),
                  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, 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
 
@@ -415,15 +440,39 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        }
        lilv_node_free(worker_iface_uri);
 
+
+       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);
+
        if (lilv_plugin_has_feature(plugin, _world.lv2_inPlaceBroken)) {
                error << string_compose(
-                   _("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
+                   _("LV2: \"%1\" cannot be used, since it cannot do inplace processing."),
                    lilv_node_as_string(_impl->name)) << endmsg;
                lilv_node_free(_impl->name);
                lilv_node_free(_impl->author);
                throw failed_constructor();
        }
 
+#ifdef HAVE_LV2_1_2_0
+       LilvNodes *required_features = lilv_plugin_get_required_features (plugin);
+       if (lilv_nodes_contains (required_features, _world.bufz_powerOf2BlockLength) ||
+                       lilv_nodes_contains (required_features, _world.bufz_fixedBlockLength)
+          ) {
+               error << string_compose(
+                   _("LV2: \"%1\" buffer-size requirements cannot be satisfied."),
+                   lilv_node_as_string(_impl->name)) << endmsg;
+               lilv_node_free(_impl->name);
+               lilv_node_free(_impl->author);
+               lilv_nodes_free(required_features);
+               throw failed_constructor();
+       }
+       lilv_nodes_free(required_features);
+#endif
+
 #ifdef HAVE_LILV_0_16_0
        // Load default state
        LilvState* state = lilv_state_new_from_world(
@@ -608,6 +657,23 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        latency_compute_run();
 }
 
+int
+LV2Plugin::set_block_size (pframes_t nframes)
+{
+#ifdef HAVE_LV2_1_2_0
+       if (_impl->opts_iface) {
+               LV2_URID atom_Int = _uri_map.uri_to_id(LV2_ATOM__Int);
+               _impl->block_length = nframes;
+               LV2_Options_Option block_size_option = {
+                       LV2_OPTIONS_INSTANCE, 0, _uri_map.uri_to_id ("http://lv2plug.in/ns/ext/buf-size#nominalBlockLength"),
+                       sizeof(int32_t), atom_Int, (void*)&_impl->block_length
+               };
+               _impl->opts_iface->set (_impl->instance->lv2_handle, &block_size_option);
+       }
+#endif
+       return 0;
+}
+
 LV2Plugin::~LV2Plugin ()
 {
        DEBUG_TRACE(DEBUG::LV2, string_compose("%1 destroy\n", name()));
@@ -618,6 +684,7 @@ LV2Plugin::~LV2Plugin ()
        lilv_instance_free(_impl->instance);
        lilv_node_free(_impl->name);
        lilv_node_free(_impl->author);
+       free(_impl->options);
 
        free(_features);
        free(_make_path_feature.data);
@@ -638,6 +705,7 @@ LV2Plugin::~LV2Plugin ()
 
        delete [] _control_data;
        delete [] _shadow_data;
+       delete [] _defaults;
        delete [] _ev_buffers;
 }
 
@@ -1624,24 +1692,10 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                        plugin_dir(),
                        Glib::build_filename(prop->value(), "state.ttl"));
 
-               if (!Glib::file_test (state_file, Glib::FileTest (Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR))) {
-                       /* this should be done in lilv_state_new_from_file()
-                        * some systems don't like realpath() calls with an non-existent file.
-                        * (hopefully this fixes crashes on OSX 10.5/PPC, see #6456,
-                        * segfault in __asm realpath$DARWIN_EXTSN
-                        * if so, backport upstream to liblilv)
-                        */
-                       error << string_compose(
-                               "LV2: expected state file \"%1\" does not exist.",
-                               state_file) << endmsg;
-               } else {
-
-                       LilvState* state = lilv_state_new_from_file(
-                                       _world.world, _uri_map.urid_map(), NULL, state_file.c_str());
+               LilvState* state = lilv_state_new_from_file(
+                       _world.world, _uri_map.urid_map(), NULL, state_file.c_str());
 
-                       // lilv_state_restore allows/ignores possible NULL state
-                       lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL);
-               }
+               lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL);
        }
 
        latency_compute_run();
@@ -1922,7 +1976,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
        TempoMetric             tmetric  = tmap.metric_at(_session.transport_frame(), &metric_i);
 
        if (_freewheel_control_port) {
-               *_freewheel_control_port = _session.engine().freewheeling();
+               *_freewheel_control_port = _session.engine().freewheeling() ? 1.f : 0.f;
        }
 
        if (_bpm_control_port) {
@@ -2378,10 +2432,21 @@ 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);
+#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);
+       bufz_nominalBlockLength  = lilv_new_uri(world, "http://lv2plug.in/ns/ext/buf-size#nominalBlockLength");
+#endif
+
 }
 
 LV2World::~LV2World()
 {
+#ifdef HAVE_LV2_1_2_0
+       lilv_node_free(bufz_nominalBlockLength);
+       lilv_node_free(bufz_fixedBlockLength);
+       lilv_node_free(bufz_powerOf2BlockLength);
+#endif
        lilv_node_free(patch_Message);
        lilv_node_free(patch_writable);
        lilv_node_free(units_hz);
@@ -2504,6 +2569,29 @@ LV2PluginInfo::discover()
                        continue;
                }
 
+               if (lilv_plugin_has_feature(p, world.lv2_inPlaceBroken)) {
+                       warning << string_compose(
+                           _("Ignoring LV2 plugin \"%1\" since it cannot do inplace processing."),
+                           lilv_node_as_string(name)) << endmsg;
+                       lilv_node_free(name);
+                       continue;
+               }
+
+#ifdef HAVE_LV2_1_2_0
+               LilvNodes *required_features = lilv_plugin_get_required_features (p);
+               if (lilv_nodes_contains (required_features, world.bufz_powerOf2BlockLength) ||
+                               lilv_nodes_contains (required_features, world.bufz_fixedBlockLength)
+                  ) {
+                       warning << string_compose(
+                           _("Ignoring LV2 plugin \"%1\" because its buffer-size requirements cannot be satisfied."),
+                           lilv_node_as_string(name)) << endmsg;
+                       lilv_nodes_free(required_features);
+                       lilv_node_free(name);
+                       continue;
+               }
+               lilv_nodes_free(required_features);
+#endif
+
                info->type = LV2;
 
                info->name = string(lilv_node_as_string(name));