The connection was stored by the Port where it was initiated from:
1. Connect A to B
2. Disconnect B from A
(1) Port A remembers the connection to B
(2) Port B does not know about the connection from A
Since disconnect is initiated on port B, port A still retained
the connection information.
When restarting the engine, Port::reconnect() reestablished the
connection.
This is only relevant when libardour's own connection information is
used. e.g. the session is closed without engine, or when re-starting
the engine while the session is open.
Changes include workarounds for weird Rubberband API (pad, drop, truncate requirements),
and a shift to push logic after a slot is finished back up into the TriggerBox.
Not finished yet, some easily encountered bugs remain
::snap_to() was intended to round a Beats value to the nearest multiple
of another Beats value. It did not do that, but instead rounded down.
Worse, it used Beats::operator/ which in turn uses int_div_round(),
which is incorrect for a situation where we need integer truncation.
The changes fix the actual arithmetic and add 2 variant functions so that the
API includes round down, round up and round to nearest.
Program Changes are stored as an offset from the 'source' start, and must be translated to/from region time.
Better locating of patches wrt the grid:
You can't assume time_to_pixel is steady across the timeline
* calculate position of the patch-change flag
* calculate region start position, and set flag's x offset from there
also: consolidate patch-location code into display_patch_changes()
max_samplepos and max_samplecnt and both INT64_MAX which is (a) too large to fit into a signed 62 bit
integer and (b) definitely too large to be represented in a signed 62 bit superclock value.
Move the constructors that use samplepos_t into the .cc file, and treat these two values as special
cases that mean "as large/late/huge/long as possible".
This works around a race-condition, calling d'tors from
two threads concurrently.
The GUI thread destroys ctrl surfaces. ~~MIDIControllable()
calls ::drop_external_control() -> ::midi_forget()
This unsubscribes from signals (notably MIDI::Parser events)
by calling ScopedConnection::disconnect(), Connection::disconnect().
At the same time auto_connect_thread can call
PortManager::clear_pending_port_deletions() which removes
the MIDI port and destorys the MIDI::Parser.
~Parser() calls Connection::signal_going_away() to invalidate
connected signals.
This can deadlock if it is called concurrently with
Connection::disconnect() on the same signal.
see also
https://discourse.ardour.org/t/ardour-session-close-hangs/106523/10