honor LV2 rsz:minimumSize for Atom Event buffers
authorRobin Gareus <robin@gareus.org>
Sun, 2 Jun 2013 22:48:17 +0000 (00:48 +0200)
committerRobin Gareus <robin@gareus.org>
Sun, 2 Jun 2013 22:48:17 +0000 (00:48 +0200)
libs/ardour/ardour/buffer_set.h
libs/ardour/ardour/lv2_plugin.h
libs/ardour/buffer_set.cc
libs/ardour/lv2_evbuf.c
libs/ardour/lv2_evbuf.h
libs/ardour/lv2_plugin.cc

index 1a1d5642886e33a0c885f07767b10640995ff420..12e9dbc63b0a99ddfcfad0c0961e3bf59fc08b33 100644 (file)
@@ -120,6 +120,9 @@ public:
         */
        LV2_Evbuf* get_lv2_midi(bool input, size_t i, bool old_api);
 
+       /** ensure minimum size of LV2 Atom port buffer */
+       void ensure_lv2_bufsize(bool input, size_t i, size_t buffer_capacity);
+
        /** Flush modified LV2 event output buffers back to Ardour buffers */
        void flush_lv2_midi(bool input, size_t i);
 
index d62ddb140ef6b4b92bc8a01c0b93b42d34d0658c..4cd34b30266ef6405c37a926c5089d5ec6480c81 100644 (file)
@@ -202,6 +202,7 @@ class LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
        typedef unsigned PortFlags;
 
        std::vector<PortFlags>         _port_flags;
+       std::vector<size_t>            _port_minimumSize;
        std::map<std::string,uint32_t> _port_indices;
 
        /// Message send to/from UI via ports
index c231a8f402722a104120c83cc1ecf8c474d1eef2..184e23d1afff57016e72ff0a0472c867ebbb863a 100644 (file)
@@ -252,6 +252,25 @@ BufferSet::get(DataType type, size_t i) const
 
 #ifdef LV2_SUPPORT
 
+void
+BufferSet::ensure_lv2_bufsize(bool input, size_t i, size_t buffer_capacity)
+{
+       assert(count().get(DataType::MIDI) > i);
+
+       LV2Buffers::value_type b     = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
+       LV2_Evbuf*             evbuf = b.second;
+
+       if (lv2_evbuf_get_capacity(evbuf) >= buffer_capacity) return;
+
+       lv2_evbuf_free(b.second);
+       _lv2_buffers.at(i * 2 + (input ? 0 : 1)) =
+               std::make_pair(false, lv2_evbuf_new(
+                                       buffer_capacity,
+                                       LV2_EVBUF_EVENT,
+                                       LV2Plugin::urids.atom_Chunk,
+                                       LV2Plugin::urids.atom_Sequence));
+}
+
 LV2_Evbuf*
 BufferSet::get_lv2_midi(bool input, size_t i, bool old_api)
 {
index 1cce8730a9f181793b79f5fbd9cba89c03be3378..8942d19a9b2b038cb2ad9599939508b051250375 100644 (file)
@@ -115,6 +115,12 @@ lv2_evbuf_get_size(LV2_Evbuf* evbuf)
        return 0;
 }
 
+uint32_t
+lv2_evbuf_get_capacity(LV2_Evbuf* evbuf)
+{
+       return evbuf->capacity;
+}
+
 void*
 lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
 {
index fdb7766f96f7ac710c3db72d5e94f7ec39e55122..3700be8e0288c3224001f056de892f6611e7ce91 100644 (file)
@@ -92,6 +92,12 @@ lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input);
 uint32_t
 lv2_evbuf_get_size(LV2_Evbuf* evbuf);
 
