make switching between input+disk monitoring work "right" for MIDI tracks; also fix...
[ardour.git] / libs / ardour / midi_ring_buffer.cc
1 /*
2     Copyright (C) 2006-2008 Paul Davis
3
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.
8
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.
13
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.
17 */
18
19 #include "pbd/compose.h"
20 #include "pbd/error.h"
21
22 #include "ardour/debug.h"
23 #include "ardour/midi_ring_buffer.h"
24 #include "ardour/midi_buffer.h"
25 #include "ardour/event_type_map.h"
26
27 using namespace std;
28 using namespace PBD;
29
30 namespace ARDOUR {
31
32 /** Read a block of MIDI events from this buffer into a MidiBuffer.
33  *
34  * Timestamps of events returned are relative to start (i.e. event with stamp 0
35  * occurred at start), with offset added.
36  */
37 template<typename T>
38 size_t
39 MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset, bool stop_on_overflow_in_dst)
40 {
41         if (this->read_space() == 0) {
42                 return 0;
43         }
44
45         T                 ev_time;
46         Evoral::EventType ev_type;
47         uint32_t          ev_size;
48
49         /* If we see the end of a loop during this read, we must write the events after it
50            to the MidiBuffer with adjusted times.  The situation is as follows:
51
52            session frames----------------------------->
53
54                      |                            |                    |
55                 start_of_loop                   start              end_of_loop
56
57            The MidiDiskstream::read method which will have happened before this checks for
58            loops ending, and helpfully inserts a magic LoopEvent into the ringbuffer.  After this,
59            the MidiDiskstream continues to write events with their proper session frame times,
60            so after the LoopEvent event times will go backwards (ie non-monotonically).
61
62            Once we hit end_of_loop, we need to fake it to make it look as though the loop has been
63            immediately repeated.  Say that an event E after the end_of_loop in the ringbuffer
64            has time E_t, which is a time in session frames.  Its offset from the start
65            of the loop will be E_t - start_of_loop.  Its `faked' time will therefore be
66            end_of_loop + E_t - start_of_loop.  And so its port-buffer-relative time (for
67            writing to the MidiBuffer) will be end_of_loop + E_t - start_of_loop - start.
68
69            The subtraction of start is already taken care of, so if we see a LoopEvent, we'll
70            set up loop_offset to equal end_of_loop - start_of_loop, so that given an event
71            time E_t in the ringbuffer we can get the port-buffer-relative time as
72            E_t + offset - start.
73         */
74
75         frameoffset_t loop_offset = 0;
76
77         size_t count = 0;
78
79         const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
80
81         while (this->read_space() >= prefix_size) {
82
83                 uint8_t peekbuf[prefix_size];
84                 bool success;
85
86                 success = this->peek (peekbuf, prefix_size);
87                 /* this cannot fail, because we've already verified that there
88                    is prefix_space to read
89                 */
90                 assert (success);
91
92                 ev_time = *((T*) peekbuf);
93                 ev_type = *((Evoral::EventType*)(peekbuf + sizeof (T)));
94                 ev_size = *((uint32_t*)(peekbuf + sizeof(T) + sizeof (Evoral::EventType)));
95
96                 if (ev_time + loop_offset >= end) {
97                         DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
98                         break;
99                 } else if (ev_time + loop_offset < start) {
100                         DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 before start @ %2\n", ev_time, start));
101                         this->increment_read_ptr (prefix_size);
102                         this->increment_read_ptr (ev_size);
103                         continue;
104                 } else {
105                         DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end));
106                 }
107
108                 assert(ev_time >= start);
109
110                 ev_time -= start;
111                 ev_time += offset;
112
113                 // This event marks a loop end (i.e. the next event's timestamp
114                 // will be non-monotonic). Don't write it into the buffer - the
115                 // significance of this event ends here.
116                 
117                 if (ev_type == LoopEventType) {
118                         assert (ev_size == sizeof (framepos_t));
119                         framepos_t loop_start;
120                         read_contents (ev_size, (uint8_t *) &loop_start);
121                         loop_offset = ev_time - loop_start;
122                         _tracker.resolve_notes (dst, ev_time);
123                         continue;
124                 }
125
126                 /* we're good to go ahead and read the data now but since we
127                  * have the prefix data already, just skip over that
128                  */
129                 this->increment_read_ptr (prefix_size);
130                 ev_time += loop_offset;
131
132                 uint8_t status;
133                 success = this->peek (&status, sizeof(uint8_t));
134                 assert(success); // If this failed, buffer is corrupt, all hope is lost
135
136                 // Ignore event if it doesn't match channel filter
137                 if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
138                         const uint8_t channel = status & 0x0F;
139                         if (!(get_channel_mask() & (1L << channel))) {
140                                 DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB skipping event (%3 bytes) due to channel mask (mask = %1 chn = %2)\n",
141                                                                                       get_channel_mask(), (int) channel, ev_size));
142                                 this->increment_read_ptr (ev_size); // Advance read pointer to next event
143                                 continue;
144                         }
145                 }
146
147                 /* lets see if we are going to be able to write this event into dst.
148                  */
149                 uint8_t* write_loc = dst.reserve (ev_time, ev_size);
150                 if (write_loc == 0) {
151                         if (stop_on_overflow_in_dst) {
152                                 DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events\n", count));
153                                 break;
154                         }
155                         error << "MRB: Unable to reserve space in buffer, event skipped" << endmsg;
156                         this->increment_read_ptr (ev_size); // Advance read pointer to next event
157                         continue;
158                 }
159
160                 // write MIDI buffer contents
161                 success = read_contents (ev_size, write_loc);
162
163 #ifndef NDEBUG
164                 if (DEBUG::MidiDiskstreamIO && PBD::debug_bits) {
165                         DEBUG_STR_DECL(a);
166                         DEBUG_STR_APPEND(a, string_compose ("wrote MidiEvent to Buffer (time=%1, start=%2 offset=%3)", ev_time, start, offset));
167                         for (size_t i=0; i < ev_size; ++i) {
168                                 DEBUG_STR_APPEND(a,hex);
169                                 DEBUG_STR_APPEND(a,"0x");
170                                 DEBUG_STR_APPEND(a,(int)write_loc[i]);
171                                 DEBUG_STR_APPEND(a,' ');
172                         }
173                         DEBUG_STR_APPEND(a,'\n');
174                         DEBUG_TRACE (DEBUG::MidiDiskstreamIO, DEBUG_STR(a).str());
175                 }
176 #endif
177
178                 if (success) {
179
180                         if (is_note_on(write_loc[0]) ) {
181                                 _tracker.add (write_loc[1], write_loc[0] & 0xf);
182                         } else if (is_note_off(write_loc[0])) {
183                                 _tracker.remove (write_loc[1], write_loc[0] & 0xf);
184                         }
185                         
186                         if (is_channel_event(status) && get_channel_mode() == ForceChannel) {
187                                 write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
188                         }
189                         ++count;
190                 } else {
191                         cerr << "WARNING: error reading event contents from MIDI ring" << endl;
192                 }
193         }
194
195         return count;
196 }
197
198 template<typename T>
199 void
200 MidiRingBuffer<T>::flush (framepos_t start, framepos_t end)
201 {
202         const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
203
204         while (this->read_space() >= prefix_size) {
205                 uint8_t  peekbuf[prefix_size];
206                 bool     success;
207                 uint32_t ev_size;
208                 T        ev_time;
209
210                 success = this->peek (peekbuf, prefix_size);
211                 /* this cannot fail, because we've already verified that there
212                    is prefix_space to read
213                 */
214                 assert (success);
215
216                 ev_time = *((T*) peekbuf);
217                 
218                 if (ev_time >= end) {
219                         break;
220                 }
221
222                 ev_size = *((uint32_t*)(peekbuf + sizeof(T) + sizeof (Evoral::EventType)));
223                 this->increment_read_ptr (prefix_size);
224                 this->increment_read_ptr (ev_size);
225         }
226 }
227
228 template<typename T>
229 void
230 MidiRingBuffer<T>::dump(ostream& str)
231 {
232         size_t rspace;
233
234         if ((rspace = this->read_space()) == 0) {
235                 str << "MRB::dump: empty\n";
236                 return;
237         }
238
239         T                 ev_time;
240         Evoral::EventType ev_type;
241         uint32_t          ev_size;
242
243         RingBufferNPT<uint8_t>::rw_vector vec;
244         RingBufferNPT<uint8_t>::get_read_vector (&vec);
245
246         if (vec.len[0] == 0) {
247                 return;
248         }
249
250         str << this << ": Dump size = " << vec.len[0] + vec.len[1]
251             << " r@ " << RingBufferNPT<uint8_t>::get_read_ptr()
252             << " w@" << RingBufferNPT<uint8_t>::get_write_ptr() << endl;
253
254
255         uint8_t *buf = new uint8_t[vec.len[0] + vec.len[1]];
256         memcpy (buf, vec.buf[0], vec.len[0]);
257
258         if (vec.len[1]) {
259                 memcpy (buf+vec.len[1], vec.buf[1], vec.len[1]);
260         }
261
262         uint8_t* data = buf;
263         const uint8_t* end = buf + vec.len[0] + vec.len[1];
264
265         while (data < end) {
266
267                 memcpy (&ev_time, data, sizeof (T));
268                 data += sizeof (T);
269                 str << "\ttime " << ev_time;
270
271                 if (data >= end) {
272                         str << "(incomplete)\n ";
273                         break;
274                 }
275
276                 memcpy (&ev_type, data, sizeof (ev_type));
277                 data += sizeof (ev_type);
278                 str << " type " << ev_type;
279
280                 if (data >= end) {
281                         str << "(incomplete)\n";
282                         break;
283                 }
284
285                 memcpy (&ev_size, data, sizeof (ev_size));
286                 data += sizeof (ev_size);
287                 str << " size " << ev_size;
288
289                 if (data >= end) {
290                         str << "(incomplete)\n";
291                         break;
292                 }
293
294                 for (uint32_t i = 0; i != ev_size && data < end; ++i) {
295                         str << ' ' << hex << (int) data[i] << dec;
296                 }
297
298                 data += ev_size;
299
300                 str << endl;
301         }
302
303         delete [] buf;
304 }
305
306 template<typename T>
307 void
308 MidiRingBuffer<T>::reset_tracker ()
309 {
310         _tracker.reset ();
311 }
312
313 template class MidiRingBuffer<framepos_t>;
314
315 }  // namespace ARDOUR