detect buffer "overflow" when delivering immediate events and queue remainder for delivery next time (though without actually requeing - just leave ringbuffer ptrs/indexes where they are. required some deep but minor changes in how MidiRingBuffer::read() works, so that we can detect if we're going to be able to deliver an event before we actually read any of its data. Peek FTW!
git-svn-id: svn://localhost/ardour2/branches/3.0@9629 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
36ccf83049
commit
0a9f5423f5
|
@ -50,7 +50,7 @@ public:
|
|||
inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size);
|
||||
inline bool read_contents(uint32_t size, uint8_t* buf);
|
||||
|
||||
size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0);
|
||||
size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0, bool stop_on_overflow_in_destination=false);
|
||||
void dump(std::ostream& dst);
|
||||
|
||||
/** Set the channel filtering mode.
|
||||
|
|
|
@ -34,7 +34,7 @@ using namespace PBD;
|
|||
*/
|
||||
template<typename T>
|
||||
size_t
|
||||
MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset)
|
||||
MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset, bool stop_on_overflow_in_dst)
|
||||
{
|
||||
if (this->read_space() == 0) {
|
||||
return 0;
|
||||
|
@ -74,9 +74,22 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
|
|||
|
||||
size_t count = 0;
|
||||
|
||||
while (this->read_space() >= sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t)) {
|
||||
const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
|
||||
|
||||
this->peek ((uint8_t*) &ev_time, sizeof (T));
|
||||
while (this->read_space() >= prefix_size) {
|
||||
|
||||
uint8_t peekbuf[prefix_size];
|
||||
bool success;
|
||||
|
||||
success = this->peek (peekbuf, prefix_size);
|
||||
/* this cannot fail, because we've already verified that there
|
||||
is prefix_space to read
|
||||
*/
|
||||
assert (success);
|
||||
|
||||
ev_time = *((T*) peekbuf);
|
||||
ev_type = *((Evoral::EventType*)(peekbuf + sizeof (T)));
|
||||
ev_size = *((uint32_t*)(peekbuf + sizeof(T) + sizeof (Evoral::EventType)));
|
||||
|
||||
if (ev_time + loop_offset >= end) {
|
||||
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
|
||||
|
@ -87,13 +100,33 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
|
|||
} else {
|
||||
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end));
|
||||
}
|
||||
|
||||
/* lets see if we are going to be able to write this event into dst.
|
||||
*/
|
||||
|
||||
bool success = read_prefix(&ev_time, &ev_type, &ev_size);
|
||||
if (!success) {
|
||||
cerr << "WARNING: error reading event prefix from MIDI ring" << endl;
|
||||
assert(ev_time >= start);
|
||||
|
||||
ev_time -= start;
|
||||
ev_time += offset;
|
||||
|
||||
// write the timestamp to address (write_loc - 1)
|
||||
uint8_t* write_loc = dst.reserve(ev_time, ev_size);
|
||||
if (write_loc == NULL) {
|
||||
if (stop_on_overflow_in_dst) {
|
||||
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MidiRingBuffer: overflow in destination MIDI buffer, stopped after %1 events\n", count));
|
||||
break;
|
||||
}
|
||||
cerr << "MRB: Unable to reserve space in buffer, event skipped";
|
||||
this->increment_read_ptr (prefix_size + ev_size); // Advance read pointer to next event
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we're good to go ahead and read the data now but since we
|
||||
* have the prefix data already, just skip over that
|
||||
*/
|
||||
|
||||
this->increment_read_ptr (prefix_size);
|
||||
|
||||
// This event marks a loop end (i.e. the next event's timestamp will be non-monotonic)
|
||||
if (ev_type == LoopEventType) {
|
||||
assert (ev_size == sizeof (framepos_t));
|
||||
|
@ -120,19 +153,6 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
|
|||
}
|
||||
}
|
||||
|
||||
assert(ev_time >= start);
|
||||
|
||||
ev_time -= start;
|
||||
ev_time += offset;
|
||||
|
||||
// write the timestamp to address (write_loc - 1)
|
||||
uint8_t* write_loc = dst.reserve(ev_time, ev_size);
|
||||
if (write_loc == NULL) {
|
||||
cerr << "MRB: Unable to reserve space in buffer, event skipped";
|
||||
this->increment_read_ptr (ev_size); // Advance read pointer to next event
|
||||
continue;
|
||||
}
|
||||
|
||||
// write MIDI buffer contents
|
||||
success = read_contents (ev_size, write_loc);
|
||||
|
||||
|
|
|
@ -441,13 +441,26 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
|
|||
void
|
||||
MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
|
||||
{
|
||||
// Append immediate events
|
||||
MidiBuffer& buf (bufs.get_midi (0));
|
||||
|
||||
// Append immediate events
|
||||
|
||||
if (_immediate_events.read_space()) {
|
||||
|
||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of immediate events to deliver\n",
|
||||
name(), _immediate_events.read_space()));
|
||||
|
||||
/* write as many of the immediate events as we can, but give "true" as
|
||||
* the last argument ("stop on overflow in destination") so that we'll
|
||||
* ship the rest out next time.
|
||||
*
|
||||
* the (nframes-1) argument puts all these events at the last
|
||||
* possible position of the output buffer, so that we do not
|
||||
* violate monotonicity when writing.
|
||||
*/
|
||||
|
||||
_immediate_events.read (buf, 0, 1, nframes-1, true);
|
||||
}
|
||||
_immediate_events.read (buf, 0, 1, nframes-1); // all stamps = 0
|
||||
|
||||
// MIDI thru: send incoming data "through" output
|
||||
if (_midi_thru && _session.transport_speed() != 0.0f && _input->n_ports().n_midi()) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user