X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_buffer.cc;h=dc8deb7727a723ffd1f91e0209a4935db1756bba;hb=22b07e0233a29d9633ffa825a79503befaf2e16e;hp=1a6cb7fa2612d4fc461d8a3b28c88bce2b10728c;hpb=d1cc7e5a50e2144d7aea01bc5eceed6657513c1b;p=ardour.git diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc index 1a6cb7fa26..dc8deb7727 100644 --- a/libs/ardour/midi_buffer.cc +++ b/libs/ardour/midi_buffer.cc @@ -44,7 +44,7 @@ MidiBuffer::MidiBuffer(size_t capacity) MidiBuffer::~MidiBuffer() { - free(_data); + cache_aligned_free(_data); } void @@ -60,7 +60,7 @@ MidiBuffer::resize(size_t size) return; } - free (_data); + cache_aligned_free (_data); cache_aligned_malloc ((void**) &_data, size); @@ -163,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) { @@ -178,7 +178,7 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data) #endif if (_size + stamp_size + size >= _capacity) { - cerr << "MidiBuffer::push_back2 failed (buffer is full; _size = " << _size << " capacity " + cerr << "MidiBuffer::push_back2 failed (buffer is full; _size = " << _size << " capacity " << _capacity << " stamp " << stamp_size << " size = " << size << ")" << endl; PBD::stacktrace (cerr, 20); return false; @@ -190,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((uintptr_t)write_loc)) = time; memcpy(write_loc + stamp_size, data, size); _size += stamp_size + size; @@ -199,6 +199,64 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data) return true; } +bool +MidiBuffer::insert_event(const Evoral::MIDIEvent& ev) +{ + if (size() == 0) { + return push_back(ev); + } + + const size_t stamp_size = sizeof(TimeType); + 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; + } + + 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); + } + + // 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]; + } + + uint8_t* const write_loc = _data + insert_offset; + *(reinterpret_cast((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(type, time, size, const_cast(buf))); + return size; +} + /** Reserve space for a new event in the buffer. * * This call is for copying MIDI directly into the buffer, the data location @@ -216,7 +274,7 @@ MidiBuffer::reserve(TimeType time, size_t size) // write timestamp uint8_t* write_loc = _data + _size; - *((TimeType*)write_loc) = time; + *(reinterpret_cast((uintptr_t)write_loc)) = time; // move write_loc to begin of MIDI buffer data to write to write_loc += stamp_size; @@ -246,9 +304,9 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b) /* two events at identical times. we need to determine the order in which they should occur. - + the rule is: - + Controller messages Program Change Note Off @@ -257,22 +315,22 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b) Channel Pressure Pitch Bend */ - + if ((a) >= 0xf0 || (b) >= 0xf0 || ((a & 0xf) != (b & 0xf))) { - + /* if either message is not a channel message, or if the channels are * different, we don't care about the type. */ - + b_first = true; - + } else { - + switch (b & 0xf0) { case MIDI_CMD_CONTROL: b_first = true; break; - + case MIDI_CMD_PGM_CHANGE: switch (a & 0xf0) { case MIDI_CMD_CONTROL: @@ -286,7 +344,7 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b) b_first = true; } break; - + case MIDI_CMD_NOTE_OFF: switch (a & 0xf0) { case MIDI_CMD_CONTROL: @@ -300,7 +358,7 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b) b_first = true; } break; - + case MIDI_CMD_NOTE_ON: switch (a & 0xf0) { case MIDI_CMD_CONTROL: @@ -327,7 +385,7 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b) b_first = true; } break; - + case MIDI_CMD_CHANNEL_PRESSURE: switch (a & 0xf0) { case MIDI_CMD_CONTROL: @@ -356,10 +414,10 @@ MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b) break; } } - + return b_first; } - + /** Merge \a other into this buffer. Realtime safe. */ bool MidiBuffer::merge_in_place (const MidiBuffer &other) @@ -416,7 +474,7 @@ MidiBuffer::merge_in_place (const MidiBuffer &other) * if "sz" is non-zero, there is data to be merged from "other" * into this buffer before we do anything else, corresponding * to the events from "other" that we skipped while advancing - * "them". + * "them". */ if (bytes_to_merge) { @@ -430,7 +488,7 @@ MidiBuffer::merge_in_place (const MidiBuffer &other) memcpy (_data + us.offset, other._data + merge_offset, bytes_to_merge); /* update iterator to our own events. this is a miserable hack */ us.offset += bytes_to_merge; - } + } /* if we're at the end of the other buffer, we're done */ @@ -444,25 +502,25 @@ MidiBuffer::merge_in_place (const MidiBuffer &other) if ((*us).time() == (*them).time()) { - DEBUG_TRACE (DEBUG::MidiIO, + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("simultaneous MIDI events discovered during merge, times %1/%2 status %3/%4\n", (*us).time(), (*them).time(), (int) *(_data + us.offset + sizeof (TimeType)), (int) *(other._data + them.offset + sizeof (TimeType)))); - + uint8_t our_midi_status_byte = *(_data + us.offset + sizeof (TimeType)); uint8_t their_midi_status_byte = *(other._data + them.offset + sizeof (TimeType)); bool them_first = second_simultaneous_midi_byte_is_first (our_midi_status_byte, their_midi_status_byte); - + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("other message came first ? %1\n", them_first)); - + if (!them_first) { /* skip past our own event */ ++us; } - + bytes_to_merge = sizeof (TimeType) + (*them).size(); - + /* move our remaining events later in the buffer by * enough to fit the one message we're going to merge */ @@ -481,7 +539,7 @@ MidiBuffer::merge_in_place (const MidiBuffer &other) if (them_first) { /* need to skip the event pointed to by 'us' since its at the same time as 'them' - (still), and we'll enter + (still), and we'll enter */ if (us != end()) { @@ -496,11 +554,11 @@ MidiBuffer::merge_in_place (const MidiBuffer &other) ++them; } else { - + /* advance past our own events to get to the correct insertion point for the next event(s) from "other" */ - + while (us != end() && (*us).time() <= (*them).time()) { ++us; } @@ -513,12 +571,12 @@ MidiBuffer::merge_in_place (const MidiBuffer &other) if (us == end()) { /* just append the rest of other and we're done*/ - + memcpy (_data + us.offset, other._data + them.offset, other._size - them.offset); _size += other._size - them.offset; assert(_size <= _capacity); break; - } + } } return true;