2 Copyright (C) 2006-2007 Paul Davis
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)
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
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.
21 #include <ardour/midi_buffer.h>
24 static const int CPU_CACHE_ALIGN = 64;
26 static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
30 using namespace ARDOUR;
33 // FIXME: mirroring for MIDI buffers?
34 MidiBuffer::MidiBuffer(size_t capacity)
35 : Buffer(DataType::MIDI, capacity)
45 MidiBuffer::~MidiBuffer()
56 MidiBuffer::resize(size_t size)
60 if (size < _capacity) {
70 #ifdef NO_POSIX_MEMALIGN
71 _events = (Evoral::MIDIEvent *) malloc(sizeof(Evoral::MIDIEvent) * _capacity);
72 _data = (uint8_t *) malloc(sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
74 posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(Evoral::Event) * _capacity);
75 posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
82 MidiBuffer::copy(const MidiBuffer& copy)
84 assert(_capacity >= copy._capacity);
87 for (size_t i = 0; i < copy.size(); ++i)
92 /** Read events from @a src starting at time @a offset into the START of this buffer, for
93 * time duration @a nframes. Relative time, where 0 = start of buffer.
95 * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
98 MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
100 assert(src.type() == DataType::MIDI);
101 assert(&src != this);
103 const MidiBuffer& msrc = (MidiBuffer&)src;
105 assert(_capacity >= msrc.size());
113 for (size_t i = 0; i < msrc.size(); ++i) {
114 const Evoral::MIDIEvent& ev = msrc[i];
115 //cout << "MidiBuffer::read_from event type: " << int(ev.type())
116 // << " time: " << ev.time() << " buffer size: " << _size << endl;
117 if (ev.time() < offset) {
118 //cout << "MidiBuffer::read_from skipped event before " << offset << endl;
119 } else if (ev.time() < (nframes + offset)) {
120 //cout << "MidiBuffer::read_from appending event" << endl;
123 //cerr << "MidiBuffer::read_from skipped event after "
124 // << nframes << " + " << offset << endl;
128 _silent = src.silent();
132 /** Push an event into the buffer.
134 * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
135 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
137 * @return false if operation failed (not enough room)
140 MidiBuffer::push_back(const Evoral::MIDIEvent& ev)
142 if (_size == _capacity) {
143 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
147 uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
149 memcpy(write_loc, ev.buffer(), ev.size());
151 _events[_size].set_buffer(ev.size(), write_loc, false);
153 /*cerr << "MidiBuffer: pushed @ " << _events[_size].time()
154 << " size = " << _size << endl;
155 for (size_t i = 0; i < _events[_size].size(); ++i) {
156 printf("%X ", _events[_size].buffer()[i]);
167 /** Push an event into the buffer.
169 * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
170 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
172 * @return false if operation failed (not enough room)
175 MidiBuffer::push_back(const jack_midi_event_t& ev)
177 if (_size == _capacity) {
178 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
182 uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
184 memcpy(write_loc, ev.buffer, ev.size);
185 _events[_size].time() = (double)ev.time;
186 _events[_size].set_buffer(ev.size, write_loc, false);
188 /*cerr << "MidiBuffer: pushed @ " << _events[_size].time()
189 << " size = " << _size << endl;
190 for (size_t i = 0; i < _events[_size].size(); ++i) {
191 printf("%X ", _events[_size].buffer()[i]);
202 /** Reserve space for a new event in the buffer.
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.
210 MidiBuffer::reserve(double time, size_t size)
212 if (size > MAX_EVENT_SIZE) {
213 cerr << "WARNING: Failed to reserve " << size << " bytes for event";
217 if (_size == _capacity) {
221 uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
223 _events[_size].time() = time;
224 _events[_size].set_buffer(size, write_loc, false);
227 //cerr << "MidiBuffer: reserved, size = " << _size << endl;
236 MidiBuffer::silence(nframes_t dur, nframes_t offset)
238 // FIXME use parameters
240 cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl;
242 memset(_events, 0, sizeof(Evoral::Event) * _capacity);
243 memset(_data, 0, sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
249 MidiBuffer::merge_in_place(const MidiBuffer &other)
251 if (other.size() == 0) {
255 if (this->size() == 0) {
261 MidiBuffer merge_buffer(0);
262 Evoral::MIDIEvent onstack_events[_capacity];
263 uint8_t onstack_data[_capacity * MAX_EVENT_SIZE];
264 merge_buffer._events = onstack_events;
265 merge_buffer._data = onstack_data;
266 merge_buffer._size = 0;
268 bool retval = merge_buffer.merge(*this, other);
272 // set pointers to zero again, so destructor
273 // does not end in calling free() for memory
275 merge_buffer._events = 0;
276 merge_buffer._data = 0;
282 /** Clear, and merge \a a and \a b into this buffer.
284 * FIXME: This is slow.
286 * \return true if complete merge was successful
289 MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
303 size_t count = a.size() + b.size();
307 if (size() == capacity()) {
308 cerr << "WARNING: MIDI buffer overrun, events lost!" << endl;
312 if (a_index == a.size()) {
313 push_back(b[b_index]);
315 } else if (b_index == b.size()) {
316 push_back(a[a_index]);
319 const Evoral::MIDIEvent& a_ev = a[a_index];
320 const Evoral::MIDIEvent& b_ev = b[b_index];
322 if (a_ev.time() <= b_ev.time()) {