diff options
-rw-r--r-- | libs/ardour/ardour/gain_control.h | 15 | ||||
-rw-r--r-- | libs/ardour/gain_control.cc | 80 | ||||
-rw-r--r-- | libs/ardour/vca.cc | 9 |
3 files changed, 78 insertions, 26 deletions
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 <string> +#include <list> + #include <boost/shared_ptr.hpp> +#include <glibmm/threads.h> #include "pbd/controllable.h" @@ -51,12 +54,18 @@ class LIBARDOUR_API GainControl : public AutomationControl { double lower_db; double range_db; - boost::shared_ptr<GainControl> master() const { return _master; } - void set_master (boost::shared_ptr<GainControl>); + void add_master (boost::shared_ptr<GainControl>); + void remove_master (boost::shared_ptr<GainControl>); + void clear_masters (); private: void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override); - boost::shared_ptr<GainControl> _master; + gain_t get_master_gain () const; + + mutable Glib::Threads::Mutex master_lock; + + typedef std::list<boost::shared_ptr<GainControl> > 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,49 @@ GainControl::get_user_string () const return std::string(theBuf); } -void -GainControl::set_master (boost::shared_ptr<GainControl> 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<GainControl> 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.push_back (m); + new_master_val = get_master_gain (); + } - if (_master) { - new_master_val = _master->get_value(); - } else { - new_master_val = 1.0; + if (old_master_val != new_master_val) { + Changed(); /* EMIT SIGNAL */ + } +} + +void +GainControl::remove_master (boost::shared_ptr<GainControl> 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) { @@ -132,3 +163,20 @@ GainControl::set_master (boost::shared_ptr<GainControl> m) } } +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<Route> r) { - boost::dynamic_pointer_cast<GainControl>(r->gain_control())->set_master (_control); + boost::dynamic_pointer_cast<GainControl>(r->gain_control())->add_master (_control); } void VCA::remove (boost::shared_ptr<Route> r) { - boost::shared_ptr<GainControl> route_gain = boost::dynamic_pointer_cast<GainControl>(r->gain_control()); - boost::shared_ptr<GainControl> current_master = route_gain->master(); - - if (current_master == _control) { - route_gain->set_master (boost::shared_ptr<GainControl>()); - } + r->gain_control()->remove_master (_control); } |