2 Copyright (C) 2006-2007 Paul Davis
3 Author: David Robillard
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2 of the License, or (at your option)
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "pbd/malign.h"
23 #include "pbd/compose.h"
24 #include "pbd/debug.h"
25 #include "pbd/stacktrace.h"
27 #include "ardour/debug.h"
28 #include "ardour/midi_buffer.h"
29 #include "ardour/port.h"
32 using namespace ARDOUR;
35 // FIXME: mirroring for MIDI buffers?
36 MidiBuffer::MidiBuffer(size_t capacity)
37 : Buffer (DataType::MIDI)
47 MidiBuffer::~MidiBuffer()
49 cache_aligned_free(_data);
53 MidiBuffer::resize(size_t size)
55 if (_data && size < _capacity) {
65 cache_aligned_free (_data);
67 cache_aligned_malloc ((void**) &_data, size);
76 MidiBuffer::copy(const MidiBuffer& copy)
78 assert(_capacity >= copy._size);
80 memcpy(_data, copy._data, copy._size);
84 MidiBuffer::copy(MidiBuffer const * const copy)
86 assert(_capacity >= copy->size ());
87 _size = copy->size ();
88 memcpy(_data, copy->_data, _size);
92 /** Read events from @a src starting at time @a offset into the START of this buffer, for
93 * time duration @a nframes. Relative time, where 0 = start of buffer.
95 * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
98 MidiBuffer::read_from (const Buffer& src, samplecnt_t nframes, sampleoffset_t dst_offset, sampleoffset_t /* src_offset*/)
100 assert (src.type() == DataType::MIDI);
101 assert (&src != this);
103 const MidiBuffer& msrc = (const MidiBuffer&) src;
105 assert (_capacity >= msrc.size());
107 if (dst_offset == 0) {
112 for (MidiBuffer::const_iterator i = msrc.begin(); i != msrc.end(); ++i) {
113 const Evoral::Event<TimeType> ev(*i, false);
115 if (dst_offset >= 0) {
116 /* Positive offset: shifting events from internal
117 buffer view of time (always relative to to start of
118 current possibly split cycle) to from global/port
119 view of time (always relative to start of process
122 Check it is within range of this (split) cycle, then shift.
124 if (ev.time() >= 0 && ev.time() < nframes) {
125 push_back (ev.time() + dst_offset, ev.size(), ev.buffer());
127 cerr << "\t!!!! MIDI event @ " << ev.time() << " skipped, not within range 0 .. " << nframes << ": ";
130 /* Negative offset: shifting events from global/port
131 view of time (always relative to start of process
132 cycle) back to internal buffer view of time (always
133 relative to to start of current possibly split
136 Shift first, then check it is within range of this
139 const samplepos_t evtime = ev.time() + dst_offset;
141 if (evtime >= 0 && evtime < nframes) {
142 push_back (evtime, ev.size(), ev.buffer());
144 cerr << "\t!!!! MIDI event @ " << evtime << " (based on " << ev.time() << " + " << dst_offset << ") skipped, not within range 0 .. " << nframes << ": ";
149 _silent = src.silent();
153 MidiBuffer::merge_from (const Buffer& src, samplecnt_t /*nframes*/, sampleoffset_t /*dst_offset*/, sampleoffset_t /*src_offset*/)
155 const MidiBuffer* mbuf = dynamic_cast<const MidiBuffer*>(&src);
157 assert (mbuf != this);
159 /* XXX use nframes, and possible offsets */
160 merge_in_place (*mbuf);
163 /** Push an event into the buffer.
165 * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
166 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
168 * @return false if operation failed (not enough room)
171 MidiBuffer::push_back(const Evoral::Event<TimeType>& ev)
173 return push_back (ev.time(), ev.size(), ev.buffer());
177 /** Push MIDI data into the buffer.
179 * Note that the raw MIDI pointed to by @param data will be COPIED and unmodified.
180 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
182 * @return false if operation failed (not enough room)
185 MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
187 const size_t stamp_size = sizeof(TimeType);
190 if (DEBUG_ENABLED(DEBUG::MidiIO)) {
192 DEBUG_STR_APPEND(a, string_compose ("midibuffer %1 push event @ %2 sz %3 ", this, time, size));
193 for (size_t i=0; i < size; ++i) {
194 DEBUG_STR_APPEND(a,hex);
195 DEBUG_STR_APPEND(a,"0x");
196 DEBUG_STR_APPEND(a,(int)data[i]);
197 DEBUG_STR_APPEND(a,' ');
199 DEBUG_STR_APPEND(a,'\n');
200 DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
204 if (_size + stamp_size + size >= _capacity) {
208 if (!Evoral::midi_event_is_valid(data, size)) {
212 uint8_t* const write_loc = _data + _size;
213 *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = time;
214 memcpy(write_loc + stamp_size, data, size);
216 _size += stamp_size + size;
223 MidiBuffer::insert_event(const Evoral::Event<TimeType>& ev)
226 return push_back(ev);
229 const size_t stamp_size = sizeof(TimeType);
230 const size_t bytes_to_merge = stamp_size + ev.size();
232 if (_size + bytes_to_merge >= _capacity) {
233 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
234 PBD::stacktrace (cerr, 20);
238 TimeType t = ev.time();
240 ssize_t insert_offset = -1;
241 for (MidiBuffer::iterator m = begin(); m != end(); ++m) {
242 if ((*m).time() < t) {
245 if ((*m).time() == t) {
246 const uint8_t our_midi_status_byte = *(_data + m.offset + sizeof (TimeType));
247 if (second_simultaneous_midi_byte_is_first (ev.type(), our_midi_status_byte)) {
251 insert_offset = m.offset;
254 if (insert_offset == -1) {
255 return push_back(ev);
258 // don't use memmove - it may use malloc(!)
259 // memmove (_data + insert_offset + bytes_to_merge, _data + insert_offset, _size - insert_offset);
260 for (ssize_t a = _size + bytes_to_merge - 1, b = _size - 1; b >= insert_offset; --b, --a) {
264 uint8_t* const write_loc = _data + insert_offset;
265 *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = t;
266 memcpy(write_loc + stamp_size, ev.buffer(), ev.size());
268 _size += bytes_to_merge;
274 MidiBuffer::write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf)
276 insert_event(Evoral::Event<TimeType>(type, time, size, const_cast<uint8_t*>(buf)));
280 /** Reserve space for a new event in the buffer.
282 * This call is for copying MIDI directly into the buffer, the data location
283 * (of sufficient size to write \a size bytes) is returned, or 0 on failure.
284 * This call MUST be immediately followed by a write to the returned data
285 * location, or the buffer will be corrupted and very nasty things will happen.
288 MidiBuffer::reserve(TimeType time, size_t size)
290 const size_t stamp_size = sizeof(TimeType);
291 if (_size + stamp_size + size >= _capacity) {
296 uint8_t* write_loc = _data + _size;
297 *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = time;
299 // move write_loc to begin of MIDI buffer data to write to
300 write_loc += stamp_size;
302 _size += stamp_size + size;
310 MidiBuffer::silence (samplecnt_t /*nframes*/, samplecnt_t /*offset*/)
312 /* XXX iterate over existing events, find all in range given by offset & nframes,
321 MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b)
323 bool b_first = false;
325 /* two events at identical times. we need to determine
326 the order in which they should occur.
339 if ((a) >= 0xf0 || (b) >= 0xf0 || ((a & 0xf) != (b & 0xf))) {
341 /* if either message is not a channel message, or if the channels are
342 * different, we don't care about the type.
350 case MIDI_CMD_CONTROL:
354 case MIDI_CMD_PGM_CHANGE:
356 case MIDI_CMD_CONTROL:
358 case MIDI_CMD_PGM_CHANGE:
359 case MIDI_CMD_NOTE_OFF:
360 case MIDI_CMD_NOTE_ON:
361 case MIDI_CMD_NOTE_PRESSURE:
362 case MIDI_CMD_CHANNEL_PRESSURE:
363 case MIDI_CMD_BENDER:
368 case MIDI_CMD_NOTE_OFF:
370 case MIDI_CMD_CONTROL:
371 case MIDI_CMD_PGM_CHANGE:
373 case MIDI_CMD_NOTE_OFF:
374 case MIDI_CMD_NOTE_ON:
375 case MIDI_CMD_NOTE_PRESSURE:
376 case MIDI_CMD_CHANNEL_PRESSURE:
377 case MIDI_CMD_BENDER:
382 case MIDI_CMD_NOTE_ON:
384 case MIDI_CMD_CONTROL:
385 case MIDI_CMD_PGM_CHANGE:
386 case MIDI_CMD_NOTE_OFF:
388 case MIDI_CMD_NOTE_ON:
389 case MIDI_CMD_NOTE_PRESSURE:
390 case MIDI_CMD_CHANNEL_PRESSURE:
391 case MIDI_CMD_BENDER:
395 case MIDI_CMD_NOTE_PRESSURE:
397 case MIDI_CMD_CONTROL:
398 case MIDI_CMD_PGM_CHANGE:
399 case MIDI_CMD_NOTE_OFF:
400 case MIDI_CMD_NOTE_ON:
402 case MIDI_CMD_NOTE_PRESSURE:
403 case MIDI_CMD_CHANNEL_PRESSURE:
404 case MIDI_CMD_BENDER:
409 case MIDI_CMD_CHANNEL_PRESSURE:
411 case MIDI_CMD_CONTROL:
412 case MIDI_CMD_PGM_CHANGE:
413 case MIDI_CMD_NOTE_OFF:
414 case MIDI_CMD_NOTE_ON:
415 case MIDI_CMD_NOTE_PRESSURE:
417 case MIDI_CMD_CHANNEL_PRESSURE:
418 case MIDI_CMD_BENDER:
422 case MIDI_CMD_BENDER:
424 case MIDI_CMD_CONTROL:
425 case MIDI_CMD_PGM_CHANGE:
426 case MIDI_CMD_NOTE_OFF:
427 case MIDI_CMD_NOTE_ON:
428 case MIDI_CMD_NOTE_PRESSURE:
429 case MIDI_CMD_CHANNEL_PRESSURE:
431 case MIDI_CMD_BENDER:
441 /** Merge \a other into this buffer. Realtime safe. */
443 MidiBuffer::merge_in_place (const MidiBuffer &other)
445 if (other.size() && size()) {
446 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("merge in place, sizes %1/%2\n", size(), other.size()));
449 if (other.size() == 0) {
458 if (size() + other.size() > _capacity) {
462 const_iterator them = other.begin();
463 iterator us = begin();
465 while (them != other.end()) {
467 size_t bytes_to_merge;
468 ssize_t merge_offset;
470 /* gather up total size of events that are earlier than
471 the event referenced by "us"
477 while (them != other.end() && (*them).time() < (*us).time()) {
478 if (merge_offset == -1) {
479 merge_offset = them.offset;
481 bytes_to_merge += sizeof (TimeType) + (*them).size();
485 /* "them" now points to either:
487 * 1) an event that has the same or later timestamp than the
488 * event pointed to by "us"
492 * 2) the end of the "other" buffer
494 * if "sz" is non-zero, there is data to be merged from "other"
495 * into this buffer before we do anything else, corresponding
496 * to the events from "other" that we skipped while advancing
500 if (bytes_to_merge) {
501 assert(merge_offset >= 0);
503 memmove (_data + us.offset + bytes_to_merge, _data + us.offset, _size - us.offset);
505 _size += bytes_to_merge;
506 assert (_size <= _capacity);
507 /* insert new stuff */
508 memcpy (_data + us.offset, other._data + merge_offset, bytes_to_merge);
509 /* update iterator to our own events. this is a miserable hack */
510 us.offset += bytes_to_merge;
513 /* if we're at the end of the other buffer, we're done */
515 if (them == other.end()) {
519 /* if we have two messages messages with the same timestamp. we
520 * must order them correctly.
523 if ((*us).time() == (*them).time()) {
525 DEBUG_TRACE (DEBUG::MidiIO,
526 string_compose ("simultaneous MIDI events discovered during merge, times %1/%2 status %3/%4\n",
527 (*us).time(), (*them).time(),
528 (int) *(_data + us.offset + sizeof (TimeType)),
529 (int) *(other._data + them.offset + sizeof (TimeType))));
531 uint8_t our_midi_status_byte = *(_data + us.offset + sizeof (TimeType));
532 uint8_t their_midi_status_byte = *(other._data + them.offset + sizeof (TimeType));
533 bool them_first = second_simultaneous_midi_byte_is_first (our_midi_status_byte, their_midi_status_byte);
535 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("other message came first ? %1\n", them_first));
538 /* skip past our own event */
542 bytes_to_merge = sizeof (TimeType) + (*them).size();
544 /* move our remaining events later in the buffer by
545 * enough to fit the one message we're going to merge
548 memmove (_data + us.offset + bytes_to_merge, _data + us.offset, _size - us.offset);
550 _size += bytes_to_merge;
551 assert(_size <= _capacity);
552 /* insert new stuff */
553 memcpy (_data + us.offset, other._data + them.offset, bytes_to_merge);
554 /* update iterator to our own events. this is a miserable hack */
555 us.offset += bytes_to_merge;
556 /* 'us' is now an iterator to the event right after the
557 new ones that we merged
560 /* need to skip the event pointed to by 'us'
561 since its at the same time as 'them'
562 (still), and we'll enter
570 /* we merged one event from the other buffer, so
571 * advance the iterator there.
578 /* advance past our own events to get to the correct insertion
579 point for the next event(s) from "other"
582 while (us != end() && (*us).time() <= (*them).time()) {
587 /* check to see if we reached the end of this buffer while
588 * looking for the insertion point.
593 /* just append the rest of other and we're done*/
595 memcpy (_data + us.offset, other._data + them.offset, other._size - them.offset);
596 _size += other._size - them.offset;
597 assert(_size <= _capacity);