2 * Copyright (C) 2019 Paul Davis <paul@linuxaudiosystems.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "pbd/malign.h"
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/debug.h"
25 #include "pbd/stacktrace.h"
27 #include "evoral/midi_util.h"
29 #include "ardour/debug.h"
30 #include "ardour/midi_buffer.h"
31 #include "ardour/midi_state_tracker.h"
32 #include "ardour/rt_midibuffer.h"
35 using namespace ARDOUR;
38 RTMidiBuffer::RTMidiBuffer (size_t capacity)
51 RTMidiBuffer::~RTMidiBuffer()
53 cache_aligned_free (_data);
54 cache_aligned_free (_pool);
58 RTMidiBuffer::resize (size_t size)
60 if (_data && size < _capacity) {
70 Item* old_data = _data;
72 cache_aligned_malloc ((void**) &_data, size * sizeof (Item));
75 memcpy (_data, old_data, _size);
76 cache_aligned_free (old_data);
83 RTMidiBuffer::dump (uint32_t cnt)
85 cerr << this << " total items: " << _size << " within " << _capacity << " blob pool: " << _pool_capacity << " used " << _pool_size << endl;
87 for (uint32_t i = 0; i < _size && i < cnt; ++i) {
89 Item* item = &_data[i];
95 /* more than 3 bytes ... indirect */
97 uint32_t offset = item->offset & ~(1<<(sizeof(uint8_t)-1));
98 Blob* blob = reinterpret_cast<Blob*> (&_pool[offset]);
105 size = Evoral::midi_event_size (item->bytes[1]);
106 addr = &item->bytes[1];
110 cerr << "@ " << item->timestamp << " sz=" << size << '\t';
113 for (size_t j =0 ; j < size; ++j) {
114 cerr << "0x" << hex << (int)addr[j] << dec << '/' << (int)addr[i] << ' ';
121 RTMidiBuffer::write (TimeType time, Evoral::EventType /*type*/, uint32_t size, const uint8_t* buf)
123 /* This buffer stores only MIDI, we don't care about the value of "type" */
125 if (_size == _capacity) {
126 resize (_capacity + 1024); // XXX 1024 is completely arbitrary
129 _data[_size].timestamp = time;
133 uint32_t off = store_blob (size, buf);
135 /* this indicates that the data (more than 3 bytes) is not inline */
136 _data[_size].offset = (off | (1<<(sizeof(uint8_t)-1)));
140 assert ((int) size == Evoral::midi_event_size (buf[0]));
142 /* this indicates that the data (up to 3 bytes) is inline */
143 _data[_size].bytes[0] = 0;
147 _data[_size].bytes[3] = buf[2];
150 _data[_size].bytes[2] = buf[1];
153 _data[_size].bytes[1] = buf[0];
165 item_timestamp_earlier (ARDOUR::RTMidiBuffer::Item const & item, samplepos_t time)
167 return item.timestamp < time;
173 RTMidiBuffer::read (MidiBuffer& dst, samplepos_t start, samplepos_t end, MidiStateTracker& tracker, samplecnt_t offset)
175 Item* iend = _data+_size;
176 Item* item = lower_bound (_data, iend, start, item_timestamp_earlier);
180 TimeType unadjusted_time;
183 DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("read from %1 .. %2 .. initial index = %3 (time = %4)\n", start, end, item, item->timestamp));
185 while ((item < iend) && (item->timestamp < end)) {
187 TimeType evtime = item->timestamp;
190 unadjusted_time = evtime;
192 /* Adjust event times to be relative to 'start', taking
193 * 'offset' into account.
202 if (item->bytes[0]) {
204 /* more than 3 bytes ... indirect */
206 uint32_t offset = item->offset & ~(1<<(sizeof(uint8_t)-1));
207 Blob* blob = reinterpret_cast<Blob*> (&_pool[offset]);
214 size = Evoral::midi_event_size (item->bytes[1]);
215 addr = &item->bytes[1];
219 uint8_t* write_loc = dst.reserve (evtime, size);
221 if (write_loc == 0) {
222 DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events, dst size = %2\n", count, dst.size()));
226 memcpy (write_loc, addr, size);
228 DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("read event sz %1 @ %2\n", size, unadjusted_time));
229 tracker.track (addr);
235 DEBUG_TRACE (DEBUG::MidiRingBuffer, string_compose ("total events found for %1 .. %2 = %3\n", start, end, count));
240 RTMidiBuffer::alloc_blob (uint32_t size)
242 if (_pool_size + size > _pool_capacity) {
243 uint8_t* old_pool = _pool;
245 _pool_capacity += size * 4;
247 cache_aligned_malloc ((void **) &_pool, _pool_capacity * 2);
248 memcpy (_pool, old_pool, _pool_size);
249 cache_aligned_free (old_pool);
252 uint32_t offset = _pool_size;
259 RTMidiBuffer::store_blob (uint32_t size, uint8_t const * data)
261 uint32_t offset = alloc_blob (size);
262 uint8_t* addr = &_pool[offset];
264 *(reinterpret_cast<uint32_t*> (addr)) = size;
265 addr += sizeof (size);
266 memcpy (addr, data, size);
272 RTMidiBuffer::clear ()
274 /* mark main array as empty */
276 /* free the entire current pool size, if any */