Correctly flush MIDI buffers on cycle-split

This commit is contained in:
Robin Gareus 2019-11-03 15:18:04 +01:00
parent 98224a264e
commit 2fde6a5777
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
3 changed files with 33 additions and 2 deletions

View File

@ -146,11 +146,37 @@ AudioEngine::split_cycle (pframes_t offset)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
boost::shared_ptr<Ports> p = ports.reader();
/* This is mainly for the benefit of rt-control ports (MTC, MClk)
*
* Normally ports are flushed by the route:
* ARDOUR::MidiPort::flush_buffers(unsigned int)
* ARDOUR::Delivery::flush_buffers(long)
* ARDOUR::Route::flush_processor_buffers_locked(long)
* ARDOUR::Route::run_route(long, long, unsigned int, bool, bool)
* ...
*
* This is required so that route -> route connections work during
* normal processing.
*
* However some non-route ports may contain MIDI events
* from current Port::port_offset() .. Port::port_offset() + offset.
* If those events are not pushed to ports before the cycle split,
* MidiPort::flush_buffers will drop them (event time is out of bounds).
*
* TODO: for optimized builds MidiPort::flush_buffers() could
* be relaxed, ignore ev->time() checks, and simply send
* all events as-is.
*/
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
i->second->flush_buffers (offset);
}
Port::increment_global_port_buffer_offset (offset); Port::increment_global_port_buffer_offset (offset);
/* tell all Ports that we're going to start a new (split) cycle */ /* tell all Ports that we're going to start a new (split) cycle */
boost::shared_ptr<Ports> p = ports.reader();
for (Ports::iterator i = p->begin(); i != p->end(); ++i) { for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
i->second->cycle_split (); i->second->cycle_split ();

View File

@ -308,6 +308,9 @@ MidiPort::flush_buffers (pframes_t nframes)
} }
#endif #endif
// XXX consider removing this check for optimized builds
// and just send 'em all, at cycle_end
// see AudioEngine::split_cycle (), PortManager::cycle_end()
if ( ev.time() >= _global_port_buffer_offset if ( ev.time() >= _global_port_buffer_offset
&& ev.time() < _global_port_buffer_offset + nframes) { && ev.time() < _global_port_buffer_offset + nframes) {
pframes_t tme = floor (ev.time() / _speed_ratio); pframes_t tme = floor (ev.time() / _speed_ratio);

View File

@ -845,7 +845,9 @@ PortManager::cycle_end (pframes_t nframes, Session* s)
} }
for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) { for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
p->second->flush_buffers (nframes); /* AudioEngine::split_cycle flushes buffers until Port::port_offset.
* Now only flush remaining events (after Port::port_offset) */
p->second->flush_buffers (nframes - Port::port_offset ());
} }
_cycle_ports.reset (); _cycle_ports.reset ();