Some plugins call back to restartComponent() directly from
IEditController::setComponentState.
This lead to a deadlock since VST3Plugin::load_preset
takes a lock (since 7.2-85 b27467157b), and restartComponent
takes the same mutex again.
This fixes an issue with Blendeq (and likely other plugins)
that call `restartComponent(Vst::kLatencyChanged) from the
in realtime context from plugin's process
e.g. loading a u-he zebra preset using the plugin's GUI
internally changes the controller state without using the
`performEdit` API, but instead calls `restartComponent` wit
the `kParamValuesChanged` flag to perform a a batch update.
This now also updates Ardour's AutomationControl to match.
Now that we can require glibc 2.3.4, we can use RTLD_DEEPBIND.
This can help with plugins that do no hide symbols for their
contained statically linked libraries, and instead would use
use symbols.
Note: This only works on Linux.
CPUID is part of x86_64 ISA to query CPU features. In order to determine
AVX512F ISA extension, EAX and ECX needs to be set to 7 and 0
respectively before invoking `cpuid` instruction. This commit also
removes inline assembly for __cpuid in favor of using compiler provided
intrinsic functions. Both GCC and clang provides __cpuid like function
via __cpuid_count intrinsic.
This commit also creates a portable wrapper over compiler intrinsic
functions, __cpuid and __cpuidex. `cpuid' provides base level ISA query
and `cpuidex` provides extra extension information like AVX512F. These
wrappers lean towards MSVC like API.
References:
CPUID Docs: https://en.wikipedia.org/wiki/CPUID
GCC's ``docs" on __cpuid_count:
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/config/i386/cpuid.h
Clang's docs on __cpuid_count:
https://clang.llvm.org/doxygen/cpuid_8h.html
MSVC's docs on __cpuid and __cpuidex:
https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex
In many cases optional sidechain inputs are not used.
Previously sidechain ports were created, but remained
unconnected and silence was passed to the plugin's key input.
Plugins can detected if a pin is connected. Some plugins
(e.g. VST3 Waves SSL Comp) activate the sidechain processing
automatically when depending in connection.
It is more common that a user does not want to use an external
sidechain, and if they want they should use the pin-dialog
to connect it. So leaving it off by default is sensible.
see also #9223
This is in preparation to allow to skip adding sidechain ports
by default. When a user later adds the SC input ports, it is
convenient to connect the pins just like they are when they
are connected when instantiating the plugin (via reset_map).
Ignore sidechain pins, when no sidechain ports are present.
Otherwise a plugin with 1 audio input and 1 sidechain input
would match a stereo track when the sidechain port is not present.
These tests use reference files that were generated with a particular
value for superclock_ticks_per_second. The default for that has changed
since the last time the reference files were updated though, causing
tests to fail. Rather than updating the reference files for the new
default value, this makes the test not depend on the default value by
hardcoding the value that was used to generate the reference files.
Only glibc has __ppc_get_timebase() function. On FreeBSD use the same assembly call that __ppc_get_timebase() actually executes.
This probably should be extended to musl and OpenBSD, but I have no way of checking that.
After recovering from a crash, the user still needs to
retain the option to ignore the changes that were done
just before the crash after investigating them (or save them
into a snapshot).
Previously crash recovery unconditionally overwrote the
session file (see discussion on bug tracker).
This was removed in
bf0a5256472316df357b
"SaveState" was chosen because "State" prefix overlaps with
"Stateful", and "SessionState" overlaps with "SessionEvent"
debug names. `-DState` or `-DSession` overlap respectively
with unrelated debug output.
set_parameter_internal() normalizes the value (C++ reference),
when setting a parameter manually (inline control, generic UI)
only the shadow_data is updated (which is supposed to be
normalized).
Adding a MIDI only plugin at a point where there is no
MIDI data, and/or additional audio signals results in an
'Impossible' match.
Those are usually resolved by trying to replicate the plugin,
and the fallback is to "Replicate 1 time".
While this is effectively equivalent with ExactMatch (use
1 instance), it is semantically different: Audio sources
will be ignored and if there is no MIDI signal, the MIDI
input remains unconnected.
It is the opposite to "Hide" (plugin has more inputs
of a given type, which can be fed by silence), since it has
fewer inputs of a given type signals are "dropped".
Strictly speaking we should special case this "Replicate 1 time"
case to "Drop" [sic]. which only assert(!reconfigurable_io()).
This removes the special case which assumed unity gain
when reproducing mono files on a stereo system.
ITU-R BS.1770 however specifies a channel weight of 0dB for
left, right and centre, regardless of the total channel count.
Tech 3344 6.16 mentions a 3dB attenuation to maintain the
loudness level of a mono audio signal in multi-channel signals,
and Tech 3343-2016 further specifies that "Ideally, a downmix
operation should be loudness-agnostic".
If the stop takes effect on a process cycle boundary, do not just blindly pick
the next trigger; instead using the same logic as if the stop was not on the
boundary.
Previously resampler ratio could only set when creating
an audio port. This is in preparation for setting resampler
quality when the session rate mismatches.
The session's rate is only known after basic session-setup
is performed. At this time Click-IO already exists.
Previously only adding an aux-send triggered a graph-reorder but copying
or deleting sends did nothing.
Adding/removing an aux-send may not even change the graph, but
both upstream/downstream latency can change and delaylines need to be
configured (which is done by calling update_latency_compensation with
force_whole_graph = true).
This fixes an issue with incorrect initial latency compensation after
copying a send (any later change to connections will correctly
recalculate it).
This allows to move or copy whole sections of the timline (everything
you hear) to a differnt position on the timeline.
NB. Markers and tempo-map are not yet moved, and interpolated MIDI
events are lost.
A VST3 plugin can have additional busses which were not
available in older versions of Ardour. For compatibility
reasons those should remain unconnected. This is achieved
by using a custom I/O config (same way a user would configure
this).
This unconditionally enable all busses with connected pins.
It does not provide re/configurable I/O (like Audio Unit), nor
implement dynamic Vst::kIoChanged callbacks. But regardless
this allows for plugins with multiple I/O busses (e.g. drum synths).
When not using inplace processing (because I/O pins connections
are not an identity matrix), dedicated inplace-buffers are used.
Those buffers contain silence on unused ports, and hence always
valid to use. However it is still useful for plugins to know
if a plugin-port is actually used. VST3 can disable busses
for unconnected pins.
This resolves an ambiguity between abs(int) and std::abs(T) which
depends on context and compiler version and optimization.
In context of #9057, (gcc-6.3 -O3) math.h `abs(int)` was used. This
truncated the superclock value to 31 bit in ControlList::extend_to.
The previous code only used the 1st multiplicand was use to
determine the direction of rounding, breaking commutative property
`muldiv_round (1, 3, 4) != muldiv_round (3, 1, 4)`
Previously the current iterator bbt was moved to p->bbt().
From then on, no grid line is reached if the point p is not on
a bar and mod_bar != 0 or the point is not on an expected beat_div.
e.g. when using bbt += mod_bar, and a tempo-change is at 5|2|0.
iterations continues 6|2|0 7|2|0 is_bar() is always false
and no more grid-lines were added.
Rather than trying
bbt = round-up-to-next-grid-mod-div
and then finding the metric for that position, this
approach only does the latter using the already incremented
BBT position.
This allows to properly toggle "Glue to Bars/Beats".
Editor::toggle_region_lock_style uses Region::position_time_domain(),
However Region::set_position_time_domain() checked the duration's
time-domain.
Furthermore timecnt_t::set_time_domain() changes both the
position and the duration's time domain. This can lead to
various issues. We only need to change the time-domain of
the timepos_t _position.
IParameterChanges (_input_param_changes) queue should not be
modified while the plugin processes. Doing so can lead to invalid
iterators.
Also activate/deactivate and state restore must not happen
concurrently with processing.
Some plugins (e.g. Roland JD-800) have zero controls, but
MIDI control with are not directly accounted for. This
results in a zero-size ParameterChanges queue, which later produced
a segfault when trying to enqueue a MIDI change:
```
input_param_changes.addParameterData (id, index)->addPoint (sample_off, value, index);
```
This is intended to fix an issue with odd filenames on Windows,
particularly forward and backwards single quotes as part of a filename.
Previously the filename was passed as parameter to ffmpeg as
UTF-8 string to SystemExec::make_wargs, which is fragile on Windows
in absence of a execve() call.
This test seems to be compiling and passing just fine (when run in
isolation), so turning it back on seems like a good idea. To make it
pass when run as part of the full ardour test suite, this does remove
the WebSockets control surface from the control surfaces test though, as
that control surface messes up the event loop of the main thread, which
would otherwise cause use-after-free crashes in the session test.
This also fixes a potential buffer overlow on Windows.
Window _snprintf does not null terminate the string in case
the formatted length is longer than the given buffer size.
http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx
(mingw's uses _vsnprintf under the hood which is also affected).
Alternatively we could rely in g_snprintf() to truncate the
string.
Session::setup_bundles() creates mono and stereo bundles from hardware
inputs and outputs. For mono bundles the name of the bundle was based on
the pretty name of the port (if the port has a pretty name), however
stereo bundles always used the indices of ports to make the name.
When using pipewire (or otherwise having multiple jack clients exposing
physical ports) the indices are even less meaningful than otherwise (as
different devices could appear in arbitrary order), so also using pretty
names for stereo bundles makes the UI less confusing in places where
these bundle names are used (for example the menu when clicking on an
IOButton).
Previously AudioPlaylist::read always returned the timecnt that
it was supposed to read into the buffer, regardless if the given
number of samples was read. The check in DiskReader::refill_audio
`if (nread != to_read)` never triggered.
This can happen when changing an audio-region's time-domain to
music-time (glue to bars/beats). Region-length (beats converted
to samples) can exceed the actual audio-source length (in samples).
AutomationList::start_touch must not start a write-pass.
That function is also called when the transport is no rolling.
A write-pass is started via AutomationWatch::add_automation_watch.
This fixes a crash when deleting routes, while there are still
automation events queued for the route.
Specifically, SoloControl has a reference Soloable& _soloable; which
points to the parent route. A rt-event can still hold a valid shared
pointer to the SoloControl, even if the route is destroyed.
Calling SoloControl::actually_set_value is fine (the control still
exists due to the shared ptr), but then checking the parent route:
```
if (_soloable.is_safe() || !can_solo())
```
accesses the already deleted route, which causes a crash.
The solution implemented here is to not bind a shared_ptr to the
realtime event. However, since deletion of the route happens in the main
UI thread, there may or may not still be a race.
In practice, this mostly means integers when presets leave off the ".0", but we
implement all the numeric types here for good measure.
Also while we're at it, warn about unknown types now so it doesn't take three
people a half an hour to figure out what's going on the next time something
like this happens.
This disables the feature added in 057fd9259e.
The idea was to use double-click to reset the fader (like
Harrison consoles). Simply re-select can lead to accidents.
We cannot call TempoMetric::superclock_at (BBT_Time) if the BBT time is beyond
the range of the current TempoMetric. We must discover that *before* we make
that call, not as part of the test to see if we've exceeded the range.
> This group functionality can be convenient for performing
> intermediate compositing. One common use of a group is to
> render objects as opaque within the group, (so that they
> occlude each other), and then blend the result with
> translucence onto the destination.
https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-push-group
The main use case where will be to render opaque layered
[MIDI] regions transparently onto a grid.
Now that both Audio And MIDI tracks support all three record
modes. Monitoring should be consistent. When recording
"Sound on Sound" does cue monitoring, while "layered" (opaque).
and "non-layered" monitors only the input.
Two differences remain: (1) when not recording MIDI tracks still
monitor both Input and Disk (unless Non-layered is set), and
a final special case is that MIDI tracks always monitor input
as fallback. the latter ties in with (2) audio tracks can
use hardware monitoring.
This fixes an issue when switching formats.
ExportFormatDialog::update_selection iterates e.g. WAV BWV.
If BWV was selected and a user selects WAV the following happpens
1. WAV is selected
2. BWV is deselected
3. Since BWF and WAV are the same format, ExportFormatManager
deselects WAV
This fixes a bug introduced in d06a0d9c9d. The MIDI data
has to be written first, otherwise the CC-event do not exit
and MidiModel::source_interpolation_changed() crashes.
There were many logical errors in the previous implementation. This one is
simpler to read, and appears to work much better.
It also allows the caller to specify the quarter-note subdivision to use when
generating the grid, rather than choosing only between some bar modulo or
quarter notes.
It can happen that the main AlsaAudioBackend::_device_reservation
is still busy while I/O devices are set. In this case a
dedicated AlsaDeviceReservation needs to be used which can fail
silently.
A common example is disconnecting a USB device while it is in
use. The Halted signal can show the session dialog, which calls
set_input_device_name before the device reservation of the
unplugged device terminated.
ALSA backend modified the internal state when different devices
were used, re-assigning one (usually input-device) to "None"
when it's resampled. This lead to EngineHints not matching the
EngineState, and autostart was disabled, and a dialog
"Engine I/O device has changed since you last opened this session."
Archiving creates a dedicated mono file for each Source.
When the original session has (embedded) stereo files, the
channel needs to be temporarily set to 0.
introducing a new time signature that uses non-quarter notes as the denominator
will move the beat position a given BBT time (since the middle "B" of BBT
refers to "beats" given by the denominator, not quarters).
This issue was introduced in f3423b8a77, which assumed that
number of input channels matches the number of outputs.
With flexible I/O this is not necessarily the case.
This fixes#9106, along with the previous commit.
If Route::configure_processors fails at session start,
meters are not configured (#9106), leading to a crash when
::run() is called (insufficient peak/max/midi buffers).
Previously the flag was not honored. AudioSource::write() calls
-> SndFileSource::write_unlocked()
-> SndFileSource::nondestructive_write_unlocked() which calls
-> AudioSource::compute_and_write_peaks
This produced "cannot open _peakpath" messages during
session-archive FLAC encoding. Likewise closing an audio file
calls touch_peakfile(). Although this simply failed silently.
Keep file-system paths and PBD::Searchpath mostly separate.
This amends 58c2b0a848 libs/fst directly includes relevant
ardour C++ code, so lib/fst must not link against libardour.
The problem was that 58c2b0a848 introduced additional
dependencies on other libardour functions.
libardourcp and now libardour_midisurface are not control
surfaces, but helper libraries for those.
They need to be deployed to the library folder (shared between
ctrl surfaces) and not scanned as ctrl surfaces at runtime.
Writing partial messages will lead to undefined behavior.
This does not generally happen (LV2 forge prevents overflow
of the Atom buffer itself), however if the GUI is frozen messages
may accumulate in Ardour's Ringbuffer.
Processor::deactivate must not be called concurrently with
processing. e.g. Threading rules https://lv2plug.in/ns/lv2core
This fixes a potential crash when freezing tracks
* in the past, the default behavior was: hiding a group would disable it,
and then showing the group would re-enable it
* problem occurs when user has disabled a group; hiding and showing it
unexpectedly re-enable the group
* there was a config variable to disable this behavior, but it was never
shown on the GUI and therefore not discoverable
Despite the longstanding policy, there's really no reason for
group visibility and enablement to be intertwined.
If this chnage causes a big problem for someone, they can revert to
the prior behavior by setting the new config variable in the text file
MP3 support was introduced in libsndfile 1.1.0 . It will be a simple
alternative to using external ffmpeg.
To avoid dependency on the new libsndfile or config-time checking,
hardcode the constants from sndfile.h . The actual availability will
have to be checked at runtime.
In some cases copying an instance requires an explicit
set_state() call (e.g. copy internal plugin state). This is
done by calling `set_state(other->get_state())`.
::get_state() produces XML as matching current_state_version.
(not loading_state_version).
These might be the values that PA would have chosen anyway, but make it
clear that Ardour is in control ... and will let the user control
"everything" with the buffer size.
This will also change the internal backend name, so it will miss the
previous 'config' setting '<State backend="Pulseaudio" ...'` and the
session file's '<EngineHints backend="Pulseaudio" ...'. But that is no
big deal after upgrading. Especially after the backend has been broken
for some users for a while.
In the log output, the error would look like:
[ERROR]: Export initialization failed: Exception thrown by AudioGrapher::SndfileWriter<short>: Could create output file (.../export/something.wav)
Add the missing negation.
But it would perhaps be better phrase the message differently so it not
just hints so strongly towards a file system error preventing file
creation.
Perhaps something like "Failed to initialize sound export to %s"?
Many formats use ExportFormatBase::SF_Double which incorrectly would end
up in the default "we don't handle anything else within ardour" branch.
(It happened to work correctly anyway, since ExportGraphBuilder::SFC
handled the "magic" value 1 the same was as the "error" value 0.)
For correctness, use the "magic" value 1 for double.
The libsndfile format was masked with 0xf instead of the usual
SF_FORMAT_SUBMASK. It seems like the end result generally was correct
anyway, since no supported format used subtypes that used the low bits
for anything else. Most formats use SF_FORMAT_PCM subtypes. (Only Ogg
Vorbis uses a subtype, but that happens to have 0 in the low bits and
ended up in the "this will never happen branch" ... which happened to
work too.)
This could however be a real problem when SF_FORMAT_MPEG_LAYER_III with
value 0x82 is supported ... unless worked around in some way.
I don't see anything anywhere that could stuff anything in the high bits
of the subtype, so this trivially fixed by using SF_FORMAT_SUBMASK
correctly.
Apply SF_FORMAT_SUBMASK before comparing with the expected value.
It seems like it accidentally used to work correctly for all supported
libsndfile formats anyway.
But: It seems unfortunate to hardcode Vorbis in this place. Other
formats with quality control would have to be added to the list too. It
would be nice to do use something like has_codec_quality ...
Before, an export format with an invalid enum value (for example in the
Encoding id) would crash Ardour with:
unhandled exception (type std::exception) in signal handler:
what: unknown enumerator FOO in PBD::EnumWriter
That kind of error can happen if a new type is introduced and users
switch back to versions without it.
Instead, catch such exceptions while loading a format, log an error, and
skip the format - similar to how other format loading errors are
handled.
DeviceInfo (bindings file) can include explicit motorized
and threshold settings. These values, when specified, are
used during load_bindings() during set_state and overwrote
any user customization.
Furthermore showing the GUI invalidated any prior setting
by explicitly calling binding_changed, which re-applies.
It adds some new strings to translate. These strings might be so rare
and technical that it is a bit pointless to translate them. But let's
stay consistent...
pa_threaded_mainloop_wait might wake up for several reasons. And there
is no point (but possibly harm) in moving on before we have verified
that PA actually is ready to receive our write without overflow.
ae3c8b19c6 and 03a17df68c reworked the transitions to and from
freewheeling. Some of it seems to have been experiments that tried
several things out, and generally it seems to have worked. It left some
commented out code. Clean that up.
The draining was introduced in ae3c8b19c6, apparently as an experiment
doing several changes. But the drain is outside the loop where
freewheeling changes, so the fix must have worked for other reasons.
There doesn't seem to be any benefit from draining at that point. The
stream is already empty. If not, we could have flushed it.
Draining right after uncorking will conceptualy create an intentional
underflow, even though it isn't reported as such. PipeWire seems to
(something like 6-12 months ago) have regressed in handling of that grey
area, causing that *underflow* to cause a request for too much data, and
thus causing constant *overflows* and unusable playback.
This change makes PulseAudio playback work for me again.
This is never for inline references to parameters, only for starting parameter
documentation blocks. The "@p" command is for this, although unfortunately
Doxygen doesn't actually do anything with it and it's just an alias for code
text.
Graph::prep is a private function called initially from the main
process-callback before doing any work, and later at the end of
each process cycle. This sets up the process graph-chain and
process trigger queue.
Tempo information is irrelevant here.
This is required to collect relevent undo/redo information, notably
automation-data changes from Playlist::update_after_tempo_map_change and
DiskReader::playlist_ranges_moved.
The realtime thread should not move regions to begin with, and debug
builds woudl also assert since no undo operation was started.
MIDI clock start at the next beat (round_up_to_beat), so
here we have to round the current tick, rather than fall
back to a tick that is not yet complete, as 14da117bc8 does.
Reproduced with the Session from #9027
Start loop at bar 40 with MClk generator enabled.
```
#3 in __GI___assert_fail (assertion=0x7fedd86c4fd5 "clk_pos >= pos", file=0x7fedd86c38b7 "../libs/temporal/tempo.cc", line=3336, function=0x7fedd86c4f60 "void Temporal::TempoMap::midi_clock_beat_at_or_after(Temporal::samplepos_t, Temporal::samplepos_t&, uint32_t&) const") at assert.c:101
#4 in Temporal::TempoMap::midi_clock_beat_at_or_after(long, long&, unsigned int&) const (this= 0x560187e92c00, pos=20691033, clk_pos=@0x7fedc02178b8: 20691032, clk_beat=@0x7fedc02178c4: 11472) at ../libs/temporal/tempo.cc:3336
#5 in ARDOUR::MidiClockTicker::tick(long, long, unsigned int, long) (this=0x56018eed6db0, start_sample=20691033, end_sample=20692057, n_samples=1024, pre_roll=0) at ../libs/ardour/ticker.cc:170
#6 in ARDOUR::Session::send_mclk_for_cycle(long, long, unsigned int, long) (this=0x56018a216340, start_sample=20691033, end_sample=20692057, n_samples=1024, pre_roll=0) at ../libs/ardour/session.cc:7495
#7 in ARDOUR::AudioEngine::process_callback(unsigned int) (this=0x5601881a4f20, nframes=1024) at ../libs/ardour/audioengine.cc:563
```
This is the first step to fix various MIDI edit issues for sessions with
tempo-changes.
The old code, using .earlier returned an absolute position when
calculating a relative distance. This is only valid if the session has a
fixed tempo, and the origin is irrelevant when converting the timepos.
This resulted in follow up issues since there is a difference when
summing two positions (each with an origin) vs adding an offset to a
position.
Note: this API changes breaks compilation until the GUI is updated.
This fixes various rounding issues. Notably superclock to sample
conversion must always round down when playing forward.
`::process (start, end, speed = 1)` uses exclusive end.
Processing begins at `start` and end ends just before `end`.
Next cycle will begin with the current end.
One example where this failed:
- New session at 48kHz
- Change tempo to 130 BPM
- Enable snap to 1/8 note
- Snap playhead to 1|3|0
- Enable Metronome
- Play
`assert (superclock_to_samples ((*i).sclock(), sample_rate()) < end);`
end = 177231 samples == superclock 1042118280
A grid point is found at superclock 1042116920 (that is < 1042118280).
However converting it back to samples rounded it to sample 177231 == end,
while actual location is 1360 super-clock ticks before end.
The metronome click has to be started this cycle, since the same
position will not be found at the beginning of the next cycle, with
start = 177232.
Similarly a samplecnt_t t, converted to music-time and back must not be
later than the given sample.
```
timepos_t tsc (t);
assert (timepos_t::from_ticks (tsc.ticks ()).samples () <= t);
```
IOW. When playing forward, all super-clock time between 1|1|0 and 1|1|1
should round down to 1|1|0. "We have not yet reached the first tick".
This allows to export a session from the commandline tool
```Lua
AudioEngine:set_backend("None (Dummy)", "", "")
s = load_session ("/path/to/session", "snapshot")
assert (s);
e = s:simple_export()
assert (e:check_outputs ())
e:run_export ()
e = nil
```
This fixes an issue when destroying VST plugin UIs
rather than hiding them. Even though is hidden before destroying it,
the vistracker is also destroyed in the same function call, before
the event can be processed. The window state remains visible="1"
Music-time has a significantly reduced resolution.
When evaluating parameter automation using sample-time, different
samples can be mapped back to the same beat-tick. This can result in
endless loops.
The same automation event is found again:
```
start: 112640 next_event.when: b13334 -> dist a5892029@a662323200 in dist.samples: 1002
start: 113642 next_event.when: b13334 -> dist a269@a668214960 dist.samples: 0
```
Note this fix may not be correct, since time-domains are mixed.
"end" is using sample-time. Furthermore The loop is only entered
if there is an event found using timepos_t(start).
Further work will be required (ideally use the same resolution for
all time-domains, or force everything that is evaluated in RT-context
to a single time-domain)
This fixes a deadlock, because tempo-map write copy
was not released. A later call to TempoMap::write_copy
will deadlock and in this case also hold the process lock.
This can happen if there is more than one tempo on the
timeline or if the tempo-difference is too large.
I'm not good with a mouse, so I found it hard to edit animation lines.
The mouse position has to be quite precise, with only a small threshold.
Looking at the code, AutomationLine sets the threshold for the PolyLine
to 4.0 . That seems to be a distance, and better for me than what I
experience.
The actual code in PolyLine is however comparing it directly to the
squared distance, making it more sensitive than expected.
Fixed by computing the squared threshold - also including the line
width.
This fixes the following problem:
When automation lines with significant change are zoomed in time, the
slope gets smaller (towards horizontal) as the control points moves
further away from the visible area. That was rendered correctly, but the
corresponding mouse events happened as if the line had a steeper slope.
The problem was caused by the X value being clamped to the visible area,
without scaling the Y value correspondingly. It has apparently been like
that for a decode, since introduced in c4f0063a68.
The problem is fixed by introducing a clamp2 function that scales the Y
value if clamping the X value.
Note: An old comment says that math goes wrong unless clamping below
COORD_MAX. It is not clear to me what math it refers to, and especially
why we don't need similar clamping on the lower bounds.
And while rarely a real problem, I guess it would be more correct and a
slight optimization to skip all lines where both ends are outside the
same bound. In theory, as it is now, the mouse could catch an invisible
line close to the border.
This addressee a bug where ardour 6 was able to write negative
duration `length="-1"` `length-beats="-3.3650500597559585e-05"`
Ideally timecnt_t::string_to should check for invalid,
negative, duration. But this also catches a more generic case.
```
exception at str.substr (1)
#3 Temporal::timepos_t::string_to (this=0x7fffffff7bb0, str="") at libs/temporal/timeline.cc:904
#4 Temporal::timecnt_t::string_to (this=0x7fffffff7ba0, str="-2") at libs/temporal/timeline.cc:294
#5 PBD::string_to<Temporal::timecnt_t> (str="-2") at libs/ardour/ardour/types_convert.h:131
```
The default clock-limit is 99:59:59:00, just under 360000 seconds
(see ARDOUR_UI::parameter_changed, clock-display-limit).
AudioClock calculates this limit pos as
`timepos_t (limit_sec * _session->sample_rate())`
This caused an overflow leading to a negative value:
```
timepos_t (359999 * 96000)
samples_to_superclock (359999 * 96000, 96000)
int_div_round (359999 * 96000 * 282240000, 96000)
```
Ideally this will be optimized, here the sample-rate cancels out,
so we could use a c'tor usin seconds.
In other cases we could cache the pre-calculated sc_per_sample:
`superclock_ticks_per_second() / superclock_t (sr)` which is an
integer for all commonly used sample-rates.
This moves the _amp from send to delivery (which already
applies gain for the master-bus normalization). This generalizes
the use of a gain stage for use in port-inserts.
Previously active Routes were retained until the end of
Session d'tor and not dropped during Session::destroy.
While most resources were explicitly cleaned up via DropReferences,
Processor UIs are kept around until the actual destructor runs.
Likewise some controllable are kept around while the GraphNode (Route)
owning it is not released.
It can happen that with a scaling factor of 1.0, rubberband
produces slightly fewer samples than the original.
Region::set_length (region->length * 1.0) is idempotent and
does not shorten it as appropriate to the longest source
via Region::verify_length(), which leads to various issues.
* Allow to bundle presets
* Do not use /usr/[local] on Windows
(This may need further work, for Windows, since default user
presets are in `file://$HOME/.ladspa/rdf/`)
Much like the edit-tool and grid-types, clock-modes are UI state.
Saving the UI state separately allows them to be used
consistently for new sessions. Previously clock-modes were set
initially (at application start) and when loading sessions.
The clock modes of newly created sessions was different
depending on loading another session prior to creating the
session. This is now no longer the case.
Re-assigning a sigc::connection does not disconnect
any previously connected signals.
WindowProxy::setup may be called multiple times. Notably plugin
windows can change the managed _window (generic/custom), which
requires a call to setup.
audio time nominally uses superclocks as its canonical unit. However
many things at a higher level only understand samples. If we
increment or decrement a superclock value by 1, the vast majority of
the time we will still get the same sample value after
conversion. Thus to correctly alter an audio time by an amount
that will manifest as 1 sample's difference, we have to use
samples_to_superclock(1)
Various operations, notably time-stretch and other filters, directly
added the generated whole-file region to the playlist.
The editor has not listed the generated Region in the RegionList.