Ardour  8.12
midi_buffer.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2016 David Robillard <d@drobilla.net>
3  * Copyright (C) 2007-2018 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2009-2010 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2009 Hans Baier <hansfbaier@googlemail.com>
6  * Copyright (C) 2014-2016 Robin Gareus <robin@gareus.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #ifndef __ardour_midi_buffer_h__
24 #define __ardour_midi_buffer_h__
25 
26 #include "evoral/Event.h"
27 #include "evoral/EventSink.h"
28 #include "evoral/midi_util.h"
29 #include "evoral/types.h"
30 
31 #include "ardour/buffer.h"
32 #include "ardour/parameter_types.h"
33 
34 namespace ARDOUR {
35 
36 
38 class LIBARDOUR_API MidiBuffer : public Buffer, public Evoral::EventSink<samplepos_t>
39 {
40 public:
42 
43  MidiBuffer(size_t capacity);
45 
46  void clear();
47  void silence (samplecnt_t nframes, samplecnt_t offset = 0);
48  void read_from (const Buffer& src, samplecnt_t nframes, sampleoffset_t dst_offset = 0, sampleoffset_t src_offset = 0);
49  void merge_from (const Buffer& src, samplecnt_t nframes, sampleoffset_t dst_offset = 0, sampleoffset_t src_offset = 0);
50 
51  void copy(const MidiBuffer& copy);
52  void copy(MidiBuffer const * const);
53 
54  bool push_back(const Evoral::Event<TimeType>& event);
55  bool push_back(TimeType time, Evoral::EventType event_type, size_t size, const uint8_t* data);
56 
57  uint8_t* reserve(TimeType time, Evoral::EventType event_type, size_t size);
58 
59  void resize(size_t);
60  size_t size() const { return _size; }
61  bool empty() const { return _size == 0; }
62  bool silent_data () const { return _size == 0; }
63 
65  bool merge_in_place(const MidiBuffer &other);
66 
68  uint32_t write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf);
69 
70  template<typename BufferType, typename EventType>
72  {
73  public:
74  iterator_base (BufferType& b, samplecnt_t o)
75  : buffer (&b)
76  , offset (o)
77  {
78  }
79 
81  : buffer (o.buffer)
82  , offset (o.offset)
83  {
84  }
85 
87  if (&o != this) {
88  buffer = o.buffer;
89  offset = o.offset;
90  }
91  return *this;
92  }
93 
94  inline EventType operator*() const {
95  uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType) + sizeof (Evoral::EventType);
96  int event_size = Evoral::midi_event_size(ev_start);
97  assert(event_size >= 0);
98  return EventType(
99  *((Evoral::EventType*)(buffer->_data + offset + sizeof(TimeType))),
100  *((TimeType*)(buffer->_data + offset)),
101  event_size, ev_start);
102  }
103 
104  inline EventType operator*() {
105  uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType) + sizeof (Evoral::EventType);
106  int event_size = Evoral::midi_event_size(ev_start);
107  assert(event_size >= 0);
108  return EventType(
109  *(reinterpret_cast<Evoral::EventType*>((uintptr_t)(buffer->_data + offset + sizeof(TimeType)))),
110  *(reinterpret_cast<TimeType*>((uintptr_t)(buffer->_data + offset))),
111  event_size, ev_start);
112  }
113 
114  inline TimeType * timeptr() {
115  return reinterpret_cast<TimeType*>((uintptr_t)(buffer->_data + offset));
116  }
117 
119  return reinterpret_cast<Evoral::EventType*>((uintptr_t)(buffer->_data + offset + sizeof(TimeType)));
120  }
121 
123  uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType) + sizeof (Evoral::EventType);
124  int event_size = Evoral::midi_event_size(ev_start);
125  assert(event_size >= 0);
126  offset += align32 (sizeof(TimeType) + sizeof (Evoral::EventType) + event_size);
127  return *this;
128  }
129 
130  inline bool operator!=(const iterator_base<BufferType, EventType>& other) const {
131  return (buffer != other.buffer) || (offset != other.offset);
132  }
133 
134  inline bool operator==(const iterator_base<BufferType, EventType>& other) const {
135  return (buffer == other.buffer) && (offset == other.offset);
136  }
137 
138  BufferType* buffer;
139  size_t offset;
140  };
141 
144 
145  iterator begin() { return iterator(*this, 0); }
146  iterator end() { return iterator(*this, _size); }
147 
148  const_iterator begin() const { return const_iterator(*this, 0); }
149  const_iterator end() const { return const_iterator(*this, _size); }
150 
151  iterator erase(const iterator& i) {
152  assert (i.buffer == this);
153  uint8_t* ev_start = _data + i.offset + sizeof (TimeType) + sizeof (Evoral::EventType);
154  int event_size = Evoral::midi_event_size (ev_start);
155 
156  if (event_size < 0) {
157  /* unknown size, sysex: return end() */
158  return end();
159  }
160 
161  size_t total_data_deleted = align32 (sizeof(TimeType) + sizeof (Evoral::EventType) + event_size);
162 
163  if (total_data_deleted >= _size) {
164  _size = 0;
165  _silent = true;
166  return end();
167  }
168 
169  if (i.offset + total_data_deleted >= _size) {
170  assert (_size > total_data_deleted);
171  _size -= total_data_deleted;
172  return end();
173  }
174 
175  /* we need to avoid the temporary malloc that memmove would do,
176  so copy by hand. remember: this is small amounts of data ...
177  */
178  size_t a, b;
179  for (a = i.offset, b = i.offset + total_data_deleted; b < _size; ++b, ++a) {
180  _data[a] = _data[b];
181  }
182 
183  _size -= total_data_deleted;
184 
185  assert (_size > 0);
186 
187  /* all subsequent iterators are now invalid, and the one we
188  * return should refer to the event we copied, which was after
189  * the one we just erased.
190  */
191 
192  return iterator (*this, i.offset);
193  }
194 
200  static bool second_simultaneous_midi_byte_is_first (uint8_t, uint8_t);
201 
202 private:
203  friend class iterator_base< MidiBuffer, Evoral::Event<TimeType> >;
204  friend class iterator_base< const MidiBuffer, const Evoral::Event<TimeType> >;
205 
206  static size_t align32 (size_t s) {
207 #if defined(__arm__) || defined(__aarch64__)
208  return ((s - 1) | 3) + 1;
209 #else
210  return s;
211 #endif
212  }
213 
214  uint8_t* _data;
216 };
217 
218 } // namespace ARDOUR
219 
220 #endif // __ardour_midi_buffer_h__
iterator_base(const iterator_base< BufferType, EventType > &o)
Definition: midi_buffer.h:80
iterator_base< BufferType, EventType > & operator++()
Definition: midi_buffer.h:122
iterator_base(BufferType &b, samplecnt_t o)
Definition: midi_buffer.h:74
bool operator==(const iterator_base< BufferType, EventType > &other) const
Definition: midi_buffer.h:134
Evoral::EventType * event_type_ptr()
Definition: midi_buffer.h:118
bool operator!=(const iterator_base< BufferType, EventType > &other) const
Definition: midi_buffer.h:130
MidiBuffer(size_t capacity)
uint8_t * _data
[timestamp, event-type, event]*
Definition: midi_buffer.h:214
iterator_base< MidiBuffer, Evoral::Event< TimeType > > iterator
Definition: midi_buffer.h:142
iterator erase(const iterator &i)
Definition: midi_buffer.h:151
bool silent_data() const
Definition: midi_buffer.h:62
bool merge_in_place(const MidiBuffer &other)
void read_from(const Buffer &src, samplecnt_t nframes, sampleoffset_t dst_offset=0, sampleoffset_t src_offset=0)
void resize(size_t)
void silence(samplecnt_t nframes, samplecnt_t offset=0)
void merge_from(const Buffer &src, samplecnt_t nframes, sampleoffset_t dst_offset=0, sampleoffset_t src_offset=0)
void copy(MidiBuffer const *const)
const_iterator begin() const
Definition: midi_buffer.h:148
const_iterator end() const
Definition: midi_buffer.h:149
samplepos_t TimeType
Definition: midi_buffer.h:41
size_t size() const
Definition: midi_buffer.h:60
uint32_t write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t *buf)
iterator_base< const MidiBuffer, const Evoral::Event< TimeType > > const_iterator
Definition: midi_buffer.h:143
bool push_back(const Evoral::Event< TimeType > &event)
bool empty() const
Definition: midi_buffer.h:61
iterator begin()
Definition: midi_buffer.h:145
uint8_t * reserve(TimeType time, Evoral::EventType event_type, size_t size)
bool push_back(TimeType time, Evoral::EventType event_type, size_t size, const uint8_t *data)
bool insert_event(const Evoral::Event< TimeType > &event)
void copy(const MidiBuffer &copy)
#define LIBARDOUR_API
uint32_t pframes_t
Temporal::samplecnt_t samplecnt_t
Temporal::sampleoffset_t sampleoffset_t
Temporal::samplepos_t samplepos_t
Definition: editor.h:87
static int midi_event_size(uint8_t status)