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::write (const MidiEvent& ev)
131 //static jack_nframes_t last_write_time = 0;
135 size_t priv_write_ptr = g_atomic_int_get(&_write_ptr);
137 if (write_space () == 0) {
140 //assert(ev.time >= last_write_time);
142 const size_t raw_index = priv_write_ptr * _max_event_size;
144 MidiEvent* const write_ev = &_ev_buf[priv_write_ptr];
147 memcpy(&_raw_buf[raw_index], ev.buffer, ev.size);
148 write_ev->buffer = &_raw_buf[raw_index];
149 g_atomic_int_set(&_write_ptr, (priv_write_ptr + 1) % _size);
151 printf("MRB - wrote %xd %d %d with time %u at index %zu (raw index %zu)\n",
152 write_ev->buffer[0], write_ev->buffer[1], write_ev->buffer[2], write_ev->time,
153 priv_write_ptr, raw_index);
155 assert(write_ev->size = ev.size);
157 //last_write_time = ev.time;
158 //printf("(W) read space: %zu\n", read_space());
165 MidiRingBuffer::read(MidiBuffer& dst, jack_nframes_t start, jack_nframes_t end)
167 if (read_space() == 0)
170 size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
171 jack_nframes_t time = _ev_buf[priv_read_ptr].time;
173 size_t limit = read_space();
175 while (time <= end && limit > 0) {
176 MidiEvent* const read_ev = &_ev_buf[priv_read_ptr];
178 dst.push_back(*read_ev);
179 printf("MRB - read %#X %d %d with time %u at index %zu\n",
180 read_ev->buffer[0], read_ev->buffer[1], read_ev->buffer[2], read_ev->time,
183 printf("MRB - SKIPPING - %#X %d %d with time %u at index %zu\n",
184 read_ev->buffer[0], read_ev->buffer[1], read_ev->buffer[2], read_ev->time,
189 clear_event(priv_read_ptr);
194 priv_read_ptr = (priv_read_ptr + 1) % _size;
196 assert(read_ev->time <= end);
197 time = _ev_buf[priv_read_ptr].time;
200 g_atomic_int_set(&_read_ptr, priv_read_ptr);
202 //printf("(R) read space: %zu\n", read_space());
208 MidiRingBuffer::write(const MidiBuffer& in, jack_nframes_t offset)
210 size_t num_events = in.size();
211 size_t to_write = std::min(write_space(), num_events);
213 // FIXME: double copy :/
214 for (size_t i=0; i < to_write; ++i) {
215 MidiEvent ev = in[i];
223 } // namespace ARDOUR
225 #endif // __ardour_midi_ring_buffer_h__