diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h index 1a1d564288..12e9dbc63b 100644 --- a/libs/ardour/ardour/buffer_set.h +++ b/libs/ardour/ardour/buffer_set.h @@ -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); diff --git a/libs/ardour/ardour/lv2_plugin.h b/libs/ardour/ardour/lv2_plugin.h index d62ddb140e..4cd34b3026 100644 --- a/libs/ardour/ardour/lv2_plugin.h +++ b/libs/ardour/ardour/lv2_plugin.h @@ -202,6 +202,7 @@ class LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee typedef unsigned PortFlags; std::vector _port_flags; + std::vector _port_minimumSize; std::map _port_indices; /// Message send to/from UI via ports diff --git a/libs/ardour/buffer_set.cc b/libs/ardour/buffer_set.cc index c231a8f402..184e23d1af 100644 --- a/libs/ardour/buffer_set.cc +++ b/libs/ardour/buffer_set.cc @@ -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) { diff --git a/libs/ardour/lv2_evbuf.c b/libs/ardour/lv2_evbuf.c index 1cce8730a9..8942d19a9b 100644 --- a/libs/ardour/lv2_evbuf.c +++ b/libs/ardour/lv2_evbuf.c @@ -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) { diff --git a/libs/ardour/lv2_evbuf.h b/libs/ardour/lv2_evbuf.h index fdb7766f96..3700be8e02 100644 --- a/libs/ardour/lv2_evbuf.h +++ b/libs/ardour/lv2_evbuf.h @@ -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. diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index 253961a11f..a43dc3d4ec 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -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);