Consistent Automation evaluation:

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.
This commit is contained in:
Robin Gareus 2017-07-15 20:45:49 +02:00
parent 06ca52d5a5
commit dee990103a
8 changed files with 55 additions and 7 deletions

View File

@ -90,6 +90,9 @@ Amp::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
gain_t* gab = _gain_automation_buffer;
assert (gab);
/* see note in PluginInsert::connect_and_run -- emit Changed signal */
_gain_control->set_value_unchecked (gab[0]);
if (_midi_amp) {
for (BufferSet::midi_iterator i = bufs.midi_begin(); i != bufs.midi_end(); ++i) {
MidiBuffer& mb (*i);
@ -130,6 +133,12 @@ Amp::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
_current_gain = Amp::apply_gain (bufs, _session.nominal_frame_rate(), nframes, _current_gain, dg, _midi_amp);
/* see note in PluginInsert::connect_and_run ()
* set_value_unchecked() won't emit a signal since the value is effectively unchanged
*/
_gain_control->Changed (false, PBD::Controllable::NoGroup);
} else if (_current_gain != GAIN_COEFF_UNITY) {
/* gain has not changed, but its non-unity */

View File

@ -50,7 +50,7 @@ public:
Automatable(Session&);
Automatable (const Automatable& other);
virtual ~Automatable();
virtual ~Automatable();
boost::shared_ptr<Evoral::Control> control_factory(const Evoral::Parameter& id);
@ -83,9 +83,11 @@ public:
virtual bool find_next_event (double start, double end, Evoral::ControlEvent& ev, bool only_active = true) const;
void clear_controls ();
virtual void transport_located (framepos_t now);
virtual void transport_located (framepos_t now);
virtual void transport_stopped (framepos_t now);
virtual void automation_run (framepos_t, pframes_t);
virtual std::string describe_parameter(Evoral::Parameter param);
AutoState get_parameter_automation_state (Evoral::Parameter param);
@ -103,7 +105,7 @@ public:
PBD::Signal0<void> AutomationStateChanged;
protected:
protected:
Session& _a_session;
void can_automate(Evoral::Parameter);

View File

@ -77,7 +77,7 @@ class LIBARDOUR_API Processor : public SessionObject, public Automatable, public
* if false, the method need not bother writing to @a bufs if it doesn't want to.
*/
virtual void run (BufferSet& /*bufs*/, framepos_t /*start_frame*/, framepos_t /*end_frame*/, double speed, pframes_t /*nframes*/, bool /*result_required*/) {}
virtual void silence (framecnt_t /*nframes*/, framepos_t /*start_frame*/) {}
virtual void silence (framecnt_t nframes, framepos_t start_frame) { automation_run (start_frame, nframes); }
virtual void activate () { _pending_active = true; ActiveChanged(); }
virtual void deactivate () { _pending_active = false; ActiveChanged(); }

View File

@ -345,7 +345,7 @@ Automatable::transport_located (framepos_t now)
boost::shared_ptr<AutomationControl> c
= boost::dynamic_pointer_cast<AutomationControl>(li->second);
if (c) {
boost::shared_ptr<AutomationList> l
boost::shared_ptr<AutomationList> l
= boost::dynamic_pointer_cast<AutomationList>(c->list());
if (l) {
@ -395,6 +395,19 @@ Automatable::transport_stopped (framepos_t now)
}
}
void
Automatable::automation_run (framepos_t start, pframes_t nframes)
{
for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
boost::shared_ptr<AutomationControl> c =
boost::dynamic_pointer_cast<AutomationControl>(li->second);
if (!c) {
continue;
}
c->automation_run (start, nframes);
}
}
boost::shared_ptr<Evoral::Control>
Automatable::control_factory(const Evoral::Parameter& param)
{

View File

@ -260,6 +260,7 @@ AutomationControl::set_automation_state (AutoState as)
}
} else {
AutomationWatch::instance().remove_automation_watch (shared_from_this());
Changed (false, Controllable::NoGroup);
}
}
}

View File

@ -1170,6 +1170,7 @@ PluginInsert::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame
} else {
bypass (bufs, nframes);
automation_run (start_frame, nframes);
_delaybuffers.flush ();
}

View File

@ -322,7 +322,7 @@ Route::process_output_buffers (BufferSet& bufs,
return;
}
_mute_control->automation_run (start_frame, nframes);
automation_run (start_frame, nframes);
/* figure out if we're going to use gain automation */
if (gain_automation_ok) {
@ -2980,11 +2980,16 @@ Route::silence_unlocked (framecnt_t nframes)
_output->silence (nframes);
// update owned automated controllables
automation_run (now, nframes);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<PluginInsert> pi;
if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) {
// skip plugins, they don't need anything when we're not active
/* evaluate automated automation controls */
pi->automation_run (now, nframes);
/* skip plugins, they don't need anything when we're not active */
continue;
}

View File

@ -40,6 +40,8 @@
#include "ardour/slave.h"
#include "ardour/ticker.h"
#include "ardour/types.h"
#include "ardour/vca.h"
#include "ardour/vca_manager.h"
#include "midi++/mmc.h"
@ -142,6 +144,11 @@ Session::no_roll (pframes_t nframes)
ltc_tx_send_time_code_for_cycle (_transport_frame, end_frame, _target_transport_speed, _transport_speed, nframes);
VCAList v = _vca_manager->vcas ();
for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
(*i)->automation_run (_transport_frame, nframes);
}
if (_process_graph) {
DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/no-roll\n");
_process_graph->routes_no_roll( nframes, _transport_frame, end_frame, non_realtime_work_pending(), declick);
@ -180,6 +187,11 @@ Session::process_routes (pframes_t nframes, bool& need_butler)
const framepos_t start_frame = _transport_frame;
const framepos_t end_frame = _transport_frame + floor (nframes * _transport_speed);
VCAList v = _vca_manager->vcas ();
for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
(*i)->automation_run (start_frame, nframes);
}
if (_process_graph) {
DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/process-routes\n");
if (_process_graph->process_routes (nframes, start_frame, end_frame, declick, need_butler) < 0) {
@ -225,6 +237,11 @@ Session::silent_process_routes (pframes_t nframes, bool& need_butler)
const framepos_t start_frame = _transport_frame;
const framepos_t end_frame = _transport_frame + lrintf(nframes * _transport_speed);
VCAList v = _vca_manager->vcas ();
for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
(*i)->automation_run (start_frame, nframes);
}
if (_process_graph) {
_process_graph->silent_process_routes (nframes, start_frame, end_frame, need_butler);
} else {