#include <sstream>
#include "pbd/compose.h"
+#include "pbd/failed_constructor.h"
#include "ardour/buffer.h"
#include "ardour/buffer_set.h"
#ifdef LV2_SUPPORT
#include "ardour/lv2_plugin.h"
#include "lv2_evbuf.h"
+#include "ardour/uri_map.h"
#endif
-#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT
+#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
#include "ardour/vestige/aeffectx.h"
#endif
_count.reset();
_available.reset();
-#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT
+#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
for (VSTBuffers::iterator i = _vst_buffers.begin(); i != _vst_buffers.end(); ++i) {
delete *i;
}
_vst_buffers.clear ();
#endif
+#ifdef LV2_SUPPORT
+ for (LV2Buffers::iterator i = _lv2_buffers.begin(); i != _lv2_buffers.end(); ++i) {
+ free ((*i).second);
+ }
+ _lv2_buffers.clear ();
+#endif
+
}
/** Set up this BufferSet so that its data structures mirror a PortSet's buffers.
* This is quite expensive and not RT-safe, so it should not be called in a process context;
- * get_jack_port_addresses() will fill in a structure set up by this method.
+ * get_backend_port_addresses() will fill in a structure set up by this method.
*
* XXX: this *is* called in a process context; I'm not sure quite what `should not' means above.
*/
_is_mirror = true;
}
-/** Write the JACK port addresses from a PortSet into our data structures. This
+/** Write the backend port addresses from a PortSet into our data structures. This
* call assumes that attach_buffers() has already been called for the same PortSet.
* Does not allocate, so RT-safe BUT you can only call Port::get_buffer() from
* the process() callback tree anyway, so this has to be called in RT context.
*/
void
-BufferSet::get_jack_port_addresses (PortSet& ports, framecnt_t nframes)
+BufferSet::get_backend_port_addresses (PortSet& ports, framecnt_t nframes)
{
assert (_count == ports.count ());
assert (_available == ports.count ());
// If there's not enough or they're too small, just nuke the whole thing and
// rebuild it (so I'm lazy..)
if (bufs.size() < num_buffers
- || (bufs.size() > 0 && bufs[0]->capacity() < buffer_capacity)) {
+ || (bufs.size() > 0 && bufs[0]->capacity() < buffer_capacity)) {
// Nuke it
for (BufferVec::iterator i = bufs.begin(); i != bufs.end(); ++i) {
_lv2_buffers.push_back(
std::make_pair(false, lv2_evbuf_new(buffer_capacity,
LV2_EVBUF_EVENT,
- LV2Plugin::_chunk_type,
- LV2Plugin::_sequence_type)));
+ URIMap::instance().urids.atom_Chunk,
+ URIMap::instance().urids.atom_Sequence)));
}
}
#endif
-#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT
+#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
// As above but for VST
if (type == DataType::MIDI) {
while (_vst_buffers.size() < _buffers[type].size()) {
#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,
+ URIMap::instance().urids.atom_Chunk,
+ URIMap::instance().urids.atom_Sequence));
+}
+
LV2_Evbuf*
BufferSet::get_lv2_midi(bool input, size_t i, bool old_api)
{
assert(count().get(DataType::MIDI) > i);
- MidiBuffer& mbuf = get_midi(i);
LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
LV2_Evbuf* evbuf = b.second;
- lv2_evbuf_set_type(evbuf, old_api ? LV2_EVBUF_EVENT : LV2_EVBUF_ATOM);
+ lv2_evbuf_set_type(evbuf, old_api ? LV2_EVBUF_EVENT : LV2_EVBUF_ATOM);
lv2_evbuf_reset(evbuf, input);
- if (input) {
- DEBUG_TRACE(PBD::DEBUG::LV2,
- string_compose("%1 bytes of MIDI waiting @ %2\n",
- mbuf.size(), (void*) mbuf.data()));
-
- LV2_Evbuf_Iterator i = lv2_evbuf_begin(evbuf);
- const uint32_t type = LV2Plugin::midi_event_type(old_api);
- for (MidiBuffer::iterator e = mbuf.begin(); e != mbuf.end(); ++e) {
- const Evoral::MIDIEvent<framepos_t> ev(*e, false);
-#ifndef NDEBUG
- DEBUG_TRACE(PBD::DEBUG::LV2,
- string_compose("\tMIDI event of size %1 @ %2\n",
- ev.size(), ev.time()));
- for (uint16_t x = 0; x < ev.size(); ++x) {
- std::stringstream ss;
- ss << "\t\tev[" << x << "] = " << std::hex << (int) ev.buffer()[x] << std::dec << std::endl;
- DEBUG_TRACE (PBD::DEBUG::LV2, ss.str());
- }
-#endif
- lv2_evbuf_write(&i, ev.time(), 0, type, ev.size(), ev.buffer());
+ return evbuf;
+}
+
+void
+BufferSet::forward_lv2_midi(LV2_Evbuf* buf, size_t i, bool purge_ardour_buffer)
+{
+ MidiBuffer& mbuf = get_midi(i);
+ if (purge_ardour_buffer) {
+ mbuf.silence(0, 0);
+ }
+ for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(buf);
+ lv2_evbuf_is_valid(i);
+ i = lv2_evbuf_next(i)) {
+ uint32_t frames, subframes, type, size;
+ uint8_t* data;
+ lv2_evbuf_get(i, &frames, &subframes, &type, &size, &data);
+ if (type == URIMap::instance().urids.midi_MidiEvent) {
+ mbuf.push_back(frames, size, data);
}
}
- return evbuf;
}
void
DEBUG_TRACE (PBD::DEBUG::LV2, string_compose ("\tByte[%1] = %2\n", x, (int) data[x]));
}
#endif
- mbuf.push_back(frames, size, data);
+ if (type == URIMap::instance().urids.midi_MidiEvent) {
+ // TODO: Make Ardour event buffers generic so plugins can communicate
+ mbuf.push_back(frames, size, data);
+ }
}
}
#endif /* LV2_SUPPORT */
-#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT
+#if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
VstEvents*
BufferSet::get_vst_midi (size_t b)
{
MidiBuffer& m = get_midi (b);
+ assert (b <= _vst_buffers.size());
VSTBuffer* vst = _vst_buffers[b];
vst->clear ();
}
BufferSet::VSTBuffer::VSTBuffer (size_t c)
- : _capacity (c)
+ : _events (0)
+ , _midi_events (0)
+ , _capacity (c)
{
- _events = static_cast<VstEvents*> (malloc (sizeof (VstEvents) + _capacity * sizeof (VstEvent *)));
- _midi_events = static_cast<VstMidiEvent*> (malloc (sizeof (VstMidiEvent) * _capacity));
+ if (_capacity > 0) {
+ /* from `man malloc`: "If size is 0, then malloc() returns either NULL, or a
+ * unique pointer value that can later be successfully passed to free()."
+ *
+ * The latter will cause trouble here.
+ */
+ _events = static_cast<VstEvents*> (malloc (sizeof (VstEvents) + _capacity * sizeof (VstEvent *)));
+ _midi_events = static_cast<VstMidiEvent*> (malloc (sizeof (VstMidiEvent) * _capacity));
+ }
if (_events == 0 || _midi_events == 0) {
free (_events);
free (_midi_events);
+ _events = 0;
+ _midi_events = 0;
throw failed_constructor ();
}
}
void
-BufferSet::VSTBuffer::push_back (Evoral::MIDIEvent<framepos_t> const & ev)
+BufferSet::VSTBuffer::push_back (Evoral::Event<framepos_t> const & ev)
{
if (ev.size() > 3) {
/* XXX: this will silently drop MIDI messages longer than 3 bytes, so
*/
return;
}
- int const n = _events->numEvents;
- assert (n < (int) _capacity);
+ uint32_t const n = _events->numEvents;
+ assert (n < _capacity);
+ if (n >= _capacity) {
+ return;
+ }
_events->events[n] = reinterpret_cast<VstEvent*> (_midi_events + n);
VstMidiEvent* v = reinterpret_cast<VstMidiEvent*> (_events->events[n]);
}
}
-void
-BufferSet::set_is_silent (bool yn)
-{
- for (std::vector<BufferVec>::iterator i = _buffers.begin(); i != _buffers.end(); ++i) {
- for (BufferVec::iterator b = i->begin(); b != i->end(); ++b) {
- (*b)->set_is_silent (yn);
- }
- }
-
-}
-
} // namespace ARDOUR