In theory different UIs can show different meter-types, so it
can make sense to maintain the type in different places.
MeterType is a bit-set and PeakMeter implementation provides for this.
However, this is not being used, and the current implementation
was rather fragmented, cross-connected signals to keep types in sync,
allowed inconsistent meter-types in GUI and backend.
MeterType is now kept by meter itself, however it is still
saved/restored as part of the Route state.
N.B. This change breaks the API, various methods have been renamed
for consistency.
This fixes a bug when shift() creates automation for parameters that
can not have any automation (hidden parameters, Mixbus PRE).
The GUI (RTAV) aborts() when it finds an automation lane for
a hidden parameter.
This also cleans up shift() operations in general. Empty automation
lanes should be left alone, no guard-point at zero should be added.
Delaylines are not saved in the XML and internal-return is an
invisible processor not explicitly re-added when the state is restored.
They are [re]inserted during Route::setup_invisible_processors().
So this method need to be called after restoring processor state
(indirectly via configure_processors_unlocked as needed).
PS. During route creation this call happens explicitly and on session load
hookup_io() -> Route::output_change_handler() implicitly sets this up.
Speed up route creation: add_processor() takes a process-lock
and calls configure_processors() but this is done explicitly at the
end of init() already.
Route::processors_changed() signal connects to a same thread session-slot
Session::route_processors_changed() which can end up iterating over
Routes and Processors to re-calculate latency.
This takes a ReadLock after WriteLock, which eventually leads a duplicate
unlock and segfault.
Previously "zero custom/user latency" meant "default plugin latency".
This is now saved in a separate boolean allowing a user to reduce a
processor's latency to zero.
This also prepares for a global switch to use zero latency throughout
the whole session.
This saves some memory (gmsynth loads a 30MB soundfont), and also
re-initializes the synth every time to gm defaults in case some
.mid changes patches or parameters.
When a PluginInsert is created it does not have an owner right away. That's why
a we need to set the sidechains name once the owner is known, in order to
include owner's name into the name.
Furthermore we need to follow renames of the owner.
This is required by 7d8b93ad for showing error when actively recording.
It also prevents other UIs (OSC, Lua,..) to change re-configuring
sidechain ports/plugins while recording.
ensure_track_or_route_name() can produce the current name.
This fixes the following issue:
Create a two audio tracks. Their names are "Audio" and "Audio 1".
Try to rename "Audio 1" to "Audio", its name becomes "Audio 2".
currently this is only used to resolve midi events for plugins
(this is conceptually not correct, note offs should be resolved by
the disk-reader only), but it calls into all processors now (incl
disk-reader if present), which is handy (e.g. flush delaylins)
Pan-automation is evaluated directly from the control-list.
::distribute_automated() does not update the controls.
However, the *owner* of each automation-control is responsible to
evaluate automation of automated automation-controls (and emit Changed()
signals to notify the GUI and slaved controls).
This follow the same concept as PluginInsert: The Changed signal
is called on demand when evaluating automation.
This fixes pan-automation-sliders (automation-lane header) not updating.
This properly sets the port-latencies of PluginInsert owned ports as well
as handles external sends (send-target playback latency).
NB. This needs more work to ensure that Sidechain input port playback
latency is set before the feeding send queries it the connected latency.
Re-ordering process may change sidechain or external-send latencies,
but since re-ordering does not change the route's latency,
engine.update_latency() may not be called.
The processors will becomes responsible to know about loop-positions
and map latency-compensated start_sample, end_sample into the loop-range
as needed.
* Processor implement get_state(), classes derived from Processor
implement protected ::state() -- as documented in processor.h
* likewise for Route, Track: make ::state() a protected interface
* removal of "full_state", use explicit "template_save"
* use RAII/Unwind to skip saving automation-state
Immediate events are used for MIDI-Panic and to inject GUI generated
events e.g. patch-changes, note-events from the track-header
(scroomer-keyboard) and patch-change audition.
Current behavior:
- snapshot copy immediate events from ringbuffer into a buffer at
the beginning of each the cycle.
- Inject immediate events into input-buffer directly after reading the input
- process "normally"
- pass immediate event-buffer to disk-writer, so it can skip them
(don't write immediate events to disk)
- if the Route is not monitoring input: clear buffer before disk-reader
and re-inject (original) immediate events after the disk-reader
- immediate events process normally and are also sent to outputs.
This moves common code (get and fill buffers) into ::passthru()
and renames ::passthru() to ::run_route().
passthru_silence() is no longer used (it was only needed A5 style
Track::no_roll_unlocked for no-roll + disk-monitoring)
Currently ::roll() may actually be a ::no_roll() under some circumstances.
This can also happen during count-in:
transport_stopped () == transport_rolling()
and during latency-preroll:
Global session-transport speed != 0, some tracks already roll,
read data from disk and feed latent plugins.
but other non-latent tracks or busses don't roll and still have to
behave like the switch from no_roll() to roll() has not yet happened.
This changes the game WRT to monitoring as well, previously, Route:roll()
called Route::no_roll_unlocked () for conditions outlined above.
Now Track::no_roll_unlocked is called and in some cases wrongly clears
the buffers before the signal hits the disk-writer. (more work is needed
related to 61f8e53b)
On the upside this also fixes an issue with MidiTrack::no_roll not keeping
a lock while pushing data into the step-edit-ringbuffer.
This is also a step towards consolidating all entry points:
::roll(), ::no_roll(), ::silent_roll() in the Route class.
Individual Routes cannot split the process-cycle in no_roll(); roll()
by themselves. Each of the calls will flush output buffers (and offset
port-buffers). If a route feeds another route the inputs of the other
route will only see partial data.
The general goal is to align transport-sample to be the audible frame
and use that as "anchor" for all processing.
transport_sample cannot become negative (00:00:00:00 is the first audible
frame).
Internally transport pre-rolls (read-ahead) before the transport starts
to move. This allows inputs and disk to prefill the pipeline.
When starting to roll, the session counts down a global "remaning preroll"
counter, which is the worst-latency from in-to-out.
Each route in turn will start processing at its own output-latency.
Route::process_output_buffers() - which does the actual processing
incl disk i/o - begins by offsetting the "current sample" by the
route's process-latency and decrements the offset for each latent
processor. At the end of the function the output will be aligned
and match transport-sample - downstream-playback-latency (if any).
PS. This commit is a first step only: transport looping & vari-speed have
not yet been implemented/updated.
If disk-monitoring is disabled: disk-reader position is not relevant.
If Rec-arm is off: disk-writer position is not relevant.
But...
Play -> [plugins] -> Record
is basically a bounce and best done using the bounce operation.
(faster than realtime).
Input + Play -> Record -> Output
Ardour would need to align playback with the Input to be recorded
and at the same time align it with output, so that a player can play
along on the same track. That's not possible without a time-machine (or
a 2nd play processor).
While it can work in theory under some special circumstances, allowing
the disk-reader before the disk-writer is really just confusing,
error prone and valid uses cases are better handled by dedicated
operations.
We want Track to shrink, and logic consolidation is always good. Route already knew about
disk_reader and disk_writer, now it knows about _monitoring_control too
* centralize signal_latency_at_***_position to processors
* update initial-delay/roll-delay when processor order changes
* consolidate signal-latency calculation: use the same method
for processor-changes and session's post_playback_latency.
* include relative output-delay in roll-delay
* fix capture processor position & optimize stem-export latency
(roll-delay fixes pending Route:roll() update)
Generated by tools/f2s. Some hand-editing will be required in a few places to fix up comments related to timecode
and video in order to keep the legible
Rule #89: The *owner* of each automation-control is responsible to
evaluate automation of automated automation-controls (and emit Changed()
signals to notify the GUI and slaved controls).
This can happen during run(), when the Processor evaluates automation
(eg. PluginInsert does that), but needs to regardless, every cycle.
Emit Changed signal for GainControl
This follow the same concept as PluginInsert: The Changed signal
is called on demand when evaluating automation.
_processors = new_list; may drop the last shared-ptr reference.
This may deadlock in ~IO() for I/O processors or plugins with sidechain
inputs. It's been mostly a non-issues since the GUI usually holds a last
shared-ptr reference for a processor to be deleted, but that is
not always the case.
Do not use AutomationType to identify parameters, use complete
Evoral::Parameter and Automatable.
For "batch connections", a Slavables needs to implement an API to return
the relevant controls.
This is only a first step towards a more generic Master/Slave framework.
* consistent hpf/lpf controllables (actually hi/lo bell in 32C)
* HPT, LPF frequencies are exposed as EQ band
* don't expose filter ctrl for mixbuses/master
In the past, we skipped processing if the routes had no inputs or outputs.
But:
A route with a generator plugin should work even if it has no inputs.
A route with "sends" should work even if it has no outputs.
(flush reverb tails etc)
PS. That comment "from RT audio thread" was wrong.
Route::flush_processors () is called from flush_all_inserts()
from Session::non_realtime_stop() which is not in rt-context.
Besides, the processor-lock regardless of the process_lock.
This prevents a scenario where the route has had its solo control's state set from
XML, but then we configure the route's output, and invoke output_change_handler().
Without the new conditional, this would check which downstream routes are soloed,
find none, and then unset the soloed-by-downstream state of the solo control.
Moves global update of solo state and emission of Session::SoloChanged to
a single point after 1 to N solo controls are changed.
Also avoid unnecessarily emitted Activated() signal for listen controls,
though Process::{activate,deactive}() should probably be redesigned to
avoid this in a "deeper" way
This should be the final part of a fix for bug #7025, which means the id
property of PBD::Controllable is restored and a new id is not generated at
first save.
I'm assuming this was a typo, comparing with the wrong name meant the state of
the MuteControl was never being restored. This also fixes restoring bindings
associated MuteControl instances.
This [hopefully] fixes jack1 zombification on session-load with large
plugin-states. Previously it was possible to block
Route::process_output_buffers().
The trim processor was moved to the front after the internal return was,
so the trim setting was applied before the signal coming from other
tracks/busses sends was mixed in. Change the order so that trim applies
to audio from internal sends as well.
When flushing the buffers of Delivery processors owned by a Route/Track,
inner deliveries of PortInsert processors were missed since PortInsert
is not a Delivery subclass, but rather owns a Delivery as a private
member. Expose a flush_buffers() for PortInsert and call it too.
This is correct since (external) Send is a Delivery subclass, so that
just makes the send part of inserts behave as external sends do.
Route::no_roll(), Route::roll(), Track::no_roll(), AudioTrack::roll()
and MidiTrack::roll() all had the exact same loop for flushing buffers
of their Delivery processors. That was a lot of replicated code that had
to be kept synchronised by hand. Put that code into a protected method
Route::flush_processor_buffers_locked() which is called instead.
If a route has strict I/O then the main delivery follows the output of
the last processor, but libardour ensures it has at least as many
outputs as inputs in the master strip. A good consequence is that mono
tracks get their expected panner.
An akward side-effect is that MIDI-only routes (e.g. midi tracks or busses
without a synth) get two audio channels that have no use (and indeed no
panner is added because there is nothing to pan).
Skip the completion of audio outs if there was no audio out to begin
with.
Pass current (latency compensated) cycle times to plugin.
This fixes time-reporting to plugins and also fixes automation
and when bouncing (the session->transport* is not valid) etc.
Route now calls back into Session when solo/mute/listen state changes. All other interested
parties must use the Route::{solo,mute,...}_control()->Changed() to be notified of changes.
The Session requires more information than the Changed signal can provide, in order to
propagate solo/mute changes across the entire Session correctly.
Note that this uses an experimental use of CRTP to isolate a public API within Session