redesign control slave/master system, move code from GainControl to AutomationControl
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 9 Mar 2016 04:29:17 +0000 (23:29 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 May 2016 19:30:40 +0000 (15:30 -0400)
libs/ardour/ardour/automation_control.h
libs/ardour/ardour/gain_control.h
libs/ardour/automation_control.cc
libs/ardour/gain_control.cc
libs/ardour/route.cc

index 39fdb11397b8ffbd1c6d41689b0763929529b329..de476288f0f6d6f75608d0476fd9f6fc44edd14a 100644 (file)
 #ifndef __ardour_automation_control_h__
 #define __ardour_automation_control_h__
 
+#include <map>
+
+#include <glibmm/threads.h>
+
 #include <boost/shared_ptr.hpp>
 #include <boost/enable_shared_from_this.hpp>
 
 #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<AutomationControl>);
+       void remove_master (boost::shared_ptr<AutomationControl>);
+       void clear_masters ();
+       bool slaved_to (boost::shared_ptr<AutomationControl>) const;
+       bool slaved () const;
+       std::vector<PBD::ID> masters () const;
+
+       PBD::Signal0<void> MasterStatusChange;
+
+  protected:
        ARDOUR::Session& _session;
 
        const ParameterDescriptor _desc;
+
+
+       class MasterRecord {
+          public:
+               MasterRecord (boost::shared_ptr<AutomationControl> gc, double r)
+                       : _master (gc)
+                       , _ratio (r)
+               {}
+
+               boost::shared_ptr<AutomationControl> master() const { return _master; }
+               double ratio () const { return _ratio; }
+               void reset_ratio (double r) { _ratio = r; }
+
+               PBD::ScopedConnection connection;
+
+         private:
+               boost::shared_ptr<AutomationControl> _master;
+               double _ratio;
+
+       };
+
+       mutable Glib::Threads::RWLock master_lock;
+       typedef std::map<PBD::ID,MasterRecord> Masters;
+       Masters _masters;
+       PBD::ScopedConnectionList masters_connections;
+
+       void master_going_away (boost::weak_ptr<AutomationControl>);
+       virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
+       double get_value_locked() const;
 };
 
 
index e565dd33c93708d342cb18f0df62d4f32627b96a..4ec538e698192577371e7c27739f23cf188501ef 100644 (file)
 #define __ardour_gain_control_h__
 
 #include <string>
-#include <map>
 
 #include <boost/shared_ptr.hpp>
-#include <glibmm/threads.h>
 
 #include "pbd/controllable.h"
 
@@ -41,7 +39,6 @@ class LIBARDOUR_API GainControl : public AutomationControl {
        GainControl (Session& session, const Evoral::Parameter &param,
                     boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>());
 
-       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<VCA>);
-       void remove_master (boost::shared_ptr<VCA>);
-       void clear_masters ();
-       bool slaved_to (boost::shared_ptr<VCA>) const;
-       bool slaved () const;
-       std::vector<uint32_t> masters () const;
-
-       PBD::Signal0<void> VCAStatusChange;
-
        int set_state (XMLNode const&, int);
        XMLNode& get_state();
 
   private:
-       class MasterRecord {
-          public:
-               MasterRecord (boost::shared_ptr<AutomationControl> gc, double r)
-                       : _master (gc)
-                       , _ratio (r)
-               {}
-
-               boost::shared_ptr<AutomationControl> master() const { return _master; }
-               double ratio () const { return _ratio; }
-               void reset_ratio (double r) { _ratio = r; }
-
-               PBD::ScopedConnection connection;
-
-         private:
-               boost::shared_ptr<AutomationControl> _master;
-               double _ratio;
-
-       };
-
-       mutable Glib::Threads::RWLock master_lock;
-       typedef std::map<uint32_t,MasterRecord> 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<VCA>);
-       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);
 };
index 3629345d941e7a9efe06fc805df15080ea07a939..4317a187884d30b3a45edd3b0e66206861fde543 100644 (file)
@@ -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<AutomationControl> m)
+{
+       double current_value;
+       std::pair<Masters::iterator,bool> res;
+
+       {
+               Glib::Threads::RWLock::WriterLock lm (master_lock);
+               current_value = get_value_locked ();
+
+               /* ratio will be recomputed below */
+
+               res = _masters.insert (make_pair<PBD::ID,MasterRecord> (m->id(), MasterRecord (m, 1.0)));
+
+               if (res.second) {
+
+                       recompute_masters_ratios (current_value);
+
+                       /* note that we bind @param m as a weak_ptr<AutomationControl>, 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<void>::operator(), &Changed));
+               }
+       }
+
+       if (res.second) {
+               MasterStatusChange (); /* EMIT SIGNAL */
+       }
+}
+
+void
+AutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
+{
+       boost::shared_ptr<AutomationControl> m = wm.lock();
+       if (m) {
+               remove_master (m);
+       }
+}
+
+void
+AutomationControl::remove_master (boost::shared_ptr<AutomationControl> 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<AutomationControl> 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();
+}
+
index 3415f7c620d3415642263c1ffe5662b6a36f4034..456fd9b248d4e0bbea8553d7e3a5a357871e63df 100644 (file)
@@ -43,32 +43,6 @@ GainControl::GainControl (Session& session, const Evoral::Parameter &param, 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> vca)
-{
-       gain_t current_value;
-       std::pair<Masters::iterator,bool> res;
-
-       {
-               Glib::Threads::RWLock::WriterLock lm (master_lock);
-               current_value = get_value_locked ();
-
-               /* ratio will be recomputed below */
-
-               res = _masters.insert (make_pair<uint32_t,MasterRecord> (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<GainControl>, 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<void>::operator(), &Changed));
-               }
-       }
-
-       if (res.second) {
-               VCAStatusChange (); /* EMIT SIGNAL */
-       }
-}
-
-void
-GainControl::master_going_away (boost::weak_ptr<VCA> wv)
-{
-       boost::shared_ptr<VCA> v = wv.lock();
-       if (v) {
-               remove_master (v);
-       }
-}
-
-void
-GainControl::remove_master (boost::shared_ptr<VCA> 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> 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<string>::const_iterator m = masters.begin(); m != masters.end(); ++m) {
                boost::shared_ptr<VCA> vca = _session.vca_manager().vca_by_number (PBD::atoi (*m));
                if (vca) {
-                       add_master (vca);
+                       add_master (vca->gain_control());
                }
        }
 
index 5332a7003608ff020e6cb269e77d4edb5c8ed69e..641bc8ef8329afc0adc2fc103739319533c87ddd 100644 (file)
@@ -5892,13 +5892,13 @@ Route::slaved_to (boost::shared_ptr<VCA> 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> 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> 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());
        }