From c660703f95a269a7f312e84564345f8961cb7e75 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 8 Mar 2016 23:29:17 -0500 Subject: redesign control slave/master system, move code from GainControl to AutomationControl --- libs/ardour/automation_control.cc | 129 +++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) (limited to 'libs/ardour/automation_control.cc') diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc index 3629345d94..4317a18788 100644 --- a/libs/ardour/automation_control.cc +++ b/libs/ardour/automation_control.cc @@ -56,6 +56,7 @@ AutomationControl::AutomationControl(ARDOUR::Session& s AutomationControl::~AutomationControl () { + DropReferences (); /* EMIT SIGNAL */ } bool @@ -73,9 +74,36 @@ double AutomationControl::get_value() const { bool from_list = _list && ((AutomationList*)_list.get())->automation_playback(); - return Control::get_double (from_list, _session.transport_frame()); + + if (!from_list) { + Glib::Threads::RWLock::ReaderLock lm (master_lock); + return get_value_locked (); + } else { + return Control::get_double (from_list, _session.transport_frame()); + } +} + +double +AutomationControl::get_value_locked() const +{ + /* read or write masters lock must be held */ + + if (_masters.empty()) { + return Control::get_double (false, _session.transport_frame()); + } + + gain_t v = 1.0; + + for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) { + /* get current master value, scale by our current ratio with that master */ + v *= mr->second.master()->get_value () * mr->second.ratio(); + } + + return min (_desc.upper, v); } + + /** Set the value and do the right thing based on automation state * (e.g. record if necessary, etc.) * @param value `user' value @@ -232,3 +260,102 @@ AutomationControl::interface_to_internal (double val) const } +void +AutomationControl::add_master (boost::shared_ptr m) +{ + double current_value; + std::pair res; + + { + Glib::Threads::RWLock::WriterLock lm (master_lock); + current_value = get_value_locked (); + + /* ratio will be recomputed below */ + + res = _masters.insert (make_pair (m->id(), MasterRecord (m, 1.0))); + + if (res.second) { + + recompute_masters_ratios (current_value); + + /* note that we bind @param m as a weak_ptr, thus + avoiding holding a reference to the control in the binding + itself. + */ + + m->DropReferences.connect_same_thread (masters_connections, boost::bind (&AutomationControl::master_going_away, this, m)); + + /* Store the connection inside the MasterRecord, so that when we destroy it, the connection is destroyed + and we no longer hear about changes to the AutomationControl. + */ + + m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&PBD::Signal0::operator(), &Changed)); + } + } + + if (res.second) { + MasterStatusChange (); /* EMIT SIGNAL */ + } +} + +void +AutomationControl::master_going_away (boost::weak_ptr wm) +{ + boost::shared_ptr m = wm.lock(); + if (m) { + remove_master (m); + } +} + +void +AutomationControl::remove_master (boost::shared_ptr m) +{ + double current_value; + Masters::size_type erased = 0; + + { + Glib::Threads::RWLock::WriterLock lm (master_lock); + current_value = get_value_locked (); + erased = _masters.erase (m->id()); + if (erased) { + recompute_masters_ratios (current_value); + } + } + + if (erased) { + MasterStatusChange (); /* EMIT SIGNAL */ + } +} + +void +AutomationControl::clear_masters () +{ + bool had_masters = false; + + { + Glib::Threads::RWLock::WriterLock lm (master_lock); + if (!_masters.empty()) { + had_masters = true; + } + _masters.clear (); + } + + if (had_masters) { + MasterStatusChange (); /* EMIT SIGNAL */ + } +} + +bool +AutomationControl::slaved_to (boost::shared_ptr m) const +{ + Glib::Threads::RWLock::ReaderLock lm (master_lock); + return _masters.find (m->id()) != _masters.end(); +} + +bool +AutomationControl::slaved () const +{ + Glib::Threads::RWLock::ReaderLock lm (master_lock); + return !_masters.empty(); +} + -- cgit v1.2.3