From 2fde6a5777694c454d102c7fa1bd9ea594d4db2b Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 3 Nov 2019 15:18:04 +0100 Subject: Correctly flush MIDI buffers on cycle-split --- libs/ardour/audioengine.cc | 28 +++++++++++++++++++++++++++- libs/ardour/midi_port.cc | 3 +++ libs/ardour/port_manager.cc | 4 +++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 69418c1911..c7e4efa1d1 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -146,11 +146,37 @@ AudioEngine::split_cycle (pframes_t offset) { /* caller must hold process lock */ + boost::shared_ptr 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); /* tell all Ports that we're going to start a new (split) cycle */ - boost::shared_ptr p = ports.reader(); for (Ports::iterator i = p->begin(); i != p->end(); ++i) { i->second->cycle_split (); diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index d22673fe72..7eed2ef468 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -308,6 +308,9 @@ MidiPort::flush_buffers (pframes_t nframes) } #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 && ev.time() < _global_port_buffer_offset + nframes) { pframes_t tme = floor (ev.time() / _speed_ratio); diff --git a/libs/ardour/port_manager.cc b/libs/ardour/port_manager.cc index 24c693c431..8be1f7f7e9 100644 --- a/libs/ardour/port_manager.cc +++ b/libs/ardour/port_manager.cc @@ -845,7 +845,9 @@ PortManager::cycle_end (pframes_t nframes, Session* s) } 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 (); -- cgit v1.2.3