This is a follow up to 248e37ac0c.
A line at 0 with 1px width should draw from 0.5 to 1.5
(cairo pixel offset). The same line with a width of 3px
is -0.5 to 2.5.
The self.intersection code calculates this correctly, subtracting
shift, the drawing code however incorrectly added it.
This fixes MIDI track grid/note offset as well as a bleed
below the track.
the API now provides the option to call ::get_grid() with an iterator which may
be re-used on subsequent calls. This avoids unbounded O(N) "walks" from the
marker preceding the start point of the grid to the start point.
This commit also includes "fast-path" code for the common case of a single
tempo and single meter
These were not thread safe, and could not be: to be useful, a thread looking up a time
conversion could cache the result, but it would be using the global (shared) copy
of the map (because lookup is read-only, and so no write-copy is required). But
inserting into the lookup table wasn't lock protected (and shouldn't be because otherwise
that defeats the point of RCU).
So just drop it.
The diskreader uses the route's monitoring state when deciding whether or not
to fetch MIDI data for playback. Route::monitoring_state() would determine
whether or not we were already rolling to affect its return value. However,
using Session::transport_rolling() is affected by pre-roll and consequently
returns the wrong value during transport startup. Instead, we now use
::transport_state_rolling() which ignores preroll conditions. This leads to the
DR actually reading MIDI data from the initial playback position, which fixes
this issue.
Note that the bug only occured if the track or the session was rec-enabled. The
monitoring state value was always correct for non-rec-enabled conditions.
When using a UADx plugin on a Mono track in Ardour, the plugin
is configured to be Mono. by calling `setBusArrangements`.
The call succeeds and querying the Bus layout via `getBusArrangement`
as suggested by https://steinbergmedia.github.io/vst3_doc/vstinterfaces/classSteinberg_1_1Vst_1_1IAudioProcessor.html#ad3bc7bac3fd3b194122669be2a1ecc42
confirms this. The plugin acknowledges the speaker layout
for both input and output (Vst::SpeakerArr::kMono = 0x80000)
```
Input BusArrangements: 0 chan: 1 bits: 80000
Output BusArrangements: 0 chan: 1 bits: 80000
```
but UADx plugins crash later during process() if any of the lower
bits are unset and the bus is enabled.
PS. The plugin does NOT crash as long as a lower bit
(Vst::SpeakerArr::kSpeakerL or ::kSpeakerR) remains set
in addition to kMono.
Directly loading a new session (Session > Recent) stops the engine
when the sample-rate mismatches. All is fine.
When closing a session (Session > Close), the engine is kept running.
Loading a different session with different sample-rate shows
the "SR mismatch" dialog. Reconfiguring the engine then does not call
`Session::immediately_post_engine` again.
AudioBuffer::read_from() only replaces data within the given
range (offset .. n_samples + offset) leaving the rest of the
buffer untouched.
With in-place processing, where the same MIDI buffer is used
for input and output, each sub-cycle must only clear the
processed range, while leaving the rest of the buffer
untouched.
MIDI playback used samples instead of usec.
MIDI capture used time-stamp from previous cycle.
buffer-size changes were not applied to MIDI port latency
When a session is loaded, click_io->set_state is called twice.
setup_click() is called when the engine re/starts, and
possibly again from Session::set_state.
During session construction, Port connections are not directly
made. Port::set_state just creates a list, which is later
applied by Port::reconnect from Session::hookup_io.
However, the second call to IO::set_state() calls IO::ensure_ports
again. Since the port already exists, this calls
Port::disconnect_all (while holding the process lock).
Even though the port is not connected at this point in time,
this triggers a ARDOUR::PortManager::connect_callback which
is emitted from the Audioengine when the process-lock is released.
While IO::set_state() continues to set Port::state, and fill
the Port::_[ext_]connections lists, this data is invalidated
moments later when the engine resumes and ::connect_callback
calls ARDOUR::Port::port_connected_or_disconnected.
The solution is to simply not call Port::disconnect_all
if the connection is not yet made (Session::InitialConnecting)
On windows this is still limited by the timer resolution, but
it's a start. This is mainly intended to be used with NDI or
other external sources without actual audio hardware.
This correctly sets audio port I/O latency using the
portaudio API.
Per MIDI device port settings are not completely implemented.
En/disabling MIDI devices or setting custom MIDI port latency
is not functional as-is.
Sequence<Time>::append() expects events to be sorted.
Previously this only worked for non-overlapping region,
or if all events in the later region(s) are after than the
last even in any earlier region.
This fixes several callsites that were passing samplepos_t to get a TempoMetric,
some of them somewhat significant (e.g. VST plugins that want tempo information).
Bad API design on my part, apologies.
This commit combines libs/ and gtk2_ardour because the new private status
of the ::metric_at() call would be a blocking point for git bisect
* Use an atomic reference count since the freeze-thread
can call use_playlist.
* Remove explicit argument to construct unused playlist
because playlists are unused by default. This also
lead to use-count becoming negative (or rather UINT32_MAX)
This fixes a random crash with stop-and-forget capture.
When aborting capture, the disk-writer can emit
midi_write_source->drop_references ()
in the butler thread, which leads to a direct call to
Session::remove_source.
This can happen before or after Region::source_deleted
is called which is initiated from the same signal.
Furthermore it was possible that Region::source deleted
was called concurrently from the UI thread via SourceRemoved
for whole file regions, which lead to memory corruption.
TransportMasterManager::destroy () destroys any remaining
TransportMasters which in turn unregister their ports.
However the PortEngine was already destroyed.
When starting RangePlay while the transport is already rolling
the transport is now stopped (and de-clicked) before locating.
This should not clear the RangeStop event when it is caused
by a RangePlay request.
In rare cases DiskWriter::run() may call finish_capture()
concurrently with the butler thread from transport_stopped_wallclock,
this can lead to memory corruption (CaptureInfo).
Using a Mutex here is not great, but it is not usually contended
and better than crashing at rec-stop.
We should probably change DiskWrWiter::_was_recording into an
atomic bool, and use CAS to prevent concurrent calls.
The GUI was able to free memory (MidiTracer::disconnect),
while the tracer is concurrently still in use in rt-context.
This lead to memory corruption in MIDI::Parser::scanner.
port-meta-data depends on the audioengine backend/device
settings. Those are only available after the engine is started,
not from within the backend's _start() method.
This is is only relevant for callback based backends.
Backends with a blocking process thread explicitly emit
port-manager callbacks there before entering the main loop.