2 Copyright (C) 2006 Paul Davis
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
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #ifndef __ardour_midi_ring_buffer_h__
20 #define __ardour_midi_ring_buffer_h__
23 #include <ardour/types.h>
24 #include <pbd/ringbufferNPT.h>
25 #include <ardour/buffer.h>
30 * (necessary because MIDI events are variable sized so a generic RB won't do).
32 * ALL publically accessible sizes refer to event COUNTS. What actually goes
33 * on in here is none of the callers business :)
35 class MidiRingBuffer {
37 MidiRingBuffer (size_t size)
39 , _max_event_size(MidiBuffer::max_event_size())
40 , _ev_buf(new MidiEvent[size])
41 , _raw_buf(new RawMidi[size * _max_event_size])
44 assert(read_space() == 0);
45 assert(write_space() == size - 1);
48 virtual ~MidiRingBuffer() {
54 /* !!! NOT THREAD SAFE !!! */
55 g_atomic_int_set (&_write_ptr, 0);
56 g_atomic_int_set (&_read_ptr, 0);
59 size_t write_space () {
62 w = g_atomic_int_get (&_write_ptr);
63 r = g_atomic_int_get (&_read_ptr);
66 return ((r - w + _size) % _size) - 1;
74 size_t read_space () {
77 w = g_atomic_int_get (&_write_ptr);
78 r = g_atomic_int_get (&_read_ptr);
83 return (w - r + _size) % _size;
87 size_t capacity() const { return _size; }
89 /** Read one event and appends it to @a out. */
90 //size_t read(MidiBuffer& out);
92 /** Write one event (@a in) */
93 size_t write(const MidiEvent& in); // deep copies in
95 /** Read events all events up to time @a end into @a out, leaving stamps intact.
96 * Any events before @a start will be dropped. */
97 size_t read(MidiBuffer& out, jack_nframes_t start, jack_nframes_t end);
99 /** Write all events from @a in, applying @a offset to all time stamps */
100 size_t write(const MidiBuffer& in, jack_nframes_t offset = 0);
102 inline void clear_event(size_t index);
107 mutable gint _write_ptr;
108 mutable gint _read_ptr;
110 size_t _size; // size (capacity) in events
111 size_t _max_event_size; // ratio of raw_buf size to ev_buf size
112 MidiEvent* _ev_buf; // these point into...
113 RawMidi* _raw_buf; // this
117 /** Just for sanity checking */
119 MidiRingBuffer::clear_event(size_t index)
121 memset(&_ev_buf[index].buffer, 0, _max_event_size);
122 _ev_buf[index].time = 0;
123 _ev_buf[index].size = 0;
124 _ev_buf[index].buffer = 0;
129 MidiRingBuffer::read (MidiBuffer& buf)
131 const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
133 if (read_space() == 0) {
136 MidiEvent* const read_ev = &_ev_buf[priv_read_ptr];
137 assert(read_ev->size > 0);
138 buf.push_back(*read_ev);
139 printf("MRB - read %xd %d %d with time %u at index %zu\n",
140 read_ev->buffer[0], read_ev->buffer[1], read_ev->buffer[2], read_ev->time,
142 clear_event(priv_read_ptr);
143 g_atomic_int_set(&_read_ptr, (priv_read_ptr + 1) % _size);
149 MidiRingBuffer::write (const MidiEvent& ev)
151 //static jack_nframes_t last_write_time = 0;
155 size_t priv_write_ptr = g_atomic_int_get(&_write_ptr);
157 if (write_space () == 0) {
160 //assert(ev.time >= last_write_time);
162 const size_t raw_index = priv_write_ptr * _max_event_size;
164 MidiEvent* const write_ev = &_ev_buf[priv_write_ptr];
167 memcpy(&_raw_buf[raw_index], ev.buffer, ev.size);
168 write_ev->buffer = &_raw_buf[raw_index];
169 g_atomic_int_set(&_write_ptr, (priv_write_ptr + 1) % _size);
171 printf("MRB - wrote %xd %d %d with time %u at index %zu (raw index %zu)\n",
172 write_ev->buffer[0], write_ev->buffer[1], write_ev->buffer[2], write_ev->time,
173 priv_write_ptr, raw_index);
175 assert(write_ev->size = ev.size);
177 //last_write_time = ev.time;
178 printf("(W) read space: %zu\n", read_space());
185 MidiRingBuffer::read(MidiBuffer& dst, jack_nframes_t start, jack_nframes_t end)
187 if (read_space() == 0)
190 size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
191 jack_nframes_t time = _ev_buf[priv_read_ptr].time;
193 size_t limit = read_space();
195 while (time <= end && limit > 0) {
196 MidiEvent* const read_ev = &_ev_buf[priv_read_ptr];
198 dst.push_back(*read_ev);
199 printf("MRB - read %xd %d %d with time %u at index %zu\n",
200 read_ev->buffer[0], read_ev->buffer[1], read_ev->buffer[2], read_ev->time,
203 cerr << "MRB: LOST EVENT!" << endl;
206 clear_event(priv_read_ptr);
211 priv_read_ptr = (priv_read_ptr + 1) % _size;
213 assert(read_ev->time <= end);
214 time = _ev_buf[priv_read_ptr].time;
217 g_atomic_int_set(&_read_ptr, priv_read_ptr);
218 printf("(R) read space: %zu\n", read_space());
224 MidiRingBuffer::write(const MidiBuffer& in, jack_nframes_t offset)
226 size_t num_events = in.size();
227 size_t to_write = std::min(write_space(), num_events);
229 // FIXME: double copy :/
230 for (size_t i=0; i < to_write; ++i) {
231 MidiEvent ev = in[i];
239 } // namespace ARDOUR
241 #endif // __ardour_midi_ring_buffer_h__