diff --git a/libs/ardour/ardour/gain_control.h b/libs/ardour/ardour/gain_control.h index fa43b5d39f..9a79a8046f 100644 --- a/libs/ardour/ardour/gain_control.h +++ b/libs/ardour/ardour/gain_control.h @@ -20,7 +20,10 @@ #define __ardour_gain_control_h__ #include +#include + #include +#include #include "pbd/controllable.h" @@ -51,12 +54,18 @@ class LIBARDOUR_API GainControl : public AutomationControl { double lower_db; double range_db; - boost::shared_ptr master() const { return _master; } - void set_master (boost::shared_ptr); + void add_master (boost::shared_ptr); + void remove_master (boost::shared_ptr); + void clear_masters (); private: void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override); - boost::shared_ptr _master; + gain_t get_master_gain () const; + + mutable Glib::Threads::Mutex master_lock; + + typedef std::list > Masters; + Masters _masters; }; } /* namespace */ diff --git a/libs/ardour/gain_control.cc b/libs/ardour/gain_control.cc index 5af0e2d397..3021151bdc 100644 --- a/libs/ardour/gain_control.cc +++ b/libs/ardour/gain_control.cc @@ -39,10 +39,17 @@ GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boos double GainControl::get_value() const { - if (!_master) { - return AutomationControl::get_value(); + Glib::Threads::Mutex::Lock sm (master_lock, Glib::Threads::TRY_LOCK); + + if (sm.locked()) { + if (_masters.empty()) { + return AutomationControl::get_value(); + } + return AutomationControl::get_value() * get_master_gain (); + } else { + /* could not take lock */ + return AutomationControl::get_value (); } - return AutomationControl::get_value() * _master->get_value(); } void @@ -106,25 +113,31 @@ GainControl::get_user_string () const return std::string(theBuf); } -void -GainControl::set_master (boost::shared_ptr m) +gain_t +GainControl::get_master_gain () const { - double old_master_val; + /* Master lock MUST be held */ - if (_master) { - old_master_val = _master->get_value(); - } else { - old_master_val = 1.0; + gain_t g = 1.0; + + for (Masters::const_iterator m = _masters.begin(); m != _masters.end(); ++m) { + g *= (*m)->get_value (); } - _master = m; + return g; +} - double new_master_val; +void +GainControl::add_master (boost::shared_ptr m) +{ + gain_t old_master_val; + gain_t new_master_val; - if (_master) { - new_master_val = _master->get_value(); - } else { - new_master_val = 1.0; + { + Glib::Threads::Mutex::Lock lm (master_lock); + old_master_val = get_master_gain (); + _masters.push_back (m); + new_master_val = get_master_gain (); } if (old_master_val != new_master_val) { @@ -132,3 +145,38 @@ GainControl::set_master (boost::shared_ptr m) } } +void +GainControl::remove_master (boost::shared_ptr m) +{ + gain_t old_master_val; + gain_t new_master_val; + + { + Glib::Threads::Mutex::Lock lm (master_lock); + old_master_val = get_master_gain (); + _masters.remove (m); + new_master_val = get_master_gain (); + } + + if (old_master_val != new_master_val) { + Changed(); /* EMIT SIGNAL */ + } +} + +void +GainControl::clear_masters () +{ + gain_t old_master_val; + gain_t new_master_val; + + { + Glib::Threads::Mutex::Lock lm (master_lock); + old_master_val = get_master_gain (); + _masters.clear (); + new_master_val = get_master_gain (); + } + + if (old_master_val != new_master_val) { + Changed(); /* EMIT SIGNAL */ + } +} diff --git a/libs/ardour/vca.cc b/libs/ardour/vca.cc index 2ba8b8c7c4..b49489dfe7 100644 --- a/libs/ardour/vca.cc +++ b/libs/ardour/vca.cc @@ -47,16 +47,11 @@ VCA::get_value() const void VCA::add (boost::shared_ptr r) { - boost::dynamic_pointer_cast(r->gain_control())->set_master (_control); + boost::dynamic_pointer_cast(r->gain_control())->add_master (_control); } void VCA::remove (boost::shared_ptr r) { - boost::shared_ptr route_gain = boost::dynamic_pointer_cast(r->gain_control()); - boost::shared_ptr current_master = route_gain->master(); - - if (current_master == _control) { - route_gain->set_master (boost::shared_ptr()); - } + r->gain_control()->remove_master (_control); }