Merge windows+cc branch into cairocanvas branch. Not finished, need to now merge...
[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::MidiIO & PBD::debug_bits) {
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         *((TimeType*)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 /** Reserve space for a new event in the buffer.
203  *
204  * This call is for copying MIDI directly into the buffer, the data location
205  * (of sufficient size to write \a size bytes) is returned, or 0 on failure.
206  * This call MUST be immediately followed by a write to the returned data
207  * location, or the buffer will be corrupted and very nasty things will happen.
208  */
209 uint8_t*
210 MidiBuffer::reserve(TimeType time, size_t size)
211 {
212         const size_t stamp_size = sizeof(TimeType);
213         if (_size + stamp_size + size >= _capacity) {
214                 return 0;
215         }
216
217         // write timestamp
218         uint8_t* write_loc = _data + _size;
219         *((TimeType*)write_loc) = time;
220
221         // move write_loc to begin of MIDI buffer data to write to
222         write_loc += stamp_size;
223
224         _size += stamp_size + size;
225         _silent = false;
226
227         return write_loc;
228 }
229
230
231 void
232 MidiBuffer::silence (framecnt_t /*nframes*/, framecnt_t /*offset*/)
233 {
234         /* XXX iterate over existing events, find all in range given by offset & nframes,
235            and delete them.
236         */
237
238         _size = 0;
239         _silent = true;
240 }
241
242 bool
243 MidiBuffer::second_simultaneous_midi_byte_is_first (uint8_t a, uint8_t b)
244 {
245         bool b_first = false;
246
247         /* two events at identical times. we need to determine
248            the order in which they should occur.
249            
250            the rule is:
251            
252            Controller messages
253            Program Change
254            Note Off
255            Note On
256            Note Pressure
257            Channel Pressure
258            Pitch Bend
259         */
260         
261         if ((a) >= 0xf0 || (b) >= 0xf0 || ((a & 0xf) != (b & 0xf))) {
262                 
263                 /* if either message is not a channel message, or if the channels are
264                  * different, we don't care about the type.
265                  */
266                 
267                 b_first = true;
268                 
269         } else {
270                 
271                 switch (b & 0xf0) {
272                 case MIDI_CMD_CONTROL:
273                         b_first = true;
274                         break;
275                         
276                 case MIDI_CMD_PGM_CHANGE:
277                         switch (a & 0xf0) {
278                         case MIDI_CMD_CONTROL:
279                                 break;
280                         case MIDI_CMD_PGM_CHANGE:
281                         case MIDI_CMD_NOTE_OFF:
282                         case MIDI_CMD_NOTE_ON:
283                         case MIDI_CMD_NOTE_PRESSURE:
284                         case MIDI_CMD_CHANNEL_PRESSURE:
285                         case MIDI_CMD_BENDER:
286                                 b_first = true;
287                         }
288                         break;
289                         
290                 case MIDI_CMD_NOTE_OFF:
291                         switch (a & 0xf0) {
292                         case MIDI_CMD_CONTROL:
293                         case MIDI_CMD_PGM_CHANGE:
294                                 break;
295                         case MIDI_CMD_NOTE_OFF:
296                         case MIDI_CMD_NOTE_ON:
297                         case MIDI_CMD_NOTE_PRESSURE:
298                         case MIDI_CMD_CHANNEL_PRESSURE:
299                         case MIDI_CMD_BENDER:
300                                 b_first = true;
301                         }
302                         break;
303                         
304                 case MIDI_CMD_NOTE_ON:
305                         switch (a & 0xf0) {
306                         case MIDI_CMD_CONTROL:
307                         case MIDI_CMD_PGM_CHANGE:
308                         case MIDI_CMD_NOTE_OFF:
309                                 break;
310                         case MIDI_CMD_NOTE_ON:
311                         case MIDI_CMD_NOTE_PRESSURE:
312                         case MIDI_CMD_CHANNEL_PRESSURE:
313                         case MIDI_CMD_BENDER:
314                                 b_first = true;
315                         }
316                         break;
317                 case MIDI_CMD_NOTE_PRESSURE:
318                         switch (a & 0xf0) {
319                         case MIDI_CMD_CONTROL:
320                         case MIDI_CMD_PGM_CHANGE:
321                         case MIDI_CMD_NOTE_OFF:
322                         case MIDI_CMD_NOTE_ON:
323                                 break;
324                         case MIDI_CMD_NOTE_PRESSURE:
325                         case MIDI_CMD_CHANNEL_PRESSURE:
326                         case MIDI_CMD_BENDER:
327                                 b_first = true;
328                         }
329                         break;
330                         
331                 case MIDI_CMD_CHANNEL_PRESSURE:
332                         switch (a & 0xf0) {
333                         case MIDI_CMD_CONTROL:
334                         case MIDI_CMD_PGM_CHANGE:
335                         case MIDI_CMD_NOTE_OFF:
336                         case MIDI_CMD_NOTE_ON:
337                         case MIDI_CMD_NOTE_PRESSURE:
338                                 break;
339                         case MIDI_CMD_CHANNEL_PRESSURE:
340                         case MIDI_CMD_BENDER:
341                                 b_first = true;
342                         }
343                         break;
344                 case MIDI_CMD_BENDER:
345                         switch (a & 0xf0) {
346                         case MIDI_CMD_CONTROL:
347                         case MIDI_CMD_PGM_CHANGE:
348                         case MIDI_CMD_NOTE_OFF:
349                         case MIDI_CMD_NOTE_ON:
350                         case MIDI_CMD_NOTE_PRESSURE:
351                         case MIDI_CMD_CHANNEL_PRESSURE:
352                                 break;
353                         case MIDI_CMD_BENDER:
354                                 b_first = true;
355                         }
356                         break;
357                 }
358         }
359         
360         return b_first;
361 }
362         
363 /** Merge \a other into this buffer.  Realtime safe. */
364 bool
365 MidiBuffer::merge_in_place (const MidiBuffer &other)
366 {
367         if (other.size() && size()) {
368                 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("merge in place, sizes %1/%2\n", size(), other.size()));
369         }
370
371         if (other.size() == 0) {
372                 return true;
373         }
374
375         if (size() == 0) {
376                 copy (other);
377                 return true;
378         }
379
380         if (size() + other.size() > _capacity) {
381                 return false;
382         }
383
384         const_iterator them = other.begin();
385         iterator us = begin();
386
387         while (them != other.end()) {
388
389                 size_t bytes_to_merge;
390                 ssize_t merge_offset;
391
392                 /* gather up total size of events that are earlier than
393                    the event referenced by "us"
394                 */
395
396                 merge_offset = -1;
397                 bytes_to_merge = 0;
398
399                 while (them != other.end() && (*them).time() < (*us).time()) {
400                         if (merge_offset == -1) {
401                                 merge_offset = them.offset;
402                         }
403                         bytes_to_merge += sizeof (TimeType) + (*them).size();
404                         ++them;
405                 }
406
407                 /* "them" now points to either:
408                  *
409                  * 1) an event that has the same or later timestamp than the
410                  *        event pointed to by "us"
411                  *
412                  * OR
413                  *
414                  * 2) the end of the "other" buffer
415                  *
416                  * if "sz" is non-zero, there is data to be merged from "other"
417                  * into this buffer before we do anything else, corresponding
418                  * to the events from "other" that we skipped while advancing
419                  * "them". 
420                  */
421
422                 if (bytes_to_merge) {
423                         assert(merge_offset >= 0);
424                         /* move existing */
425                         memmove (_data + us.offset + bytes_to_merge, _data + us.offset, _size - us.offset);
426                         /* increase _size */
427                         _size += bytes_to_merge;
428                         assert (_size <= _capacity);
429                         /* insert new stuff */
430                         memcpy  (_data + us.offset, other._data + merge_offset, bytes_to_merge);
431                         /* update iterator to our own events. this is a miserable hack */
432                         us.offset += bytes_to_merge;
433                 } 
434
435                 /* if we're at the end of the other buffer, we're done */
436
437                 if (them == other.end()) {
438                         break;
439                 }
440
441                 /* if we have two messages messages with the same timestamp. we
442                  * must order them correctly.
443                  */
444
445                 if ((*us).time() == (*them).time()) {
446
447                         DEBUG_TRACE (DEBUG::MidiIO, 
448                                      string_compose ("simultaneous MIDI events discovered during merge, times %1/%2 status %3/%4\n",
449                                                      (*us).time(), (*them).time(),
450                                                      (int) *(_data + us.offset + sizeof (TimeType)),
451                                                      (int) *(other._data + them.offset + sizeof (TimeType))));
452                         
453                         uint8_t our_midi_status_byte = *(_data + us.offset + sizeof (TimeType));
454                         uint8_t their_midi_status_byte = *(other._data + them.offset + sizeof (TimeType));
455                         bool them_first = second_simultaneous_midi_byte_is_first (our_midi_status_byte, their_midi_status_byte);
456                         
457                         DEBUG_TRACE (DEBUG::MidiIO, string_compose ("other message came first ? %1\n", them_first));
458                         
459                         if (!them_first) {
460                                 /* skip past our own event */
461                                 ++us;
462                         }
463                                 
464                         bytes_to_merge = sizeof (TimeType) + (*them).size();
465                         
466                         /* move our remaining events later in the buffer by
467                          * enough to fit the one message we're going to merge
468                          */
469
470                         memmove (_data + us.offset + bytes_to_merge, _data + us.offset, _size - us.offset);
471                         /* increase _size */
472                         _size += bytes_to_merge;
473                         assert(_size <= _capacity);
474                         /* insert new stuff */
475                         memcpy  (_data + us.offset, other._data + them.offset, bytes_to_merge);
476                         /* update iterator to our own events. this is a miserable hack */
477                         us.offset += bytes_to_merge;
478                         /* 'us' is now an iterator to the event right after the
479                            new ones that we merged
480                         */
481                         if (them_first) {
482                                 /* need to skip the event pointed to by 'us'
483                                    since its at the same time as 'them'
484                                    (still), and we'll enter 
485                                 */
486
487                                 if (us != end()) {
488                                         ++us;
489                                 }
490                         }
491
492                         /* we merged one event from the other buffer, so
493                          * advance the iterator there.
494                          */
495
496                         ++them;
497
498                 } else {
499                         
500                         /* advance past our own events to get to the correct insertion
501                            point for the next event(s) from "other"
502                         */
503                 
504                         while (us != end() && (*us).time() <= (*them).time()) {
505                                 ++us;
506                         }
507                 }
508
509                 /* check to see if we reached the end of this buffer while
510                  * looking for the insertion point.
511                  */
512
513                 if (us == end()) {
514
515                         /* just append the rest of other and we're done*/
516                         
517                         memcpy (_data + us.offset, other._data + them.offset, other._size - them.offset);
518                         _size += other._size - them.offset;
519                         assert(_size <= _capacity);
520                         break;
521                 } 
522         }
523
524         return true;
525 }
526