ardour
midi_ring_buffer.cc
Go to the documentation of this file.
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/enumwriter.h"
21 #include "pbd/error.h"
22 
23 #include "ardour/debug.h"
25 #include "ardour/midi_buffer.h"
26 #include "ardour/event_type_map.h"
27 
28 using namespace std;
29 using namespace PBD;
30 
31 namespace ARDOUR {
32 
38 template<typename T>
39 size_t
40 MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset, bool stop_on_overflow_in_dst)
41 {
42  if (this->read_space() == 0) {
43  return 0;
44  }
45 
46  T ev_time;
47  uint32_t ev_size;
48  size_t count = 0;
49  const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
50 
51  while (this->read_space() >= prefix_size) {
52 
53  uint8_t peekbuf[prefix_size];
54 
55  /* this cannot fail, because we've already verified that there
56  is prefix_space to read
57  */
58  this->peek (peekbuf, prefix_size);
59 
60  ev_time = *(reinterpret_cast<T*>((uintptr_t)peekbuf));
61  ev_size = *(reinterpret_cast<uint32_t*>((uintptr_t)(peekbuf + sizeof(T) + sizeof (Evoral::EventType))));
62 
63  if (this->read_space() < ev_size) {
64  break;;
65  }
66 
67  if (ev_time >= end) {
68  DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
69  break;
70  } else if (ev_time < start) {
71  DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 before start @ %2\n", ev_time, start));
72  break;
73  } else {
74  DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end));
75  }
76 
77  ev_time -= start;
78  ev_time += offset;
79 
80  /* we're good to go ahead and read the data now but since we
81  * have the prefix data already, just skip over that
82  */
83  this->increment_read_ptr (prefix_size);
84 
85  uint8_t status;
86  bool r = this->peek (&status, sizeof(uint8_t));
87  assert (r); // If this failed, buffer is corrupt, all hope is lost
88 
89  /* lets see if we are going to be able to write this event into dst.
90  */
91  uint8_t* write_loc = dst.reserve (ev_time, ev_size);
92  if (write_loc == 0) {
93  if (stop_on_overflow_in_dst) {
94  DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events\n", count));
95  break;
96  }
97  error << "MRB: Unable to reserve space in buffer, event skipped" << endmsg;
98  this->increment_read_ptr (ev_size); // Advance read pointer to next event
99  continue;
100  }
101 
102  // write MIDI buffer contents
103  bool success = read_contents (ev_size, write_loc);
104 
105 #ifndef NDEBUG
107  DEBUG_STR_DECL(a);
108  DEBUG_STR_APPEND(a, string_compose ("wrote MidiEvent to Buffer (time=%1, start=%2 offset=%3)", ev_time, start, offset));
109  for (size_t i=0; i < ev_size; ++i) {
110  DEBUG_STR_APPEND(a,hex);
111  DEBUG_STR_APPEND(a,"0x");
112  DEBUG_STR_APPEND(a,(int)write_loc[i]);
113  DEBUG_STR_APPEND(a,' ');
114  }
115  DEBUG_STR_APPEND(a,'\n');
117  }
118 #endif
119 
120  if (success) {
121  _tracker.track(write_loc);
122  ++count;
123  } else {
124  cerr << "WARNING: error reading event contents from MIDI ring" << endl;
125  }
126  }
127 
128  return count;
129 }
130 
131 template<typename T>
132 size_t
134 {
135  if (this->read_space() == 0) {
136  return 0;
137  }
138 
139  T ev_time;
140  uint32_t ev_size;
141  size_t count = 0;
142  const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
143 
144  while (this->read_space() >= prefix_size) {
145 
146  uint8_t peekbuf[prefix_size];
147  this->peek (peekbuf, prefix_size);
148 
149  ev_time = *(reinterpret_cast<T*>((uintptr_t)peekbuf));
150  ev_size = *(reinterpret_cast<uint32_t*>((uintptr_t)(peekbuf + sizeof(T) + sizeof (Evoral::EventType))));
151 
152  if (ev_time >= start) {
153  return count;
154  }
155 
156  if (this->read_space() < ev_size) {
157  continue;
158  }
159 
160  this->increment_read_ptr (prefix_size);
161 
162  uint8_t status;
163  bool r = this->peek (&status, sizeof(uint8_t));
164  assert (r); // If this failed, buffer is corrupt, all hope is lost
165 
166  ++count;
167 
168  /* TODO investigate and think:
169  *
170  * Does it makes sense to keep track of notes
171  * that are skipped (because they're either too late
172  * (underrun) or never used (read-ahead, loop) ?
173  *
174  * skip_to() is called on the rinbuffer between
175  * disk and process. it seems wrong to track them
176  * (a potential synth never sees skipped notes, either)
177  * but there may be more to this.
178  */
179 
180  if (ev_size >= 8) {
181  this->increment_read_ptr (ev_size);
182  } else {
183  // we only track note on/off, 8 bytes are plenty.
184  uint8_t write_loc[8];
185  bool success = read_contents (ev_size, write_loc);
186  if (success) {
187  _tracker.track(write_loc);
188  }
189  }
190  }
191  return count;
192 }
193 
194 
195 
196 template<typename T>
197 void
199 {
200  const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
201 
202  while (this->read_space() >= prefix_size) {
203  uint8_t peekbuf[prefix_size];
204  bool success;
205  uint32_t ev_size;
206  T ev_time;
207 
208  success = this->peek (peekbuf, prefix_size);
209  /* this cannot fail, because we've already verified that there
210  is prefix_space to read
211  */
212  assert (success);
213 
214  ev_time = *(reinterpret_cast<T*>((uintptr_t)peekbuf));
215 
216  if (ev_time >= end) {
217  break;
218  }
219 
220  ev_size = *(reinterpret_cast<uint32_t*>((uintptr_t)(peekbuf + sizeof(T) + sizeof (Evoral::EventType))));
221  this->increment_read_ptr (prefix_size);
222  this->increment_read_ptr (ev_size);
223  }
224 }
225 
226 template<typename T>
227 void
229 {
230  size_t rspace;
231 
232  if ((rspace = this->read_space()) == 0) {
233  str << "MRB::dump: empty\n";
234  return;
235  }
236 
237  T ev_time;
238  Evoral::EventType ev_type;
239  uint32_t ev_size;
240 
243 
244  if (vec.len[0] == 0) {
245  return;
246  }
247 
248  str << this << ": Dump size = " << vec.len[0] + vec.len[1]
250  << " w@" << RingBufferNPT<uint8_t>::get_write_ptr() << endl;
251 
252 
253  uint8_t *buf = new uint8_t[vec.len[0] + vec.len[1]];
254  memcpy (buf, vec.buf[0], vec.len[0]);
255 
256  if (vec.len[1]) {
257  memcpy (buf+vec.len[1], vec.buf[1], vec.len[1]);
258  }
259 
260  uint8_t* data = buf;
261  const uint8_t* end = buf + vec.len[0] + vec.len[1];
262 
263  while (data < end) {
264 
265  memcpy (&ev_time, data, sizeof (T));
266  data += sizeof (T);
267  str << "\ttime " << ev_time;
268 
269  if (data >= end) {
270  str << "(incomplete)\n ";
271  break;
272  }
273 
274  memcpy (&ev_type, data, sizeof (ev_type));
275  data += sizeof (ev_type);
276  str << " type " << ev_type;
277 
278  if (data >= end) {
279  str << "(incomplete)\n";
280  break;
281  }
282 
283  memcpy (&ev_size, data, sizeof (ev_size));
284  data += sizeof (ev_size);
285  str << " size " << ev_size;
286 
287  if (data >= end) {
288  str << "(incomplete)\n";
289  break;
290  }
291 
292  for (uint32_t i = 0; i != ev_size && data < end; ++i) {
293  str << ' ' << hex << (int) data[i] << dec;
294  }
295 
296  data += ev_size;
297 
298  str << endl;
299  }
300 
301  delete [] buf;
302 }
303 
304 template<typename T>
305 void
307 {
308  _tracker.reset ();
309 }
310 
311 template<typename T>
312 void
314 {
315  _tracker.resolve_notes (dst, t);
316 }
317 
318 template<typename T>
319 void
321 {
322  _tracker.resolve_notes(dst, t);
323 }
324 
325 template class MidiRingBuffer<framepos_t>;
326 
327 } // namespace ARDOUR
Definition: Beats.hpp:239
LIBARDOUR_API uint64_t MidiDiskstreamIO
Definition: debug.cc:30
LIBPBD_API Transmitter error
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
uint8_t * reserve(TimeType time, size_t size)
Definition: midi_buffer.cc:268
int64_t framecnt_t
Definition: types.h:76
Definition: amp.h:29
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
int64_t framepos_t
Definition: types.h:66
uint32_t EventType
Definition: types.hpp:43
LIBPBD_API uint64_t debug_bits
Definition: debug.cc:55
#define DEBUG_STR_APPEND(id, s)
Definition: debug.h:58
Definition: debug.h:30
#define DEBUG_STR(id)
Definition: debug.h:57
#define DEBUG_STR_DECL(id)
Definition: debug.h:56
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208