logic rearrangement to avoid unnecessary call to Route::monitoring_state() in instrum...
[ardour.git] / libs / ardour / midi_buffer.cc
index 8d07c308ee7428207a13d207731be0c5cec24714..50ff7b728fb05ede14c66382c79a417e67ac797c 100644 (file)
@@ -22,6 +22,7 @@
 #include "pbd/malign.h"
 #include "pbd/compose.h"
 #include "pbd/debug.h"
+#include "pbd/stacktrace.h"
 
 #include "ardour/debug.h"
 #include "ardour/midi_buffer.h"
@@ -32,34 +33,39 @@ using namespace PBD;
 
 // FIXME: mirroring for MIDI buffers?
 MidiBuffer::MidiBuffer(size_t capacity)
-       : Buffer(DataType::MIDI, capacity)
-       , _data(0)
+       : Buffer (DataType::MIDI)
+       , _data (0)
 {
        if (capacity) {
-               resize(_capacity);
-               silence(_capacity);
+               resize (capacity);
+               silence (capacity);
        }
 }
 
 MidiBuffer::~MidiBuffer()
 {
-       free(_data);
+       cache_aligned_free(_data);
 }
 
 void
 MidiBuffer::resize(size_t size)
 {
-       assert(size > 0);
+       if (_data && size < _capacity) {
+
+               if (_size < size) {
+                       /* truncate */
+                       _size = size;
+               }
 
-       if (size < _capacity) {
                return;
        }
 
-       free(_data);
+       cache_aligned_free (_data);
+
+       cache_aligned_malloc ((void**) &_data, size);
 
        _size = 0;
        _capacity = size;
-       cache_aligned_malloc ((void**) &_data, _capacity);
 
        assert(_data);
 }
@@ -84,7 +90,7 @@ MidiBuffer::read_from (const Buffer& src, framecnt_t nframes, framecnt_t dst_off
        assert (src.type() == DataType::MIDI);
        assert (&src != this);
 
-       const MidiBuffer& msrc = (MidiBuffer&) src;
+       const MidiBuffer& msrc = (const MidiBuffer&) src;
 
        assert (_capacity >= msrc.size());
 
@@ -130,11 +136,10 @@ bool
 MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
 {
        const size_t stamp_size = sizeof(TimeType);
-       /*cerr << "MidiBuffer: pushing event @ " << ev.time()
-               << " size = " << ev.size() << endl;*/
 
        if (_size + stamp_size + ev.size() >= _capacity) {
                cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
+               PBD::stacktrace (cerr, 20);
                return false;
        }
 
@@ -158,7 +163,7 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
        const size_t stamp_size = sizeof(TimeType);
 
 #ifndef NDEBUG
-       if (DEBUG::MidiIO & PBD::debug_bits) {
+       if (DEBUG_ENABLED(DEBUG::MidiIO)) {
                DEBUG_STR_DECL(a);
                DEBUG_STR_APPEND(a, string_compose ("midibuffer %1 push event @ %2 sz %3 ", this, time, size));
                for (size_t i=0; i < size; ++i) {
@@ -173,7 +178,9 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
 #endif
 
        if (_size + stamp_size + size >= _capacity) {
-               cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
+               cerr << "MidiBuffer::push_back2 failed (buffer is full; _size = " << _size << " capacity " 
+                    << _capacity << " stamp " << stamp_size << " size = " << size << ")" << endl;
+               PBD::stacktrace (cerr, 20);
                return false;
        }
 
@@ -183,7 +190,7 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
        }
 
        uint8_t* const write_loc = _data + _size;
-       *((TimeType*)write_loc) = time;
+       *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = time;
        memcpy(write_loc + stamp_size, data, size);
 
        _size += stamp_size + size;
@@ -192,38 +199,63 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
        return true;
 }
 
-
-/** Push an event into the buffer.
- *
- * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
- * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
- * Realtime safe.
- * @return false if operation failed (not enough room)
- */
 bool
-MidiBuffer::push_back(const jack_midi_event_t& ev)
+MidiBuffer::insert_event(const Evoral::MIDIEvent<TimeType>& ev)
 {
+       if (size() == 0) {
+               return push_back(ev);
+       }
+
        const size_t stamp_size = sizeof(TimeType);
-       if (_size + stamp_size + ev.size >= _capacity) {
+       const size_t bytes_to_merge = stamp_size + ev.size();
+
+       if (_size + bytes_to_merge >= _capacity) {
                cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
+               PBD::stacktrace (cerr, 20);
                return false;
        }
 
-       if (!Evoral::midi_event_is_valid(ev.buffer, ev.size)) {
-               cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl;
-               return false;
+       TimeType t = ev.time();
+
+       ssize_t insert_offset = -1;
+       for (MidiBuffer::iterator m = begin(); m != end(); ++m) {
+               if ((*m).time() < t) {
+                       continue;
+               }
+               if ((*m).time() == t) {
+                       const uint8_t our_midi_status_byte = *(_data + m.offset + sizeof (TimeType));
+                       if (second_simultaneous_midi_byte_is_first (ev.type(), our_midi_status_byte)) {
+                               continue;
+                       }
+               }
+               insert_offset = m.offset;
+               break;
+       }
+       if (insert_offset == -1) {
+               return push_back(ev);
        }
 
-       uint8_t* const write_loc = _data + _size;
-       *((TimeType*)write_loc) = ev.time;
-       memcpy(write_loc + stamp_size, ev.buffer, ev.size);
+       // don't use memmove - it may use malloc(!)
+       // memmove (_data + insert_offset + bytes_to_merge, _data + insert_offset, _size - insert_offset);
+       for (ssize_t a = _size + bytes_to_merge - 1, b = _size - 1; b >= insert_offset; --b, --a) {
+               _data[a] = _data[b];
+       }
 
-       _size += stamp_size + ev.size;
-       _silent = false;
+       uint8_t* const write_loc = _data + insert_offset;
+       *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = t;
+       memcpy(write_loc + stamp_size, ev.buffer(), ev.size());
+
+       _size += bytes_to_merge;
 
        return true;
 }
 
+uint32_t
+MidiBuffer::write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf)
+{
+       insert_event(Evoral::MIDIEvent<TimeType>(type, time, size, const_cast<uint8_t*>(buf)));
+       return size;
+}
 
 /** Reserve space for a new event in the buffer.
  *
@@ -242,7 +274,7 @@ MidiBuffer::reserve(TimeType time, size_t size)
 
        // write timestamp
        uint8_t* write_loc = _data + _size;
-       *((TimeType*)write_loc) = time;
+       *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = time;
 
        // move write_loc to begin of MIDI buffer data to write to
        write_loc += stamp_size;
@@ -311,6 +343,7 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b)
                        case MIDI_CMD_BENDER:
                                b_first = true;
                        }
+                       break;
                        
                case MIDI_CMD_NOTE_OFF:
                        switch (a & 0xf0) {
@@ -387,9 +420,9 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b)
        
 /** Merge \a other into this buffer.  Realtime safe. */
 bool
-MidiBuffer::merge_in_place(const MidiBuffer &other)
+MidiBuffer::merge_in_place (const MidiBuffer &other)
 {
-       if (other.size() || size()) {
+       if (other.size() && size()) {
                DEBUG_TRACE (DEBUG::MidiIO, string_compose ("merge in place, sizes %1/%2\n", size(), other.size()));
        }
 
@@ -549,49 +582,3 @@ MidiBuffer::merge_in_place(const MidiBuffer &other)
        return true;
 }
 
-/** Clear, and merge \a a and \a b into this buffer.
- *
- * \return true if complete merge was successful
- */
-bool
-MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
-{
-       _size = 0;
-
-       if (this == &a) {
-           return merge_in_place(b);
-       } else if (this == &b) {
-           return merge_in_place(a);
-       }
-
-       const_iterator ai = a.begin();
-       const_iterator bi = b.begin();
-
-       resize(a.size() + b.size());
-       while (ai != a.end() && bi != b.end()) {
-               if ((*ai).time() < (*bi).time()) {
-                       memcpy(_data + _size, (*ai).buffer(), (*ai).size());
-                       _size += (*ai).size();
-                       ++ai;
-               } else {
-                       memcpy(_data + _size, (*bi).buffer(), (*bi).size());
-                       _size += (*bi).size();
-                       ++bi;
-               }
-       }
-
-       while (ai != a.end()) {
-               memcpy(_data + _size, (*ai).buffer(), (*ai).size());
-               _size += (*ai).size();
-               ++ai;
-       }
-
-       while (bi != b.end()) {
-               memcpy(_data + _size, (*bi).buffer(), (*bi).size());
-               _size += (*bi).size();
-               ++bi;
-       }
-
-       return true;
-}
-