ardour
midi_buffer.cc
Go to the documentation of this file.
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 
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
75 {
76  assert(_capacity >= copy._size);
77  _size = copy._size;
78  memcpy(_data, copy._data, copy._size);
79 }
80 
81 
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 
135 bool
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 
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
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
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 
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
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:
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:
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:
371  case MIDI_CMD_BENDER:
372  b_first = true;
373  }
374  break;
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;
384  case MIDI_CMD_BENDER:
385  b_first = true;
386  }
387  break;
388 
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:
396  break;
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:
410  break;
411  case MIDI_CMD_BENDER:
412  b_first = true;
413  }
414  break;
415  }
416  }
417 
418  return b_first;
419 }
420 
422 bool
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 
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 
size_t size() const
Definition: midi_buffer.h:55
DataType type() const
Definition: buffer.h:55
static bool second_simultaneous_midi_byte_is_first(uint8_t, uint8_t)
Definition: midi_buffer.cc:301
#define MIDI_CMD_NOTE_OFF
Definition: midi_events.h:107
void resize(size_t)
Definition: midi_buffer.cc:51
#define MIDI_CMD_NOTE_ON
Definition: midi_events.h:108
LIBPBD_API void stacktrace(std::ostream &out, int levels=0)
Definition: stacktrace.cc:115
bool silent() const
Definition: buffer.h:57
#define MIDI_CMD_CHANNEL_PRESSURE
Definition: midi_events.h:112
static bool midi_event_is_valid(const uint8_t *buffer, size_t len)
Definition: midi_util.h:113
pframes_t _capacity
Definition: buffer.h:81
#define MIDI_CMD_PGM_CHANGE
Definition: midi_events.h:111
LIBARDOUR_API uint64_t MidiIO
Definition: debug.cc:44
void silence(framecnt_t nframes, framecnt_t offset=0)
Definition: midi_buffer.cc:290
Definition: Beats.hpp:239
#define MIDI_CMD_BENDER
Definition: midi_events.h:113
uint8_t * _data
timestamp, event, timestamp, event, ...
Definition: midi_buffer.h:181
framepos_t TimeType
Definition: midi_buffer.h:38
uint8_t * reserve(TimeType time, size_t size)
Definition: midi_buffer.cc:268
uint32_t write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t *buf)
Definition: midi_buffer.cc:254
#define MIDI_CMD_CONTROL
Definition: midi_events.h:110
int64_t framecnt_t
Definition: types.h:76
bool merge_in_place(const MidiBuffer &other)
Definition: midi_buffer.cc:423
uint32_t size() const
Definition: Event.hpp:134
Definition: amp.h:29
Time time() const
Definition: Event.hpp:132
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
uint32_t EventType
Definition: types.hpp:43
void merge_from(const Buffer &src, framecnt_t nframes, framecnt_t dst_offset=0, framecnt_t src_offset=0)
Definition: midi_buffer.cc:118
void copy(const MidiBuffer &copy)
Definition: midi_buffer.cc:74
uint8_t type() const
Definition: MIDIEvent.hpp:60
LIBPBD_API uint64_t debug_bits
Definition: debug.cc:55
#define DEBUG_STR_APPEND(id, s)
Definition: debug.h:58
bool push_back(const Evoral::MIDIEvent< TimeType > &event)
Definition: midi_buffer.cc:136
virtual void clear()
Definition: buffer.h:70
Definition: debug.h:30
int cache_aligned_malloc(void **memptr, size_t size)
Definition: malign.cc:38
bool insert_event(const Evoral::MIDIEvent< TimeType > &event)
Definition: midi_buffer.cc:203
iterator begin()
Definition: midi_buffer.h:127
const uint8_t * buffer() const
Definition: Event.hpp:135
#define DEBUG_STR(id)
Definition: debug.h:57
void read_from(const Buffer &src, framecnt_t nframes, framecnt_t dst_offset=0, framecnt_t src_offset=0)
Definition: midi_buffer.cc:88
#define DEBUG_STR_DECL(id)
Definition: debug.h:56
#define MIDI_CMD_NOTE_PRESSURE
Definition: midi_events.h:109
bool _silent
Definition: buffer.h:82
Definition: ardour.h:41
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208