We were 2 more debug "bits" away from overflow, so recast PBD::DEBUG mechanism away...
[ardour.git] / libs / ardour / midi_buffer.cc
1 /*
2     Copyright (C) 2006-2007 Paul Davis
3     Author: David Robillard
4
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)
8     any later version.
9
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
13     for more details.
14
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.
18 */
19
20 #include <iostream>
21
22 #include "pbd/malign.h"
23 #include "pbd/compose.h"
24 #include "pbd/debug.h"
25 #include "pbd/stacktrace.h"
26
27 #include "ardour/debug.h"
28 #include "ardour/midi_buffer.h"
29
30 using namespace std;
31 using namespace ARDOUR;
32 using namespace PBD;
33
34 // FIXME: mirroring for MIDI buffers?
35 MidiBuffer::MidiBuffer(size_t capacity)
36         : Buffer (DataType::MIDI)
37         , _data (0)
38 {
39         if (capacity) {
40                 resize (capacity);
41                 silence (capacity);
42         }
43 }
44
45 MidiBuffer::~MidiBuffer()
46 {
47         free(_data);
48 }
49
50 void
51 MidiBuffer::resize(size_t size)
52 {
53         if (_data && size < _capacity) {
54
55                 if (_size < size) {
56                         /* truncate */
57                         _size = size;
58                 }
59
60                 return;
61         }
62
63         free (_data);
64
65         cache_aligned_malloc ((void**) &_data, size);
66
67         _size = 0;
68         _capacity = size;
69
70         assert(_data);
71 }
72
73 void
74 MidiBuffer::copy(const MidiBuffer& copy)
75 {
76         assert(_capacity >= copy._size);
77         _size = copy._size;
78         memcpy(_data, copy._data, copy._size);
79 }
80
81
82 /** Read events from @a src starting at time @a offset into the START of this buffer, for
83  * time duration @a nframes.  Relative time, where 0 = start of buffer.
84  *
85  * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
86  */
87 void
88 MidiBuffer::read_from (const Buffer& src, framecnt_t nframes, framecnt_t dst_offset, framecnt_t src_offset)
89 {
90         assert (src.type() == DataType::MIDI);
91         assert (&src != this);
92
93         const MidiBuffer& msrc = (const MidiBuffer&) src;
94
95         assert (_capacity >= msrc.size());
96
97         if (dst_offset == 0) {
98                 clear ();
99                 assert (_size == 0);
100         }
101
102         /* XXX use dst_offset somehow */
103
104         for (MidiBuffer::const_iterator i = msrc.begin(); i != msrc.end(); ++i) {
105                 const Evoral::MIDIEvent<TimeType> ev(*i, false);
106                 if (ev.time() >= src_offset && ev.time() < (nframes+src_offset)) {
107                         push_back (ev);
108                 } else {
109                         cerr << "MIDI event @ " <<  ev.time() << " skipped, not within range "
110                              << src_offset << " .. " << (nframes + src_offset) << endl;
111                 }
112         }
113
114         _silent = src.silent();
115 }
116
117 void
118 MidiBuffer::merge_from (const Buffer& src, framecnt_t /*nframes*/, framecnt_t /*dst_offset*/, framecnt_t /*src_offset*/)
119 {
120         const MidiBuffer* mbuf = dynamic_cast<const MidiBuffer*>(&src);
121         assert (mbuf);
122         assert (mbuf != this);
123
124         /* XXX use nframes, and possible offsets */
125         merge_in_place (*mbuf);
126 }
127
128 /** Push an event into the buffer.
129  *
130  * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
131  * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
132  * Realtime safe.
133  * @return false if operation failed (not enough room)
134  */
135 bool
136 MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
137 {
138         const size_t stamp_size = sizeof(TimeType);
139
140         if (_size + stamp_size + ev.size() >= _capacity) {
141                 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
142                 PBD::stacktrace (cerr, 20);
143                 return false;
144         }
145
146         if (!Evoral::midi_event_is_valid(ev.buffer(), ev.size())) {
147                 cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl;
148                 return false;
149         }
150
151         push_back(ev.time(), ev.size(), ev.buffer());
152
153         return true;
154 }
155
156
157 /** Push an event into the buffer.
158  * @return false if operation failed (not enough room)
159  */
160 bool
161 MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
162 {
163         const size_t stamp_size = sizeof(TimeType);
164
165 #ifndef NDEBUG
166         if (DEBUG_ENABLED(DEBUG::MidiIO)) {
167                 DEBUG_STR_DECL(a);
168                 DEBUG_STR_APPEND(a, string_compose ("midibuffer %1 push event @ %2 sz %3 ", this, time, size));
169                 for (size_t i=0; i < size; ++i) {
170                         DEBUG_STR_APPEND(a,hex);
171                         DEBUG_STR_APPEND(a,"0x");
172                         DEBUG_STR_APPEND(a,(int)data[i]);
173                         DEBUG_STR_APPEND(a,' ');
174                 }
175                 DEBUG_STR_APPEND(a,'\n');
176                 DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
177         }
178 #endif
179
180         if (_size + stamp_size + size >= _capacity) {
181                 cerr << "MidiBuffer::push_back2 failed (buffer is full; _size = " << _size << " capacity " 
182                      << _capacity << " stamp " << stamp_size << " size = " << size << ")" << endl;
183                 PBD::stacktrace (cerr, 20);
184                 return false;
185         }
186
187         if (!Evoral::midi_event_is_valid(data, size)) {
188                 cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl;
189                 return false;
190         }
191
192         uint8_t* const write_loc = _data + _size;
193         *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = time;
194         memcpy(write_loc + stamp_size, data, size);
195
196         _size += stamp_size + size;
197         _silent = false;
198
199         return true;
200 }
201
202 bool
203 MidiBuffer::insert_event(const Evoral::MIDIEvent<TimeType>& ev)
204 {
205         if (size() == 0) {
206                 return push_back(ev);
207         }
208
209         const size_t stamp_size = sizeof(TimeType);
210         const size_t bytes_to_merge = stamp_size + ev.size();
211
212         if (_size + bytes_to_merge >= _capacity) {
213                 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
214                 PBD::stacktrace (cerr, 20);
215                 return false;
216         }
217
218         TimeType t = ev.time();
219
220         ssize_t insert_offset = -1;
221         for (MidiBuffer::iterator m = begin(); m != end(); ++m) {
222                 if ((*m).time() < t) {
223                         continue;
224                 }
225                 if ((*m).time() == t) {
226                         const uint8_t our_midi_status_byte = *(_data + m.offset + sizeof (TimeType));
227                         if (second_simultaneous_midi_byte_is_first (ev.type(), our_midi_status_byte)) {
228                                 continue;
229                         }
230                 }
231                 insert_offset = m.offset;
232                 break;
233         }
234         if (insert_offset == -1) {
235                 return push_back(ev);
236         }
237
238         // don't use memmove - it may use malloc(!)
239         // memmove (_data + insert_offset + bytes_to_merge, _data + insert_offset, _size - insert_offset);
240         for (ssize_t a = _size + bytes_to_merge - 1, b = _size - 1; b >= insert_offset; --b, --a) {
241                 _data[a] = _data[b];
242         }
243
244         uint8_t* const write_loc = _data + insert_offset;
245         *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = t;
246         memcpy(write_loc + stamp_size, ev.buffer(), ev.size());
247
248         _size += bytes_to_merge;
249
250         return true;
251 }
252
253 uint32_t
254 MidiBuffer::write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf)
255 {
256         insert_event(Evoral::MIDIEvent<TimeType>(type, time, size, const_cast<uint8_t*>(buf)));
257         return size;
258 }
259
260 /** Reserve space for a new event in the buffer.
261  *
262  * This call is for copying MIDI directly into the buffer, the data location
263  * (of sufficient size to write \a size bytes) is returned, or 0 on failure.
264  * This call MUST be immediately followed by a write to the returned data
265  * location, or the buffer will be corrupted and very nasty things will happen.
266  */
267 uint8_t*
268 MidiBuffer::reserve(TimeType time, size_t size)
269 {
270         const size_t stamp_size = sizeof(TimeType);
271         if (_size + stamp_size + size >= _capacity) {
272                 return 0;
273         }
274
275         // write timestamp
276         uint8_t* write_loc = _data + _size;
277         *(reinterpret_cast<TimeType*>((uintptr_t)write_loc)) = time;
278
279         // move write_loc to begin of MIDI buffer data to write to
280         write_loc += stamp_size;
281
282         _size += stamp_size + size;
283         _silent = false;
284
285         return write_loc;
286 }
287
288
289 void
290 MidiBuffer::silence (framecnt_t /*nframes*/, framecnt_t /*offset*/)
291 {
292         /* XXX iterate over existing events, find all in range given by offset & nframes,
293            and delete them.
294         */
295
296         _size = 0;
297         _silent = true;
298 }
299
300 bool
301 MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b)
302 {
303         bool b_first = false;
304
305         /* two events at identical times. we need to determine
306            the order in which they should occur.
307            
308            the rule is:
309            
310            Controller messages
311            Program Change
312            Note Off
313            Note On
314            Note Pressure
315            Channel Pressure
316            Pitch Bend
317         */
318         
319         if ((a) >= 0xf0 || (b) >= 0xf0 || ((a & 0xf) != (b & 0xf))) {
320                 
321                 /* if either message is not a channel message, or if the channels are
322                  * different, we don't care about the type.
323                  */
324                 
325                 b_first = true;
326                 
327         } else {
328                 
329                 switch (b & 0xf0) {
330                 case MIDI_CMD_CONTROL:
331                         b_first = true;
332                         break;
333                         
334                 case MIDI_CMD_PGM_CHANGE:
335                         switch (a & 0xf0) {
336                         case MIDI_CMD_CONTROL:
337                                 break;
338                         case MIDI_CMD_PGM_CHANGE:
339                         case MIDI_CMD_NOTE_OFF:
340                         case MIDI_CMD_NOTE_ON:
341                         case MIDI_CMD_NOTE_PRESSURE:
342                         case MIDI_CMD_CHANNEL_PRESSURE:
343                         case MIDI_CMD_BENDER:
344                                 b_first = true;
345                         }
346                         break;
347                         
348                 case MIDI_CMD_NOTE_OFF:
349                         switch (a & 0xf0) {
350                         case MIDI_CMD_CONTROL:
351                         case MIDI_CMD_PGM_CHANGE:
352                                 break;
353                         case MIDI_CMD_NOTE_OFF:
354                         case MIDI_CMD_NOTE_ON:
355                         case MIDI_CMD_NOTE_PRESSURE:
356                         case MIDI_CMD_CHANNEL_PRESSURE:
357                         case MIDI_CMD_BENDER:
358                                 b_first = true;
359                         }
360                         break;
361                         
362                 case MIDI_CMD_NOTE_ON:
363                         switch (a & 0xf0) {
364                         case MIDI_CMD_CONTROL:
365                         case MIDI_CMD_PGM_CHANGE:
366                         case MIDI_CMD_NOTE_OFF:
367                                 break;
368                         case MIDI_CMD_NOTE_ON:
369                         case MIDI_CMD_NOTE_PRESSURE:
370                         case MIDI_CMD_CHANNEL_PRESSURE:
371                         case MIDI_CMD_BENDER:
372                                 b_first = true;
373                         }
374                         break;
375                 case MIDI_CMD_NOTE_PRESSURE:
376                         switch (a & 0xf0) {
377                         case MIDI_CMD_CONTROL:
378                         case MIDI_CMD_PGM_CHANGE:
379                         case MIDI_CMD_NOTE_OFF:
380                         case MIDI_CMD_NOTE_ON:
381                                 break;
382                         case MIDI_CMD_NOTE_PRESSURE:
383                         case MIDI_CMD_CHANNEL_PRESSURE:
384                         case MIDI_CMD_BENDER:
385                                 b_first = true;
386                         }
387                         break;
388                         
389                 case MIDI_CMD_CHANNEL_PRESSURE:
390                         switch (a & 0xf0) {
391                         case MIDI_CMD_CONTROL:
392                         case MIDI_CMD_PGM_CHANGE:
393                         case MIDI_CMD_NOTE_OFF:
394                         case MIDI_CMD_NOTE_ON:
395                         case MIDI_CMD_NOTE_PRESSURE:
396                                 break;
397                         case MIDI_CMD_CHANNEL_PRESSURE:
398                         case MIDI_CMD_BENDER:
399                                 b_first = true;
400                         }
401                         break;
402                 case MIDI_CMD_BENDER:
403                         switch (a & 0xf0) {
404                         case MIDI_CMD_CONTROL:
405                         case MIDI_CMD_PGM_CHANGE:
406                         case MIDI_CMD_NOTE_OFF:
407                         case MIDI_CMD_NOTE_ON:
408                         case MIDI_CMD_NOTE_PRESSURE:
409                         case MIDI_CMD_CHANNEL_PRESSURE:
410                                 break;
411                         case MIDI_CMD_BENDER:
412                                 b_first = true;
413                         }
414                         break;
415                 }
416         }
417         
418         return b_first;
419 }
420         
421 /** Merge \a other into this buffer.  Realtime safe. */
422 bool
423 MidiBuffer::merge_in_place (const MidiBuffer &other)
424 {
425         if (other.size() && size()) {
426                 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("merge in place, sizes %1/%2\n", size(), other.size()));
427         }
428
429         if (other.size() == 0) {
430                 return true;
431         }
432
433         if (size() == 0) {
434                 copy (other);
435                 return true;
436         }
437
438         if (size() + other.size() > _capacity) {
439                 return false;
440         }
441
442         const_iterator them = other.begin();
443         iterator us = begin();
444
445         while (them != other.end()) {
446
447                 size_t bytes_to_merge;
448                 ssize_t merge_offset;
449
450                 /* gather up total size of events that are earlier than
451                    the event referenced by "us"
452                 */
453
454                 merge_offset = -1;
455                 bytes_to_merge = 0;
456
457                 while (them != other.end() && (*them).time() < (*us).time()) {
458                         if (merge_offset == -1) {
459                                 merge_offset = them.offset;
460                         }
461                         bytes_to_merge += sizeof (TimeType) + (*them).size();
462                         ++them;
463                 }
464
465                 /* "them" now points to either:
466                  *
467                  * 1) an event that has the same or later timestamp than the
468                  *        event pointed to by "us"
469                  *
470                  * OR
471                  *
472                  * 2) the end of the "other" buffer
473                  *
474                  * if "sz" is non-zero, there is data to be merged from "other"
475                  * into this buffer before we do anything else, corresponding
476                  * to the events from "other" that we skipped while advancing
477                  * "them". 
478                  */
479
480                 if (bytes_to_merge) {
481                         assert(merge_offset >= 0);
482                         /* move existing */
483                         memmove (_data + us.offset + bytes_to_merge, _data + us.offset, _size - us.offset);
484                         /* increase _size */
485                         _size += bytes_to_merge;
486                         assert (_size <= _capacity);
487                         /* insert new stuff */
488                         memcpy  (_data + us.offset, other._data + merge_offset, bytes_to_merge);
489                         /* update iterator to our own events. this is a miserable hack */
490                         us.offset += bytes_to_merge;
491                 } 
492
493                 /* if we're at the end of the other buffer, we're done */
494
495                 if (them == other.end()) {
496                         break;
497                 }
498
499                 /* if we have two messages messages with the same timestamp. we
500                  * must order them correctly.
501                  */
502
503                 if ((*us).time() == (*them).time()) {
504
505                         DEBUG_TRACE (DEBUG::MidiIO, 
506                                      string_compose ("simultaneous MIDI events discovered during merge, times %1/%2 status %3/%4\n",
507                                                      (*us).time(), (*them).time(),
508                                                      (int) *(_data + us.offset + sizeof (TimeType)),
509                                                      (int) *(other._data + them.offset + sizeof (TimeType))));
510                         
511                         uint8_t our_midi_status_byte = *(_data + us.offset + sizeof (TimeType));
512                         uint8_t their_midi_status_byte = *(other._data + them.offset + sizeof (TimeType));
513                         bool them_first = second_simultaneous_midi_byte_is_first (our_midi_status_byte, their_midi_status_byte);
514                         
515                         DEBUG_TRACE (DEBUG::MidiIO, string_compose ("other message came first ? %1\n", them_first));
516                         
517                         if (!them_first) {
518                                 /* skip past our own event */
519                                 ++us;
520                         }
521                                 
522                         bytes_to_merge = sizeof (TimeType) + (*them).size();
523                         
524                         /* move our remaining events later in the buffer by
525                          * enough to fit the one message we're going to merge
526                          */
527
528                         memmove (_data + us.offset + bytes_to_merge, _data + us.offset, _size - us.offset);
529                         /* increase _size */
530                         _size += bytes_to_merge;
531                         assert(_size <= _capacity);
532                         /* insert new stuff */
533                         memcpy  (_data + us.offset, other._data + them.offset, bytes_to_merge);
534                         /* update iterator to our own events. this is a miserable hack */
535                         us.offset += bytes_to_merge;
536                         /* 'us' is now an iterator to the event right after the
537                            new ones that we merged
538                         */
539                         if (them_first) {
540                                 /* need to skip the event pointed to by 'us'
541                                    since its at the same time as 'them'
542                                    (still), and we'll enter 
543                                 */
544
545                                 if (us != end()) {
546                                         ++us;
547                                 }
548                         }
549
550                         /* we merged one event from the other buffer, so
551                          * advance the iterator there.
552                          */
553
554                         ++them;
555
556                 } else {
557                         
558                         /* advance past our own events to get to the correct insertion
559                            point for the next event(s) from "other"
560                         */
561                 
562                         while (us != end() && (*us).time() <= (*them).time()) {
563                                 ++us;
564                         }
565                 }
566
567                 /* check to see if we reached the end of this buffer while
568                  * looking for the insertion point.
569                  */
570
571                 if (us == end()) {
572
573                         /* just append the rest of other and we're done*/
574                         
575                         memcpy (_data + us.offset, other._data + them.offset, other._size - them.offset);
576                         _size += other._size - them.offset;
577                         assert(_size <= _capacity);
578                         break;
579                 } 
580         }
581
582         return true;
583 }
584