This also allows to disable the resampler, effectively disabling
varispeed support, for the benefit of adding no additional latency.
By default 2 * 16 samples latency are added, due to port-resampler,
this is not desirable if Ardour is used as mixer only.
Session::route_processors_changed accumulates signals emitted
in realtime and processing is delegated to a dedicated rt-safe
thread. Previously this resulted in any changed to be converted
to a `GeneralChange`, which unconditionally triggered a route-reorder.
Record-arming a track causes a MeterPointChange (meters change to "in"),
and this caused routes to be resorted and a latency-update.
While the former is reasonable (Ardour prefers to process
rec-armed routes first), the latter certainly is not.
Even if we start at time T, if the tempo point before T is ramped, we need to
adjust it's omega value based on the beat time of the following tempo point. If
we don't do this, then using that tempo to compute ::superclock_at() for
subsequent points will be incorrect.
Note: there may be an ordering issue here with Tempo/Meter points. We might
need to pass over all tempo points first, then process meters etc. Something
like that.
libs/ardour/session_state.cc:1500:13: note: in instantiation of
function template specialization 'XMLNode::set_property<unsigned long>'
requested here
libs/pbd/pbd/string_convert.h:151:11: error:
type 'unsigned long' cannot be used prior to '::' because it
has no members
The master needs to be restored first, otherwise setting
the master value with be propagated. Furthermore the
actual value is saved at the time of VCA assignment.
Restoring the vaule needs to scale by the master-reduced value.
changes in tempo can be negative (decelerando/slowing down), and thus so can _omega. We cannot call log() or its
cousins on negative values, so in this scenario use an alternate expression for "t from b" in the tempo.pdf paper
We discovered in the past that the C++ API for GSource/Glib::Source has some fatal and unfixable flaws. Copy similar
code and just use the C API for GSource instead
This is based on code from earlier commits that were later reversed, but we need some mechanism
to ensure that threads have a thread local tempo map ptr set. The big difference is that this
time we do not implement this for all instances of an AbstractUI - implementation is left to
each thread/event loop
Events in the delay-buffer must be shifted back every cycle.
Also in case of fixed-delay-lines events may not be in sequence
since events are only sorted at backend port-level.
this solves the oft-recurring problem where we assign
a beat-count of '3' or '7' because minipm mis-detected the tempo,
and that situation is vanishingly rare. it's better to assume 4 or 8
the user always has the option to change the number of beats (and
therefore the detected tempo) manually, for those clips that are
in a different time signature. but minibpm cannot be expected
to help us there.
NOTE: this is a fallback to make things 'just work' lacking any other context.
* if the tempo is detected in the filename, we use that instead
* clips that were recorded to the timeline use that bpm+timesig
* in the future we can use file-metadata (acidized wave?) instead
* this is audio-only: midi files can have an embedded timesignature
but... given no other information, experience says the vast majority
of downloaded/purchased clips will be 1,2 or 4 bars at 4/4.
omega can be computed from Beat or superclock duration. This gives rise to
different units for omega, and we must use the correct value in a given
context.
This commit also changes the way that the audio time omega is computed during
TempoMap::reset_starting_at()
Rampable only existed to provide exclusive access to ::set_end() for the
TempoMap. More idiomatic C++ but now that _type has also gone away, so has
::set_ramped() and it really was not worth keeping it around.
Ramped/Constant is really a function of start/end note_types_per_minute. Having
a separate member is really just caching it and leads to errors or risk thereof.
MidiBuffer::read_from() clears the buffer, so events were not
accumulated into the delay-buffer.
This also includes a small optimization and comments for the
variable delayline.
* when you copy a Range into a playlist, the playlist's 'timeline' should
begin at the start of the selected Range. Regions should retain the
offset they had from the Range's start.
* this fixes the Draw tool when adding notes; if you tried to draw in
a region with a trimmed front, the note would not get added in the correct
location
syntax for beginning and ending a diff command is:
"new_diff_command" -> "apply_diff_command"
syntax for applying a diff_command is:
"_as_commit" : Begins and Commits a standalone undo Command
"_as_subcommand" : adds to undo but does not Begin or Commit a Command
"_only" : (new) applies the note_diff but does not have any effect on undo
This is useful after a freewheel export, where a realtime-stop
is called, but the actual Locate/MustStop event is only processed
later. Once the session switches back to normal processing after
export the transport is still rolling, TSFM schedules a de-click
locate. This may play some remaining audio.
This new API allows to hard stop the transport, without going
via any session-events and process_with_events. It is intended to
be called from the freewheel process-callback in the last export
cycle.
The idea is to run a plugin outside the process graph, and provide
its I/O as port (much like an external JACK app).
The intended use-case is NDI (provide additional I/O), but it could
also be useful for other cases.
This allows to pass any GraphChain to the Graph to process.
It removes the need to use a mutex to swap two dedicated
chains (setup-chain <> active-chain, pending-chain).
Also various special cases pertaining to graph interaction
while auditioning and route-deletion can be removed.
This also unconditionally creates a graph-thread for GraphChains
to be processed, even if the main callback uses a special-cased
sorted RouteList if there is only one process thread.
The process-graph should only be concerned with GraphNodes,
which may or may not be Routes.
This also removes intrinsic connection information from
the graph-node. Connection information is to be kept separate
from the nodes.
When the graph is re-calculated in the background, old information
has to be retained until the new graph becomes active.
Previously *new* information was already stored in the nodes
while the graph is sorted, even though the new graph was not
active.
In all years of using these assert()s never triggered. Besides
there are valid_port() tests in other strategic locations that
are not periodically hit in realtime context.
The set uses a custom sort-by-name comparator.
Previously it was possible to have an inconsistent set iterator.
std::set::find() did not find a given port while std::find() did.
This fixes using std::set::find() on the PortIndex set.
Temporal::most_recent_engine_sample_rate is used in performance-critical code so shouldn't be accessed via a 'get()' function. But (via the TEMPORAL_SAMPLE_RATE #define) it does get accessed outside of libtemporal and therefore needs to get exported.
We were using a given tempo or meter point as part of the metric used when
recomputing its position. In fact, the metric should be only use the
tempo/meter immediately preceding the given point.
It is more useful to get the actual TempoPoint than just the Tempo
that we discover.
Aside: it would be awesome to understand how to use boost::intrusive to get the
next tempo point directly from the tempo hook.
On M1, the cross-thread channel sets G_IO_PRI in addition to G_IO_IN
this breaks various assumptions in receivers, which test for ~G_IO_IN
as error condition.
We modify elements of the source object, not to mention the peakfiles on disk. This
was a regression introduced when switching from Lock to RWLock, caused by a failure
to recognize this as a case where a write lock was required.
The presence of scoped_array<> as a member of AudioSource (peak_cache) is suspicious
nevertheless, and we should establish that it serves a useful purpose.
Return from poll_for_request() when CrossThreadChannel is
closed/destroyed. -- see also f4166fb61d
This also cleans up poll API usage, and check for nonnegative
return value is added.
This is mainly relevant for Mixbus, which allows cyclic-connections
to record Master-out on a Track (which unconditionally has Mixbus send
and feeds master).
In Ardour it may also cause issues when creating loopback connections,
however latency is not usually updated with invalid graphs (old
process graph remains in use).
Otherwise it fixes a crash connecting Track 1 -> Track 2 -> Track 1.
This also optimizes Route::output_effectively_connected by caching
any prior lookup. This helps e.g. Track 1 -> Track 2 -> Master.
The connection "Track 2 -> Master" now only need to be looked up once.
See also 7958031287 and a556e96ed0
Changes handle_cursor_right_press() in PluginSubviewState to pure virtual
function so that PluginSelect and PluginEdit can each have their own
version.
The cursor_left and cursor_right mackie control buttons will now move the
sends subview left and right like it does in the plugin subview. Previously,
if you had more than 8 sends (which is almost always the case for Mixbus),
then sends 9+ were unreachable on an 8 channel controller.
This is in preparation for a pure-virtual base class for
PluginInsert to expose `DropReferences` in the virtual base.
```
class PlugInsertBase : virtual public PBD::Destructible
class PluginInsert : public Processor, public PlugInsertBase
class Processor : public SessionObject
class SessionObject : public PBD::StatefulDestructible
```
This fixes a crash on windows, close(-1) or closing an
already closed FD will abort the application
(Save-As can trigger the issue in done_with_peakfile_writes).
Note that g_open() returns -1 if an error occurred. However
other negative number may still be a valid FD.
Fix compilation error seen with gcc 12.0.1 on Fedora 36:
In file included from ../libs/ardour/ardour/variant.h:30,
from ../libs/ardour/ardour/parameter_descriptor.h:25,
from ../libs/ardour/ardour/automation_control.h:39,
from ../libs/ardour/ardour/amp.h:30,
from ../libs/ardour/session.cc:61:
../libs/pbd/pbd/compose.h: In instantiation of ‘StringPrivate::Composition& StringPrivate::Composition::arg(const T&) [with T = ARDOUR::PresentationInfo]’:
../libs/pbd/pbd/compose.h:277:31: required from ‘std::string string_compose(const std::string&, const T1&, const T2&, const T3&, const T4&) [with T1 = std::__cxx11::basic_string<char>; T2 = unsigned int; T3 = std::__cxx11::basic_string<char>; T4 = ARDOUR::PresentationInfo; std::string = std::__cxx11::basic_string<char>]’
../libs/ardour/session.cc:3268:4: required from here
../libs/pbd/pbd/compose.h:122:20: error: no match for ‘operator<<’ (operand types are ‘std::ostringstream’ {aka ‘std::__cxx11::basic_ostringstream<char>’} and ‘const ARDOUR::PresentationInfo’)
122 | os << obj;
| ~~~^~~~~~
This might also fix a similar problem with clang, and
https://github.com/Ardour/ardour/commit/5bbfac23808 can be backed out.
This commit leaves two issues outstanding:
1. unclear/ugly semantics for drag operations that reset the GUI thread's tempo map to the writable copy
2. undo/redo for the tempo map
These will be addressed in future commits
Found via `codespell -q 3 -S *.po,./share/patchfiles,./libs -L ba,buss,busses,doubleclick,hsi,ontop,ro,seh,siz,sord,sur,te,trough,ue`
Follow-up to 364f2f078
When building with --use-external-libs on Fedora, Ardour would fail at
runtime with messages like:
symbol lookup error: .../vamp/libardourvampplugins.so: undefined symbol: kiss_fftr_alloc
Try to automate handling of this error situation.
Fedora packaging worked around it with a custom patch that we rather
would avoid:
https://src.fedoraproject.org/rpms/ardour6/blob/rawhide/f/ardour6-missing-kissfft.patch .
This allows two reader threads to proceed without blocking each other, as can
happen when the butler renders a MIDI track into an RT-safe buffer while the
GUI reads the same MidiModel/Source for visual display.
This also requires a change in the type of reference held by
a MidiAutomationListBinder.
Both the MidiSource and MidiModel have a reference to each other, and it is
important that we avoid circular references to avoid problems with object
destruction. We had been accomplishing this by having the Model hold a
weak_ptr<MidiSource>. However, the lifetime of a MidiSource and its MidiModel
are coincident and there's really no need to use a smart ptr at all. A normal
reference is just fine. However, due to constructors that accept a serialized
state, we cannot use an actual reference (we cannot set the constructor in the
initializer list), so we use a bare ptr instead.
This forces a similar change in MidiAutomationListBinder, which also maintains
a reference to the Source. However, the only purpose of this object is to
ensure that if the Source is destroyed, relevant commands will be removed from
the undo/redo history, and so all that matters here is that the binder connects
to the Destroyed signal of the source, and arranges for its own destruction
when received.
Note that the previous construction of the binder, actually holding a
shared_ptr<MidiSource> would appear have prevented the Destroyed signal from
ever being emitted (from ~Destructible), and so this may also be a bug fix that
allows MidiSources to actually be deleted (the memory object, not the file).
This also requires a change in the type of reference held by
a MidiAutomationListBinder.
Both the MidiSource and MidiModel have a reference to each other, and it is
important that we avoid circular references to avoid problems with object
destruction. We had been accomplishing this by having the Model hold a
weak_ptr<MidiSource>. However, the lifetime of a MidiSource and its MidiModel
are coincident and there's really no need to use a smart ptr at all. A normal
reference is just fine. However, due to constructors that accept a serialized
state, we cannot use an actual reference (we cannot set the constructor in the
initializer list), so we use a bare ptr instead.
This forces a similar change in MidiAutomationListBinder, which also maintains
a reference to the Source. However, the only purpose of this object is to
ensure that if the Source is destroyed, relevant commands will be removed from
the undo/redo history, and so all that matters here is that the binder connects
to the Destroyed signal of the source, and arranges for its own destruction
when received.
Note that the previous construction of the binder, actually holding a
shared_ptr<MidiSource> would appear have prevented the Destroyed signal from
ever being emitted (from ~Destructible), and so this may also be a bug fix that
allows MidiSources to actually be deleted (the memory object, not the file).
This note-mode had no effect on anything at all, at least as far back
as 5.12. There is a note-mode in the GUI which affects the duration of notes
added using the GUI, and that remains in place. It is not clear
if the _percussive member of Evoral::Sequence ever had any effect on
the actual MIDI event stream the Sequence could generate.
If queue_draw is "frozen", we simply accumulate drawing
requests in a (union) rectangle, and when finally "thawed"
the canvas submits a single redraw request for the entire
accumulated rect.
Although in theory this is all that GTK/GDK does for
draw requests, callgrind reveals significant costs
associated with the actual calltree for GtkWidget::queue_draw_area().
One potential cost is that GDK also maintains a list of
invalidated rectangles in addition to the union, and
for MIDI regions with thousands of notes, this can represent
real overhead. This approach dispenses with the rect list,
since our Canvas drawing model only uses the union rectangle
anyway.
Code within the method was using @param start_time rather than start, which is a modified
value required to generate the correct results.
This comment also contains some logical reordering, optimization and commenting
on this rather complex method.
Note that the value is still defined in Beats (ticks) rather than seconds
which means that the interpolation density is tempo-dependent. This
should still likely change one day.
The tooltip should remain visible until the mouse leaves
the item's bounding box. Also do not start the tooltip
timeout if the item does not have a tooltip.
::start_audio_export() may be called from a background thread
which does not yet have a thread-local TempoMap.
Track::seek() calls ARDOUR::AudioPlaylist::read()
which calls Playlist::regions_touched_locked() which may require
a TempoMap to calculate overage with Temporal::Beats
This fixes mp3 export on Linux/ARM (Raspberry Pi) with
system-wide dynamically linked ffmpeg. Otherwise the there
would be library conflicts with ardour-bundled libz and libcairo.
This allows regions to be correctly imported to their
actual track number now that they are numbered from zero
without any gaps by ptformat, removing the need for a lookup table.
std::upper_bound() was not the correct tool to find the existing point,
it should have been std::lower_bound(). For code consistency, this
change doesn't use either but like ::remove_tempo() and similar methods,
just iterates over the whole list
bugfix: changing the FA state can overwrite the clip's name and color
Some params (like gain) can and should take effect immediately
by directly setting the properties. TRIGGER_DIRECT_SET does that.
But we still, ALSO have to set the ui_state, because when the
triggerbox imports ui_state via update_properties() it will
overwrite your changes.
Said another way: since we use a queued ui_state to set the properties,
you ALWAYS have to set and use the ui_state mechanism, even if you want
to short-circuit the process for specific properties.
Having identified the trigger that will be running at a given transport position, we determine its effective
length (not necessarily its own length) and last start, then "jump" forward to the next-earliest start
point prior to the transport position. This greatly reduces the amount of actual audio processing we
need to do to prepare the trigger to run in sync at the transport position.
This commit also adjusts the targetted transport position by the processor's playback offset, so that
it is correctly prepared to run() once the transport starts again.
Logic errors when using cue-isolated or empty triggers were also fixed.
We know when we call non_realtime_stop() if we will be subsequently
locating. If so, do not do an additional non_realtime_locate() from
within the stop.
Region-gain (unlike other automation) is specific to the
region and independent of the source. Region::start() offset
does not apply. When region-start is trimmed the region's
envelope is modified (not just offset). The event-list is truncated.
Any audio-region envelope does (and must) have a point exactly
at the start and end of the region.
truncate_start() can thus calculate the earliest position of
valid events with the new length relative to the last event.
The mathematical operator for that is subtraction, not distance.
This commit fixes an issue where if your controller was currently on a
bank not near the first few tracks, and you then deleted tracks, the
controller bank buttons would appear unresponsive because of the
"if (initial >= sorted.size())" check in switch_banks().
This would occur when the difference between the _initial_bank and
whatever sorted.size() returns was greater than or equal to strip_cnt.
For example, if your _initial_bank was 48, your strip_cnt was 24 and you
had 24 tracks after the deletion, then the above conditional would evaluate
to true and exit out of switch_banks BEFORE actually switching the bank,
effectively stranding the controller unless you added enough tracks back.
If the QCon ProG2 is selected as the device profile, then the button map
will be built with handlers that map specific to the iCon QCon ProG2
controller.
Adds function to clear solo and (with shift) mute all channels.Adds
function to save and (with shift) save as. Adds function to toggle all
processors on selected track. Adds functions to select track to the
left/right. Adds function to add marker and (with shift) remove marker at
playhead. Adds function to undo without needing shift modifier.
Adds a function to go to the next and previous marker. Adds a function to
redo (without requiring a shift modifier). Adds a function to open a
project.
Adds a device profile for iCon Platform M+ controller and new function
that flips between editor and mixer window. This function is mapped to
"mixer" button on controller.
We do not want a value as large as the previous one, which limits the time
range that can be represented in 62 bits unnecessarily. The new value is
9 times smaller than the previous value, and loses only 384000 as a significant
factor.
This commit also switches to using an (inline) accessor for superclock_ticks_per_second,
making it possible in debug/testing phases to spot early/illegal uses of the value.
This does the internal shutdown of a Trigger that is shared between
a normal shutdown and when stopping for a locate/stop. There's no
output to buffers possible.
This method/design may need to change if/when we add declicking for
various conditions
Now using a globally-scoped static variable which is updated by the
AudioEngine whenever an SR change occurs. Defaults to 48kHz and can
be used even before there is a backend.
Due to recent changes, when the master bus is disconnected its
private port latency was never unset. This lead to misalignment
when using stem-export if master (or monitor) output was not
connected.