change VCA model to facilitate Harrison *and* SSL designs
authorPaul Davis <paul@linuxaudiosystems.com>
Sun, 28 Feb 2016 16:57:18 +0000 (11:57 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 May 2016 19:30:38 +0000 (15:30 -0400)
libs/ardour/ardour/gain_control.h
libs/ardour/gain_control.cc
libs/ardour/vca.cc

index fa43b5d39f5faee24516b309a84640918669972a..9a79a8046f50053affd575e39e99cc1b28f37f8b 100644 (file)
 #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 */
index 5af0e2d397cf13d0d86d81dd17f82bbb23e7a7cb..3021151bdc6491b4f51472fa8a2801b5350eb4a0 100644 (file)
@@ -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 */
+       }
+}
index 2ba8b8c7c43332566c8a5acd35907856ac060420..b49489dfe7ded9f97ddda8caa2834470d90c3c34 100644 (file)
@@ -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);
 }