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/ardour/automation_control.h | 46 ++++++++- libs/ardour/ardour/gain_control.h | 41 +------- libs/ardour/automation_control.cc | 129 ++++++++++++++++++++++++- libs/ardour/gain_control.cc | 162 ++------------------------------ libs/ardour/route.cc | 6 +- 5 files changed, 186 insertions(+), 198 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h index 39fdb11397..de476288f0 100644 --- a/libs/ardour/ardour/automation_control.h +++ b/libs/ardour/ardour/automation_control.h @@ -21,10 +21,16 @@ #ifndef __ardour_automation_control_h__ #define __ardour_automation_control_h__ +#include + +#include + #include #include #include "pbd/controllable.h" + +#include "evoral/types.hpp" #include "evoral/Control.hpp" #include "ardour/libardour_visibility.h" @@ -111,10 +117,48 @@ public: const ARDOUR::Session& session() const { return _session; } void commit_transaction (bool did_write); -protected: + void add_master (boost::shared_ptr); + void remove_master (boost::shared_ptr); + void clear_masters (); + bool slaved_to (boost::shared_ptr) const; + bool slaved () const; + std::vector masters () const; + + PBD::Signal0 MasterStatusChange; + + protected: ARDOUR::Session& _session; const ParameterDescriptor _desc; + + + class MasterRecord { + public: + MasterRecord (boost::shared_ptr gc, double r) + : _master (gc) + , _ratio (r) + {} + + boost::shared_ptr master() const { return _master; } + double ratio () const { return _ratio; } + void reset_ratio (double r) { _ratio = r; } + + PBD::ScopedConnection connection; + + private: + boost::shared_ptr _master; + double _ratio; + + }; + + mutable Glib::Threads::RWLock master_lock; + typedef std::map Masters; + Masters _masters; + PBD::ScopedConnectionList masters_connections; + + void master_going_away (boost::weak_ptr); + virtual void recompute_masters_ratios (double val) { /* do nothing by default */} + double get_value_locked() const; }; diff --git a/libs/ardour/ardour/gain_control.h b/libs/ardour/ardour/gain_control.h index e565dd33c9..4ec538e698 100644 --- a/libs/ardour/ardour/gain_control.h +++ b/libs/ardour/ardour/gain_control.h @@ -20,10 +20,8 @@ #define __ardour_gain_control_h__ #include -#include #include -#include #include "pbd/controllable.h" @@ -41,7 +39,6 @@ class LIBARDOUR_API GainControl : public AutomationControl { GainControl (Session& session, const Evoral::Parameter ¶m, boost::shared_ptr al = boost::shared_ptr()); - double get_value () const; void set_value (double val, PBD::Controllable::GroupControlDisposition group_override); void set_value_unchecked (double); @@ -54,51 +51,15 @@ class LIBARDOUR_API GainControl : public AutomationControl { double lower_db; double range_db; - gain_t get_master_gain () const; - void add_master (boost::shared_ptr); - void remove_master (boost::shared_ptr); - void clear_masters (); - bool slaved_to (boost::shared_ptr) const; - bool slaved () const; - std::vector masters () const; - - PBD::Signal0 VCAStatusChange; - int set_state (XMLNode const&, int); XMLNode& get_state(); private: - class MasterRecord { - public: - MasterRecord (boost::shared_ptr gc, double r) - : _master (gc) - , _ratio (r) - {} - - boost::shared_ptr master() const { return _master; } - double ratio () const { return _ratio; } - void reset_ratio (double r) { _ratio = r; } - - PBD::ScopedConnection connection; - - private: - boost::shared_ptr _master; - double _ratio; - - }; - - mutable Glib::Threads::RWLock master_lock; - typedef std::map Masters; - Masters _masters; - PBD::ScopedConnectionList masters_connections; std::string masters_string; PBD::ScopedConnection vca_loaded_connection; - gain_t get_value_locked () const; - gain_t get_master_gain_locked () const; - void master_going_away (boost::weak_ptr); - void recompute_masters_ratios (double val); void vcas_loaded(); + void recompute_masters_ratios (double val); void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override); }; 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(); +} + diff --git a/libs/ardour/gain_control.cc b/libs/ardour/gain_control.cc index 3415f7c620..456fd9b248 100644 --- a/libs/ardour/gain_control.cc +++ b/libs/ardour/gain_control.cc @@ -43,32 +43,6 @@ GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boos range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db; } -gain_t -GainControl::get_value_locked () const { - - /* read or write masters lock must be held */ - - if (_masters.empty()) { - return AutomationControl::get_value(); - } - - gain_t g = 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 */ - g *= mr->second.master()->get_value () * mr->second.ratio(); - } - - return min (Config->get_max_gain(), g); -} - -double -GainControl::get_value () const -{ - Glib::Threads::RWLock::ReaderLock lm (master_lock); - return get_value_locked (); -} - void GainControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override) { @@ -97,6 +71,10 @@ GainControl::_set_value (double val, Controllable::GroupControlDisposition group } } + /* this sets the Evoral::Control::_user_value for us, which will + be retrieved by AutomationControl::get_value () + */ + AutomationControl::set_value (val, group_override); _session.set_dirty (); @@ -141,118 +119,6 @@ GainControl::get_user_string () const return std::string(theBuf); } -gain_t -GainControl::get_master_gain () const -{ - Glib::Threads::RWLock::ReaderLock sm (master_lock, Glib::Threads::TRY_LOCK); - - if (sm.locked()) { - return get_master_gain_locked (); - } - - return 1.0; -} - -gain_t -GainControl::get_master_gain_locked () const -{ - /* Master lock MUST be held (read or write lock is acceptable) */ - - gain_t g = 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 */ - g *= mr->second.master()->get_value () * mr->second.ratio(); - } - - return g; -} - -void -GainControl::add_master (boost::shared_ptr vca) -{ - gain_t 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 (vca->number(), MasterRecord (vca->gain_control(), 0.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. - */ - - vca->DropReferences.connect_same_thread (masters_connections, boost::bind (&GainControl::master_going_away, this, vca)); - - /* 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 VCA. - */ - - vca->gain_control()->Changed.connect_same_thread (res.first->second.connection, boost::bind (&PBD::Signal0::operator(), &Changed)); - } - } - - if (res.second) { - VCAStatusChange (); /* EMIT SIGNAL */ - } -} - -void -GainControl::master_going_away (boost::weak_ptr wv) -{ - boost::shared_ptr v = wv.lock(); - if (v) { - remove_master (v); - } -} - -void -GainControl::remove_master (boost::shared_ptr vca) -{ - gain_t current_value; - Masters::size_type erased = 0; - - { - Glib::Threads::RWLock::WriterLock lm (master_lock); - current_value = get_value_locked (); - erased = _masters.erase (vca->number()); - if (erased) { - recompute_masters_ratios (current_value); - } - } - - if (erased) { - VCAStatusChange (); /* EMIT SIGNAL */ - } -} - -void -GainControl::clear_masters () -{ - bool had_masters = false; - - { - Glib::Threads::RWLock::WriterLock lm (master_lock); - if (!_masters.empty()) { - had_masters = true; - } - _masters.clear (); - } - - if (had_masters) { - VCAStatusChange (); /* EMIT SIGNAL */ - } -} - void GainControl::recompute_masters_ratios (double val) { @@ -301,25 +167,12 @@ GainControl::recompute_masters_ratios (double val) } } -bool -GainControl::slaved_to (boost::shared_ptr vca) const -{ - Glib::Threads::RWLock::ReaderLock lm (master_lock); - return _masters.find (vca->number()) != _masters.end(); -} - -bool -GainControl::slaved () const -{ - Glib::Threads::RWLock::ReaderLock lm (master_lock); - return !_masters.empty(); -} - XMLNode& GainControl::get_state () { XMLNode& node (AutomationControl::get_state()); +#if 0 /* store VCA master IDs */ string str; @@ -337,6 +190,7 @@ GainControl::get_state () if (!str.empty()) { node.add_property (X_("masters"), str); } +#endif return node; } @@ -346,6 +200,7 @@ GainControl::set_state (XMLNode const& node, int version) { AutomationControl::set_state (node, version); +#if 0 XMLProperty const* prop = node.property (X_("masters")); /* Problem here if we allow VCA's to be slaved to other VCA's .. we @@ -362,6 +217,7 @@ GainControl::set_state (XMLNode const& node, int version) _session.vca_manager().VCAsLoaded.connect_same_thread (vca_loaded_connection, boost::bind (&GainControl::vcas_loaded, this)); } } +#endif return 0; } @@ -379,7 +235,7 @@ GainControl::vcas_loaded () for (vector::const_iterator m = masters.begin(); m != masters.end(); ++m) { boost::shared_ptr vca = _session.vca_manager().vca_by_number (PBD::atoi (*m)); if (vca) { - add_master (vca); + add_master (vca->gain_control()); } } diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 5332a70036..641bc8ef83 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -5892,13 +5892,13 @@ Route::slaved_to (boost::shared_ptr vca) const return false; } - return _gain_control->slaved_to (vca); + return _gain_control->slaved_to (vca->gain_control()); } void Route::vca_assign (boost::shared_ptr vca) { - _gain_control->add_master (vca); + _gain_control->add_master (vca->gain_control()); vca->add_solo_target (shared_from_this()); vca->add_mute_target (shared_from_this()); } @@ -5911,7 +5911,7 @@ Route::vca_unassign (boost::shared_ptr vca) _gain_control->clear_masters (); /* XXXX need to remove from solo/mute target lists */ } else { - _gain_control->remove_master (vca); + _gain_control->remove_master (vca->gain_control()); vca->remove_solo_target (shared_from_this()); vca->remove_mute_target (shared_from_this()); } -- cgit v1.2.3