summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/gain_control.h15
-rw-r--r--libs/ardour/gain_control.cc80
-rw-r--r--libs/ardour/vca.cc9
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 &param, 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);
}