Reading of MIDI CC from MIDI regions (MidiModel). UI still needs work though..
[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
31 namespace ARDOUR {
32
33
34 // FIXME: mirroring for MIDI buffers?
35 MidiBuffer::MidiBuffer(size_t capacity)
36         : Buffer(DataType::MIDI, capacity)
37 //      , _owns_data(true)
38         , _events(NULL)
39         , _data(NULL)
40 {
41         assert(capacity > 0);
42
43         _size = 0;
44
45 #ifdef NO_POSIX_MEMALIGN
46         _events = (MidiEvent *) malloc(sizeof(MidiEvent) * capacity);
47         _data = (Byte *) malloc(sizeof(Byte) * capacity * MAX_EVENT_SIZE);
48 #else
49         posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MidiEvent) * capacity);
50         posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Byte) * capacity * MAX_EVENT_SIZE);
51 #endif  
52         assert(_data);
53         assert(_events);
54         silence(_capacity);
55 }
56
57 void
58 MidiBuffer::copy(const MidiBuffer& copy)
59 {
60         assert(_capacity >= copy._capacity);
61         _size = 0;
62
63         for (size_t i=0; i < copy.size(); ++i)
64                 push_back(copy[i]);
65 }
66
67 MidiBuffer::~MidiBuffer()
68 {
69         free(_events);
70         free(_data);
71 }
72
73
74 /** Read events from @a src starting at time @a offset into the START of this buffer, for
75  * time direction @a nframes.  Relative time, where 0 = start of buffer.
76  *
77  * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
78  */
79 void
80 MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
81 {
82         assert(src.type() == DataType::MIDI);
83         const MidiBuffer& msrc = (MidiBuffer&)src;
84
85         assert(_capacity >= src.size());
86
87         clear();
88         assert(_size == 0);
89
90         // FIXME: slow
91         for (size_t i=0; i < src.size(); ++i) {
92                 const MidiEvent& ev = msrc[i];
93                 if (ev.time() >= offset && ev.time() < offset+nframes) {
94                         //cerr << "MidiBuffer::read_from got event, " << ev.time() << endl;
95                         push_back(ev);
96                 } else {
97                         //cerr << "MidiBuffer event out of range, " << ev.time() << endl;
98                 }
99         }
100
101         _silent = src.silent();
102 }
103
104
105 /** Push an event into the buffer.
106  *
107  * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
108  * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
109  * Realtime safe.
110  * @return false if operation failed (not enough room)
111  */
112 bool
113 MidiBuffer::push_back(const MidiEvent& ev)
114 {
115         if (_size == _capacity)
116                 return false;
117
118         Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
119
120         memcpy(write_loc, ev.buffer(), ev.size());
121         _events[_size] = ev;
122         _events[_size].set_buffer(write_loc, false);
123         ++_size;
124
125         //cerr << "MidiBuffer: pushed, size = " << _size << endl;
126
127         _silent = false;
128
129         return true;
130 }
131
132
133 /** Push an event into the buffer.
134  *
135  * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
136  * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
137  * Realtime safe.
138  * @return false if operation failed (not enough room)
139  */
140 bool
141 MidiBuffer::push_back(const jack_midi_event_t& ev)
142 {
143         if (_size == _capacity)
144                 return false;
145
146         Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
147
148         memcpy(write_loc, ev.buffer, ev.size);
149         _events[_size].time() = (double)ev.time;
150         _events[_size].size() = ev.size;
151         _events[_size].set_buffer(write_loc, false);
152         ++_size;
153
154         //cerr << "MidiBuffer: pushed, size = " << _size << endl;
155
156         _silent = false;
157
158         return true;
159 }
160
161
162 /** Reserve space for a new event in the buffer.
163  *
164  * This call is for copying MIDI directly into the buffer, the data location
165  * (of sufficient size to write \a size bytes) is returned, or NULL on failure.
166  * This call MUST be immediately followed by a write to the returned data
167  * location, or the buffer will be corrupted and very nasty things will happen.
168  */
169 Byte*
170 MidiBuffer::reserve(double time, size_t size)
171 {
172         assert(size <= MAX_EVENT_SIZE);
173
174         if (_size == _capacity)
175                 return NULL;
176
177         Byte* const write_loc = _data + (_size * MAX_EVENT_SIZE);
178
179         _events[_size].time() = time;
180         _events[_size].size() = size;
181         _events[_size].set_buffer(write_loc, false);
182         ++_size;
183
184         //cerr << "MidiBuffer: reserved, size = " << _size << endl;
185
186         _silent = false;
187
188         return write_loc;
189 }
190
191
192 void
193 MidiBuffer::silence(nframes_t dur, nframes_t offset)
194 {
195         // FIXME use parameters
196         assert(offset == 0);
197         //assert(dur == _capacity);
198
199         memset(_events, 0, sizeof(MidiEvent) * _capacity);
200         memset(_data, 0, sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
201         _size = 0;
202         _silent = true;
203 }
204
205
206 /** Clear, and merge \a a and \a b into this buffer.
207  *
208  * FIXME: This is slow.
209  *
210  * \return true if complete merge was successful
211  */
212 bool
213 MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b)
214 {
215         _size = 0;
216
217         // Die if a merge isn't necessary as it's expensive
218         assert(a.size() > 0 && b.size() > 0);
219
220         size_t a_index = 0;
221         size_t b_index = 0;
222         size_t count = a.size() + b.size();
223
224         while (count > 0 && a_index < a.size() && b_index < b.size()) {
225                 
226                 if (size() == capacity()) {
227                         cerr << "WARNING: MIDI buffer overrun, events lost!" << endl;
228                         return false;
229                 }
230                 
231                 if (a_index == a.size()) {
232                         push_back(a[a_index]);
233                         ++a_index;
234                 } else if (b_index == b.size()) {
235                         push_back(b[b_index]);
236                         ++b_index;
237                 } else {
238                         const MidiEvent& a_ev = a[a_index];
239                         const MidiEvent& b_ev = b[b_index];
240
241                         if (a_ev.time() <= b_ev.time()) {
242                                 push_back(a_ev);
243                                 ++a_index;
244                         } else {
245                                 push_back(b_ev);
246                                 ++b_index;
247                         }
248                 }
249
250                 --count;
251         }
252
253         return true;
254 }
255
256
257 } // namespace ARDOUR
258