Ardour  9.0-pre0-582-g084a23a80d
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 #pragma once
24 
25 #include "evoral/Event.h"
26 #include "evoral/EventSink.h"
27 #include "evoral/midi_util.h"
28 #include "evoral/types.h"
29 
30 #include "ardour/buffer.h"
31 #include "ardour/parameter_types.h"
32 
33 namespace ARDOUR {
34 
35 
37 class LIBARDOUR_API MidiBuffer : public Buffer, public Evoral::EventSink<samplepos_t>
38 {
39 public:
41 
42  MidiBuffer(size_t capacity);
44 
45  void clear();
46  void silence (samplecnt_t nframes, samplecnt_t offset = 0);
47  void read_from (const Buffer& src, samplecnt_t nframes, sampleoffset_t dst_offset = 0, sampleoffset_t src_offset = 0);
48  void merge_from (const Buffer& src, samplecnt_t nframes, sampleoffset_t dst_offset = 0, sampleoffset_t src_offset = 0);
49 
50  void copy(const MidiBuffer& copy);
51  void copy(MidiBuffer const * const);
52 
53  bool push_back(const Evoral::Event<TimeType>& event);
54  bool push_back(TimeType time, Evoral::EventType event_type, size_t size, const uint8_t* data);
55 
56  uint8_t* reserve(TimeType time, Evoral::EventType event_type, size_t size);
57 
58  void resize(size_t);
59  size_t size() const { return _size; }
60  bool empty() const { return _size == 0; }
61  bool silent_data () const { return _size == 0; }
62 
64  bool merge_in_place(const MidiBuffer &other);
65 
67  uint32_t write(TimeType time, Evoral::EventType type, uint32_t size, const uint8_t* buf);
68 
69  template<typename BufferType, typename EventType>
71  {
72  public:
73  iterator_base (BufferType& b, samplecnt_t o)
74  : buffer (&b)
75  , offset (o)
76  {
77  }
78 
80  : buffer (o.buffer)
81  , offset (o.offset)
82  {
83  }
84 
86  if (&o != this) {
87  buffer = o.buffer;
88  offset = o.offset;
89  }
90  return *this;
91  }
92 
93  inline EventType operator*() const {
94  uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType) + sizeof (Evoral::EventType);
95  int event_size = Evoral::midi_event_size(ev_start);
96  assert(event_size >= 0);
97  return EventType(
98  *((Evoral::EventType*)(buffer->_data + offset + sizeof(TimeType))),
99  *((TimeType*)(buffer->_data + offset)),
100  event_size, ev_start);
101  }
102 
103  inline EventType operator*() {
104  uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType) + sizeof (Evoral::EventType);
105  int event_size = Evoral::midi_event_size(ev_start);
106  assert(event_size >= 0);
107  return EventType(
108  *(reinterpret_cast<Evoral::EventType*>((uintptr_t)(buffer->_data + offset + sizeof(TimeType)))),
109  *(reinterpret_cast<TimeType*>((uintptr_t)(buffer->_data + offset))),
110  event_size, ev_start);
111  }
112 
113  inline TimeType * timeptr() {
114  return reinterpret_cast<TimeType*>((uintptr_t)(buffer->_data + offset));
115  }
116 
118  return reinterpret_cast<Evoral::EventType*>((uintptr_t)(buffer->_data + offset + sizeof(TimeType)));
119  }
120 
122  uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType) + sizeof (Evoral::EventType);
123  int event_size = Evoral::midi_event_size(ev_start);
124  assert(event_size >= 0);
125  offset += align32 (sizeof(TimeType) + sizeof (Evoral::EventType) + event_size);
126  return *this;
127  }
128 
129  inline bool operator!=(const iterator_base<BufferType, EventType>& other) const {
130  return (buffer != other.buffer) || (offset != other.offset);
131  }
132 
133  inline bool operator==(const iterator_base<BufferType, EventType>& other) const {
134  return (buffer == other.buffer) && (offset == other.offset);
135  }
136 
137  BufferType* buffer;
138  size_t offset;
139  };
140 
143 
144  iterator begin() { return iterator(*this, 0); }
145  iterator end() { return iterator(*this, _size); }
146 
147  const_iterator begin() const { return const_iterator(*this, 0); }
148  const_iterator end() const { return const_iterator(*this, _size); }
149 
150  iterator erase(const iterator& i) {
151  assert (i.buffer == this);
152  uint8_t* ev_start = _data + i.offset + sizeof (TimeType) + sizeof (Evoral::EventType);
153  int event_size = Evoral::midi_event_size (ev_start);
154 
155  if (event_size < 0) {
156  /* unknown size, sysex: return end() */
157  return end();
158  }
159 
160  size_t total_data_deleted = align32 (sizeof(TimeType) + sizeof (Evoral::EventType) + event_size);
161 
162  if (total_data_deleted >= _size) {
163  _size = 0;
164  _silent = true;
165  return end();
166  }
167 
168  if (i.offset + total_data_deleted >= _size) {
169  assert (_size > total_data_deleted);
170  _size -= total_data_deleted;
171  return end();
172  }
173 
174  /* we need to avoid the temporary malloc that memmove would do,
175  so copy by hand. remember: this is small amounts of data ...
176  */
177  size_t a, b;
178  for (a = i.offset, b = i.offset + total_data_deleted; b < _size; ++b, ++a) {
179  _data[a] = _data[b];
180  }
181 
182  _size -= total_data_deleted;
183 
184  assert (_size > 0);
185 
186  /* all subsequent iterators are now invalid, and the one we
187  * return should refer to the event we copied, which was after
188  * the one we just erased.
189  */
190 
191  return iterator (*this, i.offset);
192  }
193 
199  static bool second_simultaneous_midi_byte_is_first (uint8_t, uint8_t);
200 
201 private:
202  friend class iterator_base< MidiBuffer, Evoral::Event<TimeType> >;
203  friend class iterator_base< const MidiBuffer, const Evoral::Event<TimeType> >;
204 
205  static size_t align32 (size_t s) {
206 #if defined(__arm__) || defined(__aarch64__)
207  return ((s - 1) | 3) + 1;
208 #else
209  return s;
210 #endif
211  }
212 
213  uint8_t* _data;
215 };
216 
217 } // namespace ARDOUR
218 
iterator_base(const iterator_base< BufferType, EventType > &o)
Definition: midi_buffer.h:79
iterator_base< BufferType, EventType > & operator++()
Definition: midi_buffer.h:121
iterator_base(BufferType &b, samplecnt_t o)
Definition: midi_buffer.h:73
bool operator==(const iterator_base< BufferType, EventType > &other) const
Definition: midi_buffer.h:133
Evoral::EventType * event_type_ptr()
Definition: midi_buffer.h:117
bool operator!=(const iterator_base< BufferType, EventType > &other) const
Definition: midi_buffer.h:129
MidiBuffer(size_t capacity)
uint8_t * _data
[timestamp, event-type, event]*
Definition: midi_buffer.h:213
iterator_base< MidiBuffer, Evoral::Event< TimeType > > iterator
Definition: midi_buffer.h:141
iterator erase(const iterator &i)
Definition: midi_buffer.h:150
bool silent_data() const
Definition: midi_buffer.h:61
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:147
const_iterator end() const
Definition: midi_buffer.h:148
samplepos_t TimeType
Definition: midi_buffer.h:40
size_t size() const
Definition: midi_buffer.h:59
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:142
bool push_back(const Evoral::Event< TimeType > &event)
bool empty() const
Definition: midi_buffer.h:60
iterator begin()
Definition: midi_buffer.h:144
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:86
static int midi_event_size(uint8_t status)