Fix immediate event delivery (panic button, controller sliders, etc).
[ardour.git] / libs / ardour / midi_buffer.cc
1 /*
2     Copyright (C) 2006-2007 Paul Davis 
3         Author: Dave Robillard
4     
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)
8     any later version.
9     
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
13     for more details.
14     
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.
18 */
19
20 #include <iostream>
21 #include <ardour/midi_buffer.h>
22
23 #ifdef __x86_64__
24 static const int CPU_CACHE_ALIGN = 64;
25 #else
26 static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
27 #endif
28
29 using namespace std;
30 using namespace ARDOUR;
31
32
33 // FIXME: mirroring for MIDI buffers?
34 MidiBuffer::MidiBuffer(size_t capacity)
35         : Buffer(DataType::MIDI, capacity)
36         , _events(0)
37         , _data(0)
38 //      , _owns_data(false)
39 {
40         if (capacity) {
41                 resize (_capacity);
42                 silence(_capacity);
43         }
44 }
45         
46 MidiBuffer::~MidiBuffer()
47 {
48         if (_events) {
49                 free(_events);
50         }
51         if (_data) {
52                 free(_data);
53         }
54 }
55
56 void
57 MidiBuffer::resize (size_t size)
58 {
59         assert(size > 0);
60
61         if (size < _capacity) {
62                 return;
63         }
64
65         if (_data) {
66                 free (_data);
67         }
68
69         if (_events) {
70                 free (_events);
71         }
72
73         _size = 0;
74         _capacity = size;
75
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);
79 #else
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);
82 #endif  
83         assert(_data);
84         assert(_events);
85 }
86
87 void
88 MidiBuffer::copy(const MidiBuffer& copy)
89 {
90         assert(_capacity >= copy._capacity);
91         _size = 0;
92
93         for (size_t i = 0; i < copy.size(); ++i)
94                 push_back(copy[i]);
95 }
96
97
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.
100  *
101  * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
102  */
103 void
104 MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
105 {
106         assert(src.type() == DataType::MIDI);
107         assert(&src != this);
108
109         const MidiBuffer& msrc = (MidiBuffer&)src;
110         
111         assert(_capacity >= msrc.size());
112
113         if (offset == 0) {
114                 clear();
115                 assert(_size == 0);
116         }
117         
118         // FIXME: slow
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;
127                         push_back(ev);
128                 } else {
129                         //cerr << "MidiBuffer::read_from skipped event after "
130                         //      << nframes << " + " << offset << endl;
131                 }
132         }
133
134         _silent = src.silent();
135 }
136
137
138 /** Push an event into the buffer.
139  *
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).
142  * Realtime safe.
143  * @return false if operation failed (not enough room)
144  */
145 bool
146 MidiBuffer::push_back(const Evoral::MIDIEvent& ev)
147 {
148         if (_size == _capacity) {
149                 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
150                 return false;
151         }
152
153         uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
154
155         memcpy(write_loc, ev.buffer(), ev.size());
156         _events[_size] = ev;
157         _events[_size].set_buffer(ev.size(), write_loc, false);
158
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]);
163         }
164         printf("\n");*/
165
166         ++_size;
167         _silent = false;
168
169         return true;
170 }
171
172
173 /** Push an event into the buffer.
174  *
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).
177  * Realtime safe.
178  * @return false if operation failed (not enough room)
179  */
180 bool
181 MidiBuffer::push_back(const jack_midi_event_t& ev)
182 {
183         if (_size == _capacity) {
184                 cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
185                 return false;
186         }
187
188         uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
189
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);
193
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]);
198         }
199         printf("\n");*/
200         
201         ++_size;
202         _silent = false;
203
204         return true;
205 }
206
207
208 /** Reserve space for a new event in the buffer.
209  *
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.
214  */
215 uint8_t*
216 MidiBuffer::reserve(double time, size_t size)
217 {
218         if (size > MAX_EVENT_SIZE) {
219                 cerr << "WARNING: Failed to reserve " << size << " bytes for event";
220                 return 0;
221         }
222
223         if (_size == _capacity)
224                 return 0;
225
226         uint8_t* const write_loc = _data + (_size * MAX_EVENT_SIZE);
227
228         _events[_size].time() = time;
229         _events[_size].set_buffer(size, write_loc, false);
230         ++_size;
231
232         //cerr << "MidiBuffer: reserved, size = " << _size << endl;
233
234         _silent = false;
235
236         return write_loc;
237 }
238
239
240 void
241 MidiBuffer::silence(nframes_t dur, nframes_t offset)
242 {
243         // FIXME use parameters
244         if (offset != 0)
245                 cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl;
246
247         memset(_events, 0, sizeof(Evoral::Event) * _capacity);
248         memset(_data, 0, sizeof(uint8_t) * _capacity * MAX_EVENT_SIZE);
249         _size = 0;
250         _silent = true;
251 }
252
253 bool
254 MidiBuffer::merge_in_place( const MidiBuffer &other )
255 {
256         if( other.size() == 0 )
257                 return true;
258
259         if( this->size() == 0 ) {
260                 copy( other );
261                 return true;
262         }
263
264         {
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;
271
272                 bool retval = merge_buffer.merge( *this, other );
273
274                 copy( merge_buffer );
275
276                 // set pointers to zero again, so destructor
277                 // does not end in calling free() for memory
278                 // on the stack;
279                 merge_buffer._events = 0;
280                 merge_buffer._data = 0;
281
282                 return retval;
283         }
284 }
285
286 /** Clear, and merge \a a and \a b into this buffer.
287  *
288  * FIXME: This is slow.
289  *
290  * \return true if complete merge was successful
291  */
292 bool
293 MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
294 {
295         _size = 0;
296
297         // This is mostly the case :(
298         if( this == &a )
299             merge_in_place( b );
300
301         if( this == &b )
302             merge_in_place( a );
303
304         size_t a_index = 0;
305         size_t b_index = 0;
306         size_t count = a.size() + b.size();
307
308         while (count > 0) {
309                 
310                 if (size() == capacity()) {
311                         cerr << "WARNING: MIDI buffer overrun, events lost!" << endl;
312                         return false;
313                 }
314                 
315                 if (a_index == a.size()) {
316                         push_back(b[b_index]);
317                         ++b_index;
318                 } else if (b_index == b.size()) {
319                         push_back(a[a_index]);
320                         ++a_index;
321                 } else {
322                         const Evoral::MIDIEvent& a_ev = a[a_index];
323                         const Evoral::MIDIEvent& b_ev = b[b_index];
324
325                         if (a_ev.time() <= b_ev.time()) {
326                                 push_back(a_ev);
327                                 ++a_index;
328                         } else {
329                                 push_back(b_ev);
330                                 ++b_index;
331                         }
332                 }
333
334                 --count;
335         }
336
337         return true;
338 }
339