templatize RTMidiBuffer to allow use in different time domains
Also add ::track_state() method to configue a MidiStateTracker to correspond to the state implied by an RTMidiBuffer<T,D> at a given point in time.
This commit is contained in:
parent
b693d07fcb
commit
a4a277c141
@ -40,7 +40,8 @@ class MidiNoteTracker;
|
||||
class MidiStateTracker;
|
||||
|
||||
/** */
|
||||
class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
|
||||
template<typename TimeType, typename DistanceType>
|
||||
class LIBARDOUR_API RTMidiBufferBase : public Evoral::EventSink<TimeType>
|
||||
{
|
||||
private:
|
||||
struct Blob {
|
||||
@ -49,28 +50,26 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
|
||||
};
|
||||
|
||||
public:
|
||||
typedef samplepos_t TimeType;
|
||||
|
||||
RTMidiBuffer ();
|
||||
~RTMidiBuffer();
|
||||
RTMidiBufferBase ();
|
||||
~RTMidiBufferBase ();
|
||||
|
||||
void clear();
|
||||
void resize(size_t);
|
||||
size_t size() const { return _size; }
|
||||
bool empty() const { return _size == 0; }
|
||||
|
||||
samplecnt_t span() const;
|
||||
DistanceType span() const;
|
||||
|
||||
uint32_t write (TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf);
|
||||
uint32_t read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiNoteTracker& tracker, samplecnt_t offset = 0);
|
||||
void track (MidiStateTracker&, samplepos_t start, samplepos_t end);
|
||||
uint32_t read (MidiBuffer& dst, TimeType start, TimeType end, MidiNoteTracker& tracker, DistanceType offset = 0);
|
||||
void track (MidiStateTracker&, TimeType start, TimeType end);
|
||||
|
||||
void dump (uint32_t);
|
||||
void reverse ();
|
||||
bool reversed() const;
|
||||
|
||||
struct Item {
|
||||
samplepos_t timestamp;
|
||||
TimeType timestamp;
|
||||
union {
|
||||
uint8_t bytes[4];
|
||||
uint32_t offset;
|
||||
@ -84,7 +83,7 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
|
||||
return _data[n];
|
||||
}
|
||||
|
||||
uint8_t const * bytes (Item const & item, uint32_t& size) {
|
||||
uint8_t const * bytes (Item const & item, uint32_t& size) const {
|
||||
if (!item.bytes[0]) {
|
||||
size = Evoral::midi_event_size (item.bytes[1]);
|
||||
return &item.bytes[1];
|
||||
@ -97,7 +96,11 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
|
||||
}
|
||||
}
|
||||
|
||||
void shift (sampleoffset_t distance) {
|
||||
/* XXX this really requires a 3rd template argument for a potentially
|
||||
* negative offset
|
||||
*/
|
||||
|
||||
void shift (DistanceType distance) {
|
||||
if (_size == 0) {
|
||||
return;
|
||||
}
|
||||
@ -106,6 +109,8 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
|
||||
}
|
||||
}
|
||||
|
||||
void track_state (TimeType when, MidiStateTracker& mst) const;
|
||||
|
||||
private:
|
||||
friend struct WriteProtectRender;
|
||||
|
||||
@ -130,7 +135,7 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
|
||||
public:
|
||||
class WriteProtectRender {
|
||||
public:
|
||||
WriteProtectRender (RTMidiBuffer& rtm) : lm (rtm._lock, Glib::Threads::NOT_LOCK) {}
|
||||
WriteProtectRender (RTMidiBufferBase& rtm) : lm (rtm._lock, Glib::Threads::NOT_LOCK) {}
|
||||
void acquire () { lm.acquire(); }
|
||||
|
||||
private:
|
||||
@ -138,6 +143,8 @@ class LIBARDOUR_API RTMidiBuffer : public Evoral::EventSink<samplepos_t>
|
||||
};
|
||||
};
|
||||
|
||||
typedef RTMidiBufferBase<samplepos_t,samplecnt_t> RTMidiBuffer;
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif // __ardour_rt_midi_buffer_h__
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/debug.h"
|
||||
|
||||
#include "temporal/beats.h"
|
||||
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
#include "ardour/midi_state_tracker.h"
|
||||
@ -33,7 +35,8 @@ using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
RTMidiBuffer::RTMidiBuffer ()
|
||||
template<class TimeType, class DistanceType>
|
||||
RTMidiBufferBase<TimeType,DistanceType>::RTMidiBufferBase ()
|
||||
: _size (0)
|
||||
, _capacity (0)
|
||||
, _data (0)
|
||||
@ -44,14 +47,16 @@ RTMidiBuffer::RTMidiBuffer ()
|
||||
{
|
||||
}
|
||||
|
||||
RTMidiBuffer::~RTMidiBuffer()
|
||||
template<class TimeType, class DistanceType>
|
||||
RTMidiBufferBase<TimeType,DistanceType>::~RTMidiBufferBase()
|
||||
{
|
||||
cache_aligned_free (_data);
|
||||
cache_aligned_free (_pool);
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
void
|
||||
RTMidiBuffer::resize (size_t size)
|
||||
RTMidiBufferBase<TimeType,DistanceType>::resize (size_t size)
|
||||
{
|
||||
if (_data && size < _capacity) {
|
||||
|
||||
@ -69,21 +74,23 @@ RTMidiBuffer::resize (size_t size)
|
||||
|
||||
if (_size) {
|
||||
assert (old_data);
|
||||
memcpy (_data, old_data, _size * sizeof (Item));
|
||||
memcpy ((void*) _data, (void*) old_data, _size * sizeof (Item));
|
||||
cache_aligned_free (old_data);
|
||||
}
|
||||
|
||||
_capacity = size;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
bool
|
||||
RTMidiBuffer::reversed () const
|
||||
RTMidiBufferBase<TimeType,DistanceType>::reversed () const
|
||||
{
|
||||
return _reversed;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
void
|
||||
RTMidiBuffer::reverse ()
|
||||
RTMidiBufferBase<TimeType,DistanceType>::reverse ()
|
||||
{
|
||||
if (_size == 0) {
|
||||
return;
|
||||
@ -148,8 +155,9 @@ RTMidiBuffer::reverse ()
|
||||
_reversed = !_reversed;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
void
|
||||
RTMidiBuffer::dump (uint32_t cnt)
|
||||
RTMidiBufferBase<TimeType,DistanceType>::dump (uint32_t cnt)
|
||||
{
|
||||
cerr << this << " total items: " << _size << " within " << _capacity << " blob pool: " << _pool_capacity << " used " << _pool_size << endl;
|
||||
|
||||
@ -187,8 +195,9 @@ RTMidiBuffer::dump (uint32_t cnt)
|
||||
}
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
uint32_t
|
||||
RTMidiBuffer::write (TimeType time, Evoral::EventType /*type*/, uint32_t size, const uint8_t* buf)
|
||||
RTMidiBufferBase<TimeType,DistanceType>::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" */
|
||||
|
||||
@ -238,21 +247,16 @@ RTMidiBuffer::write (TimeType time, Evoral::EventType /*type*/, uint32_t size, c
|
||||
/*
|
||||
static
|
||||
bool
|
||||
item_timestamp_earlier (ARDOUR::RTMidiBuffer::Item const & item, samplepos_t const & time)
|
||||
item_timestamp_earlier (ARDOUR::template<class TimeType, class DistanceType>
|
||||
RTMidiBufferBase<TimeType,DistanceType>::Item const & item, samplepos_t const & time)
|
||||
{
|
||||
return item.timestamp < time;
|
||||
}
|
||||
*/
|
||||
|
||||
static
|
||||
bool
|
||||
item_item_earlier (ARDOUR::RTMidiBuffer::Item const & item, ARDOUR::RTMidiBuffer::Item const & other)
|
||||
{
|
||||
return item.timestamp < other.timestamp;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
void
|
||||
RTMidiBuffer::track (MidiStateTracker& mst, samplepos_t start, samplepos_t end)
|
||||
RTMidiBufferBase<TimeType,DistanceType>::track (MidiStateTracker& mst, TimeType start, TimeType end)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (_lock, Glib::Threads::TRY_LOCK);
|
||||
|
||||
@ -268,13 +272,13 @@ RTMidiBuffer::track (MidiStateTracker& mst, samplepos_t start, samplepos_t end)
|
||||
|
||||
if (start < end) {
|
||||
iend = _data+_size;
|
||||
item = lower_bound (_data, iend, foo, item_item_earlier);
|
||||
item = lower_bound (_data, iend, foo, [](Item const & a, Item const & b) { return a.timestamp < b.timestamp; });
|
||||
reverse = false;
|
||||
} else {
|
||||
iend = _data;
|
||||
--iend; /* yes, this is technically "illegal" but we will never indirect */
|
||||
Item* uend = _data + _size;
|
||||
item = upper_bound (_data, uend, foo, item_item_earlier);
|
||||
item = upper_bound (_data, uend, foo, [](Item const & a, Item const & b) { return a.timestamp < b.timestamp; });
|
||||
|
||||
if (item == uend) {
|
||||
--item;
|
||||
@ -330,8 +334,9 @@ RTMidiBuffer::track (MidiStateTracker& mst, samplepos_t start, samplepos_t end)
|
||||
}
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
uint32_t
|
||||
RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiNoteTracker& tracker, samplecnt_t offset)
|
||||
RTMidiBufferBase<TimeType,DistanceType>::read (MidiBuffer& dst, TimeType start, TimeType end, MidiNoteTracker& tracker, DistanceType offset)
|
||||
{
|
||||
Glib::Threads::RWLock::ReaderLock lm (_lock, Glib::Threads::TRY_LOCK);
|
||||
|
||||
@ -348,13 +353,13 @@ RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiNot
|
||||
|
||||
if (start < end) {
|
||||
iend = _data+_size;
|
||||
item = lower_bound (_data, iend, foo, item_item_earlier);
|
||||
item = lower_bound (_data, iend, foo, [](Item const & a, Item const & b) { return a.timestamp < b.timestamp; });
|
||||
reverse = false;
|
||||
} else {
|
||||
iend = _data;
|
||||
--iend; /* yes, this is technically "illegal" but we will never indirect */
|
||||
Item* uend = _data + _size;
|
||||
item = upper_bound (_data, uend, foo, item_item_earlier);
|
||||
item = upper_bound (_data, uend, foo, [](Item const & a, Item const & b) { return a.timestamp < b.timestamp; });
|
||||
|
||||
if (item == uend) {
|
||||
--item;
|
||||
@ -418,7 +423,9 @@ RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiNot
|
||||
|
||||
}
|
||||
|
||||
if (!dst.push_back (evtime, Evoral::MIDI_EVENT, size, addr)) {
|
||||
const samplepos_t evsamples (timepos_t (evtime).samples());
|
||||
|
||||
if (!dst.push_back (evsamples, Evoral::MIDI_EVENT, size, addr)) {
|
||||
DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events, dst size = %2\n", count, dst.size()));
|
||||
break;
|
||||
}
|
||||
@ -448,8 +455,9 @@ RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiNot
|
||||
return count;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
uint32_t
|
||||
RTMidiBuffer::alloc_blob (uint32_t size)
|
||||
RTMidiBufferBase<TimeType,DistanceType>::alloc_blob (uint32_t size)
|
||||
{
|
||||
if (_pool_size + size > _pool_capacity) {
|
||||
uint8_t* old_pool = _pool;
|
||||
@ -471,8 +479,9 @@ RTMidiBuffer::alloc_blob (uint32_t size)
|
||||
return offset;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
uint32_t
|
||||
RTMidiBuffer::store_blob (uint32_t size, uint8_t const * data)
|
||||
RTMidiBufferBase<TimeType,DistanceType>::store_blob (uint32_t size, uint8_t const * data)
|
||||
{
|
||||
uint32_t offset = alloc_blob (size);
|
||||
uint8_t* addr = &_pool[offset];
|
||||
@ -484,8 +493,9 @@ RTMidiBuffer::store_blob (uint32_t size, uint8_t const * data)
|
||||
return offset;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
void
|
||||
RTMidiBuffer::clear ()
|
||||
RTMidiBufferBase<TimeType,DistanceType>::clear ()
|
||||
{
|
||||
/* mark main array as empty */
|
||||
_size = 0;
|
||||
@ -495,11 +505,12 @@ RTMidiBuffer::clear ()
|
||||
_reversed = false;
|
||||
}
|
||||
|
||||
samplecnt_t
|
||||
RTMidiBuffer::span() const
|
||||
template<class TimeType, class DistanceType>
|
||||
DistanceType
|
||||
RTMidiBufferBase<TimeType,DistanceType>::span() const
|
||||
{
|
||||
if (_size == 0 || _size == 1) {
|
||||
return 0;
|
||||
return DistanceType ();
|
||||
}
|
||||
|
||||
const Item* last = &_data[_size-1];
|
||||
@ -508,3 +519,21 @@ RTMidiBuffer::span() const
|
||||
return last->timestamp - first->timestamp;
|
||||
}
|
||||
|
||||
template<class TimeType, class DistanceType>
|
||||
void
|
||||
RTMidiBufferBase<TimeType,DistanceType>::track_state (TimeType when, MidiStateTracker& mst) const
|
||||
{
|
||||
uint32_t evsize;
|
||||
|
||||
for (uint32_t index = 0; index < _size; ++index) {
|
||||
if (_data[index].timestamp >= when) {
|
||||
break;
|
||||
}
|
||||
mst.track (bytes (_data[index], evsize));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Explicit instantiation
|
||||
template class RTMidiBufferBase<samplepos_t,samplecnt_t>;
|
||||
template class RTMidiBufferBase<Temporal::Beats,Temporal::Beats>;
|
||||
|
Loading…
Reference in New Issue
Block a user