summaryrefslogtreecommitdiff
path: root/libs/ardour/rt_midibuffer.cc
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2019-10-14 19:00:32 -0600
committerPaul Davis <paul@linuxaudiosystems.com>2019-11-02 16:32:18 -0600
commit22da779322e742775eb8d1e22bdf8c16f20c16b2 (patch)
tree61327a4f3df2ff393600f78b4573a35d833dbea1 /libs/ardour/rt_midibuffer.cc
parentcc949232fe39c4c0a8a0775ab9fc9284df3fb39a (diff)
introduce new all-in-RAM MIDI datastructure and use it for MIDI playback
Diffstat (limited to 'libs/ardour/rt_midibuffer.cc')
-rw-r--r--libs/ardour/rt_midibuffer.cc154
1 files changed, 154 insertions, 0 deletions
diff --git a/libs/ardour/rt_midibuffer.cc b/libs/ardour/rt_midibuffer.cc
new file mode 100644
index 0000000000..a440c7bb6f
--- /dev/null
+++ b/libs/ardour/rt_midibuffer.cc
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 Paul Davis <paul@linuxaudiosystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <iostream>
+
+#include "pbd/malign.h"
+#include "pbd/compose.h"
+#include "pbd/error.h"
+#include "pbd/debug.h"
+#include "pbd/stacktrace.h"
+
+#include "ardour/debug.h"
+#include "ardour/midi_buffer.h"
+#include "ardour/rt_midibuffer.h"
+
+using namespace std;
+using namespace ARDOUR;
+using namespace PBD;
+
+RTMidiBuffer::RTMidiBuffer (size_t capacity)
+ : _size (0)
+ , _capacity (0)
+ , _data (0)
+{
+ if (capacity) {
+ resize (capacity);
+ clear ();
+ }
+}
+
+RTMidiBuffer::~RTMidiBuffer()
+{
+ cache_aligned_free (_data);
+}
+
+void
+RTMidiBuffer::resize (size_t size)
+{
+ if (_data && size < _capacity) {
+
+ if (_size < size) {
+ /* truncate */
+ _size = size;
+ }
+
+ return;
+ }
+
+ uint8_t* old_data = _data;
+
+ cache_aligned_malloc ((void**) &_data, size);
+
+ if (_size) {
+ memcpy (_data, old_data, _size);
+ }
+
+ cache_aligned_free (old_data);
+ _capacity = size;
+
+ assert(_data);
+}
+
+uint32_t
+RTMidiBuffer::write (TimeType time, Evoral::EventType /*type*/, uint32_t size, const uint8_t* buf)
+{
+ /* This buffer stores only MIDI, we don't care about the value of "type" */
+
+ const size_t bytes_to_merge = sizeof (size) + size;
+
+ if (_size + bytes_to_merge > _capacity) {
+ resize (_capacity + 8192); // XXX 8192 is completely arbitrary
+ }
+
+ _map.insert (make_pair (time, _size));
+
+ uint8_t* addr = &_data[_size];
+
+ *(reinterpret_cast<uint32_t*>(addr)) = size;
+ addr += sizeof (size);
+ memcpy (addr, buf, size);
+
+ _size += bytes_to_merge;
+
+ return size;
+}
+
+uint32_t
+RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, samplecnt_t offset)
+{
+ Map::iterator iter = _map.lower_bound (start);
+ uint32_t count = 0;
+#ifndef NDEBUG
+ TimeType unadjusted_time;
+#endif
+
+ DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("read from %1 .. %2\n", start, end));
+
+ while ((iter != _map.end()) && (iter->first < end)) {
+
+ /* the event consists of a size followed by bytes of MIDI
+ * data. It begins at _data[iter->second], which was stored in
+ * our map when we wrote the event into the data structure.
+ */
+
+ uint8_t* addr = &_data[iter->second];
+ TimeType evtime = iter->first;
+
+#ifndef NDEBUG
+ unadjusted_time = evtime;
+#endif
+ uint32_t size = *(reinterpret_cast<Evoral::EventType*>(addr));
+ addr += sizeof (size);
+
+ /* Adjust event times to be relative to 'start', taking
+ * 'offset' into account.
+ */
+
+ evtime -= start;
+ evtime += offset;
+
+ uint8_t* write_loc = dst.reserve (evtime, size);
+
+ if (write_loc == 0) {
+ DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events, dst size = %2\n", count, dst.size()));
+ cerr << string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events, dst size = %1\n", count, dst.size()) << endl;
+ break;
+ }
+
+ DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("read event sz %1 @ %2\n", size, unadjusted_time));
+
+ memcpy (write_loc, addr, size);
+
+ ++iter;
+ ++count;
+ }
+
+ DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("total events found for %1 .. %2 = %3\n", start, end, count));
+ return count;
+}