+/**
+   Return the available capacity of the buffer
+*/
+uint32_t
+lv2_evbuf_get_capacity(LV2_Evbuf* evbuf);
+
 /**
    Return the actual buffer implementation.
    The format of the buffer returned depends on the buffer type.
index 253961a11f1cd8f65ee16363395d421cea3d916e..a43dc3d4ecc2ba3e19dab43010d1aa58a11268a9 100644 (file)
@@ -61,6 +61,7 @@
 #include "lv2/lv2plug.in/ns/ext/state/state.h"
 #include "lv2/lv2plug.in/ns/ext/time/time.h"
 #include "lv2/lv2plug.in/ns/ext/worker/worker.h"
+#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
 #include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
 #ifdef HAVE_NEW_LV2
 #include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
@@ -132,6 +133,7 @@ public:
        LilvNode* lv2_toggled;
        LilvNode* midi_MidiEvent;
        LilvNode* rdfs_comment;
+       LilvNode* rsz_minimumSize;
        LilvNode* time_Position;
        LilvNode* ui_GtkUI;
        LilvNode* ui_external;
@@ -408,6 +410,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        for (uint32_t i = 0; i < num_ports; ++i) {
                const LilvPort* port  = lilv_plugin_get_port_by_index(_impl->plugin, i);
                PortFlags       flags = 0;
+               size_t          minimumSize = 0;
 
                if (lilv_port_is_a(_impl->plugin, port, _world.lv2_OutputPort)) {
                        flags |= PORT_OUTPUT;
@@ -442,6 +445,11 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                                        flags |= PORT_POSITION;
                                }
                        }
+                       LilvNode* min_size = lilv_port_get(_impl->plugin, port, _world.rsz_minimumSize);
+                       if (min_size && lilv_node_is_int(min_size)) {
+                               minimumSize = lilv_node_as_int(min_size);
+                       }
+                       lilv_node_free(min_size);
                        lilv_nodes_free(buffer_types);
                        lilv_nodes_free(atom_supports);
                } else {
@@ -452,6 +460,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                }
 
                _port_flags.push_back(flags);
+               _port_minimumSize.push_back(minimumSize);
        }
 
        _control_data = new float[num_ports];
@@ -1409,6 +1418,7 @@ LV2Plugin::allocate_atom_event_buffers()
         */
        int count_atom_out = 0;
        int count_atom_in = 0;
+       int minimumSize = 32768; // TODO use a per-port minimum-size
        for (uint32_t i = 0; i < lilv_plugin_get_num_ports(p); ++i) {
                const LilvPort* port  = lilv_plugin_get_port_by_index(p, i);
                if (lilv_port_is_a(p, port, _world.atom_AtomPort)) {
@@ -1425,6 +1435,10 @@ LV2Plugin::allocate_atom_event_buffers()
                                if (lilv_port_is_a(p, port, _world.lv2_OutputPort)) {
                                        count_atom_out++;
                                }
+                               LilvNode* min_size = lilv_port_get(_impl->plugin, port, _world.rsz_minimumSize);
+                               if (min_size && lilv_node_is_int(min_size)) {
+                                       minimumSize = std::max(minimumSize, lilv_node_as_int(min_size));
+                               }
                        }
                        lilv_nodes_free(buffer_types);
                        lilv_nodes_free(atom_supports);
@@ -1442,7 +1456,7 @@ LV2Plugin::allocate_atom_event_buffers()
        DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers\n", total_atom_buffers));
        _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(32768, LV2_EVBUF_ATOM,
+               _atom_ev_buffers[i] = lv2_evbuf_new(minimumSize, LV2_EVBUF_ATOM,
                                LV2Plugin::urids.atom_Chunk, LV2Plugin::urids.atom_Sequence);
        }
        _atom_ev_buffers[total_atom_buffers] = 0;
@@ -1551,6 +1565,12 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                        index = out_map.get(DataType::MIDI, midi_out_index++, &valid);
                                }
                                if (valid && bufs.count().n_midi() > index) {
+                                       /* Note, ensure_lv2_bufsize() is not RT safe!
+                                        * However free()/alloc() is only called if a
+                                        * plugin requires a rsz:minimumSize buffersize
+                                        * and the existing buffer if smaller.
+                                        */
+                                       bufs.ensure_lv2_bufsize((flags & PORT_INPUT), index, _port_minimumSize[port_index]);
                                        _ev_buffers[port_index] = bufs.get_lv2_midi(
                                                (flags & PORT_INPUT), index, (flags & PORT_EVENT));
                                }
@@ -1881,6 +1901,7 @@ LV2World::LV2World()
        lv2_enumeration    = lilv_new_uri(world, LV2_CORE__enumeration);
        midi_MidiEvent     = lilv_new_uri(world, LILV_URI_MIDI_EVENT);
        rdfs_comment       = lilv_new_uri(world, LILV_NS_RDFS "comment");
+       rsz_minimumSize    = lilv_new_uri(world, LV2_RESIZE_PORT__minimumSize);
        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");
@@ -1903,6 +1924,7 @@ LV2World::~LV2World()
        lilv_node_free(ext_logarithmic);
        lilv_node_free(ext_notOnGUI);
        lilv_node_free(ev_EventPort);
+       lilv_node_free(rsz_minimumSize);
        lilv_node_free(atom_eventTransfer);
        lilv_node_free(atom_bufferType);
        lilv_node_free(atom_Sequence);