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