mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-11 17:16:38 +01:00
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
3 changed files with 55 additions and 22 deletions
|
|
@ -50,7 +50,7 @@ public:
|
||||||
inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size);
|
inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size);
|
||||||
inline bool read_contents(uint32_t size, uint8_t* buf);
|
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);
|
void dump(std::ostream& dst);
|
||||||
|
|
||||||
/** Set the channel filtering mode.
|
/** Set the channel filtering mode.
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ using namespace PBD;
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
size_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) {
|
if (this->read_space() == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -74,9 +74,22 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
|
||||||
|
|
||||||
size_t count = 0;
|
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) {
|
if (ev_time + loop_offset >= end) {
|
||||||
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
|
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
|
||||||
|
|
@ -88,12 +101,32 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
|
||||||
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end));
|
DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = read_prefix(&ev_time, &ev_type, &ev_size);
|
/* lets see if we are going to be able to write this event into dst.
|
||||||
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;
|
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)
|
// This event marks a loop end (i.e. the next event's timestamp will be non-monotonic)
|
||||||
if (ev_type == LoopEventType) {
|
if (ev_type == LoopEventType) {
|
||||||
assert (ev_size == sizeof (framepos_t));
|
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
|
// write MIDI buffer contents
|
||||||
success = read_contents (ev_size, write_loc);
|
success = read_contents (ev_size, write_loc);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -441,13 +441,26 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
|
||||||
void
|
void
|
||||||
MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
|
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));
|
MidiBuffer& buf (bufs.get_midi (0));
|
||||||
|
|
||||||
|
// Append immediate events
|
||||||
|
|
||||||
if (_immediate_events.read_space()) {
|
if (_immediate_events.read_space()) {
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of immediate events to deliver\n",
|
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of immediate events to deliver\n",
|
||||||
name(), _immediate_events.read_space()));
|
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
|
// MIDI thru: send incoming data "through" output
|
||||||
if (_midi_thru && _session.transport_speed() != 0.0f && _input->n_ports().n_midi()) {
|
if (_midi_thru && _session.transport_speed() != 0.0f && _input->n_ports().n_midi()) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue