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 */
34 // FIXME: mirroring for MIDI buffers?
35 MidiBuffer::MidiBuffer(size_t capacity)
36 : Buffer(DataType::MIDI, capacity)
47 MidiBuffer::resize (size_t size)
57 #ifdef NO_POSIX_MEMALIGN
58 _events = (MidiEvent *) malloc(sizeof(MidiEvent) * _capacity);
59 _data = (Byte *) malloc(sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
61 posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MidiEvent) * _capacity);
62 posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
69 MidiBuffer::copy(const MidiBuffer& copy)
71 assert(_capacity >= copy._capacity);
74 for (size_t i=0; i < copy.size(); ++i)
78 MidiBuffer::~MidiBuffer()
85 /** Read events from @a src starting at time @a offset into the START of this buffer, for
86 * time direction @a nframes. Relative time, where 0 = start of buffer.
88 * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
91 MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
93 assert(src.type() == DataType::MIDI);
94 const MidiBuffer& msrc = (MidiBuffer&)src;
96 assert(_capacity >= src.size());
102 for (size_t i=0; i < src.size(); ++i) {
103 const MidiEvent& ev = msrc[i];
104 if (ev.time() >= offset && ev.time() < offset+nframes) {
105 //cerr << "MidiBuffer::read_from got event, " << ev.time() << endl;
108 //cerr << "MidiBuffer event out of range, " << ev.time() << endl;
112 _silent = src.silent();
116 /** Push an event into the buffer.
118 * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
119 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
121 * @return false if operation failed (not enough room)
124 MidiBuffer::push_back(const MidiEvent& ev)
126 if (_size == _capacity)
129 Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
131 memcpy(write_loc, ev.buffer(), ev.size());
133 _events[_size].set_buffer(write_loc, false);
136 //cerr << "MidiBuffer: pushed, size = " << _size << endl;
144 /** Push an event into the buffer.
146 * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
147 * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
149 * @return false if operation failed (not enough room)
152 MidiBuffer::push_back(const jack_midi_event_t& ev)
154 if (_size == _capacity)
157 Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
159 memcpy(write_loc, ev.buffer, ev.size);
160 _events[_size].time() = (double)ev.time;
161 _events[_size].size() = ev.size;
162 _events[_size].set_buffer(write_loc, false);
165 //cerr << "MidiBuffer: pushed, size = " << _size << endl;
173 /** Reserve space for a new event in the buffer.
175 * This call is for copying MIDI directly into the buffer, the data location
176 * (of sufficient size to write \a size bytes) is returned, or NULL on failure.
177 * This call MUST be immediately followed by a write to the returned data
178 * location, or the buffer will be corrupted and very nasty things will happen.
181 MidiBuffer::reserve(double time, size_t size)
183 assert(size <= MAX_EVENT_SIZE);
185 if (_size == _capacity)
188 Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
190 _events[_size].time() = time;
191 _events[_size].size() = size;
192 _events[_size].set_buffer(write_loc, false);
195 //cerr << "MidiBuffer: reserved, size = " << _size << endl;
204 MidiBuffer::silence(nframes_t dur, nframes_t offset)
206 // FIXME use parameters
208 cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl;
210 memset(_events, 0, sizeof(MidiEvent) * _capacity);
211 memset(_data, 0, sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
217 /** Clear, and merge \a a and \a b into this buffer.
219 * FIXME: This is slow.
221 * \return true if complete merge was successful
224 MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
228 // Die if a merge isn't necessary as it's expensive
229 assert(a.size() > 0 && b.size() > 0);
233 size_t count = a.size() + b.size();
235 while (count > 0 && a_index < a.size() && b_index < b.size()) {
237 if (size() == capacity()) {
238 cerr << "WARNING: MIDI buffer overrun, events lost!" << endl;
242 if (a_index == a.size()) {
243 push_back(a[a_index]);
245 } else if (b_index == b.size()) {
246 push_back(b[b_index]);
249 const MidiEvent& a_ev = a[a_index];
250 const MidiEvent& b_ev = b[b_index];
252 if (a_ev.time() <= b_ev.time()) {
268 } // namespace ARDOUR