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)
38 // , _owns_data(false)
46 MidiBuffer::~MidiBuffer()
57 MidiBuffer::resize (size_t size)
61 if (size < _capacity) {
76 #ifdef NO_POSIX_MEMALIGN
77 _events = (Evoral::Event *) malloc(sizeof(Evoral::Event) * _capacity);
78 _data = (uint8_t *) malloc(sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
80 posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(Evoral::Event) * _capacity);
81 posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
88 MidiBuffer::copy(const MidiBuffer& copy)
90 assert(_capacity >= copy._capacity);
93 for (size_t i = 0; i < copy.size(); ++i)
98 /** Read events from @a src starting at time @a offset into the START of this buffer, for
99 * time duration @a nframes. Relative time, where 0 = start of buffer.
101 * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
104 MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
106 assert(src.type() == DataType::MIDI);
107 assert(&src != this);
109 const MidiBuffer& msrc = (MidiBuffer&)src;
111 assert(_capacity >= msrc.size());
119 for (size_t i=0; i < msrc.size(); ++i) {
120 const Evoral::MIDIEvent& ev = msrc[i];
121 //cout << "MidiBuffer::read_from event type: " << int(ev.type())
122 // << " time: " << ev.time() << " buffer size: " << _size << endl;
123 if (ev.time() < offset) {
124 //cout << "MidiBuffer::read_from skipped event before " << offset << endl;
125 } else if (ev.time() < (nframes + offset)) {
126 //cout << "MidiBuffer::read_from appending event" << endl;
129 //cerr << "MidiBuffer::read_from skipped event after "
130 // << nframes << " + " << offset << endl;
134 _silent = src.silent();
138 /** Push an event into the buffer.
140 * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
141 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
143 * @return false if operation failed (not enough room)
146 MidiBuffer::push_back(const Evoral::MIDIEvent& ev)
148 if (_size == _capacity) {
149 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
153 uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
155 memcpy(write_loc, ev.buffer(), ev.size());
157 _events[_size].set_buffer(ev.size(), write_loc, false);
159 /*cerr << "MidiBuffer: pushed @ " << _events[_size].time()
160 << " size = " << _size << endl;
161 for (size_t i = 0; i < _events[_size].size(); ++i) {
162 printf("%X ", _events[_size].buffer()[i]);
173 /** Push an event into the buffer.
175 * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
176 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
178 * @return false if operation failed (not enough room)
181 MidiBuffer::push_back(const jack_midi_event_t& ev)
183 if (_size == _capacity) {
184 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
188 uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
190 memcpy(write_loc, ev.buffer, ev.size);
191 _events[_size].time() = (double)ev.time;
192 _events[_size].set_buffer(ev.size, write_loc, false);
194 /*cerr << "MidiBuffer: pushed @ " << _events[_size].time()
195 << " size = " << _size << endl;
196 for (size_t i = 0; i < _events[_size].size(); ++i) {
197 printf("%X ", _events[_size].buffer()[i]);
208 /** Reserve space for a new event in the buffer.
210 * This call is for copying MIDI directly into the buffer, the data location
211 * (of sufficient size to write \a size bytes) is returned, or 0 on failure.
212 * This call MUST be immediately followed by a write to the returned data
213 * location, or the buffer will be corrupted and very nasty things will happen.
216 MidiBuffer::reserve(double time, size_t size)
218 if (size > MAX_EVENT_SIZE) {
219 cerr << "WARNING: Failed to reserve " << size << " bytes for event";
223 if (_size == _capacity)
226 uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
228 _events[_size].time() = time;
229 _events[_size].set_buffer(size, write_loc, false);
232 //cerr << "MidiBuffer: reserved, size = " << _size << endl;
241 MidiBuffer::silence(nframes_t dur, nframes_t offset)
243 // FIXME use parameters
245 cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl;
247 memset(_events, 0, sizeof(Evoral::Event) * _capacity);
248 memset(_data, 0, sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
254 MidiBuffer::merge_in_place( const MidiBuffer &other )
256 if( other.size() == 0 )
259 if( this->size() == 0 ) {
265 MidiBuffer merge_buffer( 0 );
266 Evoral::MIDIEvent onstack_events[_capacity];
267 uint8_t onstack_data[_capacity * MAX_EVENT_SIZE];
268 merge_buffer._events = onstack_events;
269 merge_buffer._data = onstack_data;
270 merge_buffer._size = 0;
272 bool retval = merge_buffer.merge( *this, other );
274 copy( merge_buffer );
276 // set pointers to zero again, so destructor
277 // does not end in calling free() for memory
279 merge_buffer._events = 0;
280 merge_buffer._data = 0;
286 /** Clear, and merge \a a and \a b into this buffer.
288 * FIXME: This is slow.
290 * \return true if complete merge was successful
293 MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
297 // This is mostly the case :(
306 size_t count = a.size() + b.size();
310 if (size() == capacity()) {
311 cerr << "WARNING: MIDI buffer overrun, events lost!" << endl;
315 if (a_index == a.size()) {
316 push_back(b[b_index]);
318 } else if (b_index == b.size()) {
319 push_back(a[a_index]);
322 const Evoral::MIDIEvent& a_ev = a[a_index];
323 const Evoral::MIDIEvent& b_ev = b[b_index];
325 if (a_ev.time() <= b_ev.time()) {