summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/rt_midibuffer.h32
-rw-r--r--libs/ardour/disk_reader.cc1
-rw-r--r--libs/ardour/rt_midibuffer.cc176
3 files changed, 169 insertions, 40 deletions
diff --git a/libs/ardour/ardour/rt_midibuffer.h b/libs/ardour/ardour/rt_midibuffer.h
index 28d6e69233..da2c5c0e05 100644
--- a/libs/ardour/ardour/rt_midibuffer.h
+++ b/libs/ardour/ardour/rt_midibuffer.h
@@ -43,7 +43,7 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
RTMidiBuffer (size_t capacity);
~RTMidiBuffer();
- void clear() { _size = 0; }
+ void clear();
void resize(size_t);
size_t size() const { return _size; }
@@ -52,12 +52,36 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
void dump (uint32_t);
+ struct Item {
+ samplepos_t timestamp;
+ union {
+ uint8_t bytes[4];
+ uint32_t offset;
+ };
+ };
+
private:
+
+ struct Blob {
+ uint32_t size;
+ uint8_t data[0];
+ };
+
+ /* The main store. Holds Items (timestamp+up to 3 bytes of data OR
+ * offset into secondary storage below)
+ */
+
size_t _size;
size_t _capacity;
- uint8_t* _data; ///< event data
- typedef std::multimap<TimeType,size_t> Map;
- Map _map;
+ Item* _data;
+
+ /* secondary blob storage. Holds Blobs (arbitrary size + data) */
+
+ uint32_t alloc_blob (uint32_t size);
+ uint32_t store_blob (uint32_t size, uint8_t const * data);
+ uint32_t _pool_size;
+ uint32_t _pool_capacity;
+ uint8_t* _pool;
};
} // namespace ARDOUR
diff --git a/libs/ardour/disk_reader.cc b/libs/ardour/disk_reader.cc
index 44f2afc3e2..4cf0fbc53c 100644
--- a/libs/ardour/disk_reader.cc
+++ b/libs/ardour/disk_reader.cc
@@ -519,6 +519,7 @@ DiskReader::overwrite_existing_buffers ()
minsert.reset(); minsert.start();
_mbuf.clear(); midi_playlist()->dump (_mbuf, 0);
minsert.update(); cerr << "Reading " << name() << " took " << minsert.elapsed() << " microseconds, final size = " << _mbuf.size() << endl;
+ _mbuf.dump (40);
}
g_atomic_int_set (&_pending_overwrite, 0);
diff --git a/libs/ardour/rt_midibuffer.cc b/libs/ardour/rt_midibuffer.cc
index c2fec01e59..bd4a7e3d42 100644
--- a/libs/ardour/rt_midibuffer.cc
+++ b/libs/ardour/rt_midibuffer.cc
@@ -24,6 +24,8 @@
#include "pbd/debug.h"
#include "pbd/stacktrace.h"
+#include "evoral/midi_util.h"
+
#include "ardour/debug.h"
#include "ardour/midi_buffer.h"
#include "ardour/midi_state_tracker.h"
@@ -37,6 +39,9 @@ RTMidiBuffer::RTMidiBuffer (size_t capacity)
: _size (0)
, _capacity (0)
, _data (0)
+ , _pool_size (0)
+ , _pool_capacity (0)
+ , _pool (0)
{
if (capacity) {
resize (capacity);
@@ -46,6 +51,7 @@ RTMidiBuffer::RTMidiBuffer (size_t capacity)
RTMidiBuffer::~RTMidiBuffer()
{
cache_aligned_free (_data);
+ cache_aligned_free (_pool);
}
void
@@ -61,35 +67,49 @@ RTMidiBuffer::resize (size_t size)
return;
}
- uint8_t* old_data = _data;
+ Item* old_data = _data;
- cache_aligned_malloc ((void**) &_data, size);
+ cache_aligned_malloc ((void**) &_data, size * sizeof (Item));
if (_size) {
memcpy (_data, old_data, _size);
+ cache_aligned_free (old_data);
}
- cache_aligned_free (old_data);
_capacity = size;
-
- assert(_data);
}
void
RTMidiBuffer::dump (uint32_t cnt)
{
- for (Map::iterator iter = _map.begin(); iter != _map.end() && cnt; ++iter, --cnt) {
+ for (uint32_t i = 0; i < _size && i < cnt; ++i) {
+
+ Item* item = &_data[i];
+ uint8_t* addr;
+ uint32_t size;
+
+ if (item->bytes[0]) {
+
+ /* more than 3 bytes ... indirect */
+
+ uint32_t offset = item->offset & ~(1<<(sizeof(uint8_t)-1));
+ Blob* blob = reinterpret_cast<Blob*> (&_pool[offset]);
+
+ size = blob->size;
+ addr = blob->data;
+
+ } else {
- uint8_t* addr = &_data[iter->second];
- TimeType evtime = iter->first;
- uint32_t size = *(reinterpret_cast<Evoral::EventType*>(addr));
- addr += sizeof (size);
+ size = Evoral::midi_event_size (item->bytes[1]);
+ addr = &item->bytes[1];
- cerr << "@ " << evtime << " sz=" << size << '\t';
+ }
+
+ cerr << "@ " << item->timestamp << " sz=" << size << '\t';
cerr << hex;
- for (size_t i =0 ; i < size; ++i) {
- cerr << "0x" << hex << (int)addr[i] << dec << '/' << (int)addr[i] << ' ';
+ for (size_t j =0 ; j < size; ++j) {
+ cerr << "0x" << hex << (int)addr[j] << dec << '/' << (int)addr[i] << ' ';
}
cerr << dec << endl;
}
@@ -100,52 +120,75 @@ RTMidiBuffer::write (TimeType time, Evoral::EventType /*type*/, uint32_t size, c
{
/* This buffer stores only MIDI, we don't care about the value of "type" */
- const size_t bytes_to_merge = sizeof (size) + size;
+ const size_t bytes_to_merge = sizeof (time) + sizeof (uint32_t);
if (_size + bytes_to_merge > _capacity) {
resize (_capacity + 8192); // XXX 8192 is completely arbitrary
}
- _map.insert (make_pair (time, _size));
+ _data[_size].timestamp = time;
- uint8_t* addr = &_data[_size];
+ if (size > 3) {
- *(reinterpret_cast<uint32_t*>(addr)) = size;
- addr += sizeof (size);
- memcpy (addr, buf, size);
+ uint32_t off = store_blob (size, buf);
+
+ /* this indicates that the data (more than 3 bytes) is not inline */
+ _data[_size].offset = (off | (1<<(sizeof(uint8_t)-1)));
- _size += bytes_to_merge;
+ } else {
+
+ assert ((int) size == Evoral::midi_event_size (buf[0]));
+
+ /* this indicates that the data (up to 3 bytes) is inline */
+ _data[_size].bytes[0] = 0;
+
+ switch (size) {
+ case 3:
+ _data[_size].bytes[3] = buf[2];
+ /* fallthru */
+ case 2:
+ _data[_size].bytes[2] = buf[1];
+ /* fallthru */
+ case 1:
+ _data[_size].bytes[1] = buf[0];
+ break;
+ }
+ }
+
+ ++_size;
return size;
}
+static
+bool
+item_timestamp_earlier (ARDOUR::RTMidiBuffer::Item const & item, samplepos_t time)
+{
+ return item.timestamp < time;
+}
+
+
+
uint32_t
RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiStateTracker& tracker, samplecnt_t offset)
{
- Map::iterator iter = _map.lower_bound (start);
+ Item* iend = _data+_size;
+ Item* item = lower_bound (_data, iend, start, item_timestamp_earlier);
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)) {
+ DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("read from %1 .. %2 .. initial index = %3 (time = %4)\n", start, end, item, item->timestamp));
- /* 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.
- */
+ while ((item < iend) && (item->timestamp < end)) {
- uint8_t* addr = &_data[iter->second];
- TimeType evtime = iter->first;
+ TimeType evtime = item->timestamp;
#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.
*/
@@ -153,6 +196,26 @@ RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiSta
evtime -= start;
evtime += offset;
+ uint32_t size;
+ uint8_t* addr;
+
+ if (item->bytes[0]) {
+
+ /* more than 3 bytes ... indirect */
+
+ uint32_t offset = item->offset & ~(1<<(sizeof(uint8_t)-1));
+ Blob* blob = reinterpret_cast<Blob*> (&_pool[offset]);
+
+ size = blob->size;
+ addr = blob->data;
+
+ } else {
+
+ size = Evoral::midi_event_size (item->bytes[1]);
+ addr = &item->bytes[1];
+
+ }
+
uint8_t* write_loc = dst.reserve (evtime, size);
if (write_loc == 0) {
@@ -160,15 +223,56 @@ RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiSta
break;
}
- DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("read event sz %1 @ %2\n", size, unadjusted_time));
-
memcpy (write_loc, addr, size);
+
+ DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("read event sz %1 @ %2\n", size, unadjusted_time));
tracker.track (addr);
- ++iter;
+ ++item;
++count;
}
DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("total events found for %1 .. %2 = %3\n", start, end, count));
return count;
}
+
+uint32_t
+RTMidiBuffer::alloc_blob (uint32_t size)
+{
+ if (_pool_size + size > _pool_capacity) {
+ uint8_t* old_pool = _pool;
+
+ _pool_capacity += size * 4;
+
+ cache_aligned_malloc ((void **) &_pool, _pool_capacity * 2);
+ memcpy (_pool, old_pool, _pool_size);
+ cache_aligned_free (old_pool);
+ }
+
+ uint32_t offset = _pool_size;
+ _pool_size += size;
+
+ return offset;
+}
+
+uint32_t
+RTMidiBuffer::store_blob (uint32_t size, uint8_t const * data)
+{
+ uint32_t offset = alloc_blob (size);
+ uint8_t* addr = &_pool[offset];
+
+ *(reinterpret_cast<uint32_t*> (addr)) = size;
+ addr += sizeof (size);
+ memcpy (addr, data, size);
+
+ return offset;
+}
+
+void
+RTMidiBuffer::clear ()
+{
+ /* mark main array as empty */
+ _size = 0;
+ /* free the entire current pool size, if any */
+ _pool_size = 0;
+}