save and restore vca assignments
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 25 Apr 2016 15:03:08 +0000 (11:03 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 May 2016 19:30:41 +0000 (15:30 -0400)
libs/ardour/ardour/gain_control.h
libs/ardour/ardour/slavable.h
libs/ardour/ardour/vca_manager.h
libs/ardour/gain_control.cc
libs/ardour/route.cc
libs/ardour/session_state.cc
libs/ardour/slavable.cc
libs/ardour/vca.cc
libs/ardour/vca_manager.cc

index f7041fff7826f9d7b00ab8ea06c71d9b1c903699..f72320f1dd59ca47417dfcde3d53d6d816131862 100644 (file)
@@ -54,10 +54,6 @@ class LIBARDOUR_API GainControl : public SlavableAutomationControl {
        void inc_gain (gain_t);
 
   private:
-       std::string masters_string;
-       PBD::ScopedConnection vca_loaded_connection;
-
-       void vcas_loaded();
        void recompute_masters_ratios (double val);
 };
 
index ae53caef38b384ef7745194a0c8e71c5128fbc77..b0ef33e1b43a35ce1d6a49c67cbdbdf1bc62b36e 100644 (file)
 
 #include <boost/shared_ptr.hpp>
 
+#include <pbd/signals.h>
+
 class XMLNode;
 
 namespace ARDOUR {
 
 class VCA;
-class Session;
+class VCAManager;
 
 class Slavable
 {
@@ -39,14 +41,17 @@ class Slavable
        Slavable ();
        virtual ~Slavable() {}
 
-       XMLNode& state () const;
-       int assign (Session& s, XMLNode const&);
+       XMLNode& get_state () const;
+       int set_state (XMLNode const&, int);
 
        void assign (boost::shared_ptr<VCA>);
        void unassign (boost::shared_ptr<VCA>);
 
        static std::string xml_node_name;
 
+       /* signal sent VCAManager once assignment is possible */
+       static PBD::Signal1<void,VCAManager*> Assign;
+
     protected:
        virtual int assign_controls (boost::shared_ptr<VCA>) = 0;
        virtual int unassign_controls (boost::shared_ptr<VCA>) = 0;
@@ -54,6 +59,9 @@ class Slavable
     private:
        mutable Glib::Threads::RWLock master_lock;
        std::set<uint32_t> _masters;
+       PBD::ScopedConnection assign_connection;
+
+       int do_assign (VCAManager* s);
 };
 
 } // namespace ARDOUR
index d18044a8dfc9205602aeb07430919c4dd651aa90..5102d14698fd1a4643fbffb90b96cbf474cac71f 100644 (file)
@@ -50,7 +50,6 @@ class VCAManager : public SessionHandleRef, public PBD::StatefulDestructible
 
        VCAList vcas() const;
 
-       PBD::Signal0<void>          VCAsLoaded;
        PBD::Signal1<void,VCAList&> VCAAdded;
        PBD::Signal1<void,VCAList&> VCARemoved;
 
index 3ffeb057da8fc1d0cc26a128375b15998470a3f7..ef560085cc960137d0e997e76dfdab9b59856d55 100644 (file)
@@ -178,48 +178,6 @@ GainControl::get_state ()
 int
 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
-        * have to load all VCAs first, then set up slave/master relationships
-        * once we have them all.
-        */
-
-       if (prop) {
-               masters_string = prop->value ();
-
-               if (_session.vca_manager().vcas_loaded()) {
-                       vcas_loaded ();
-               } else {
-                       _session.vca_manager().VCAsLoaded.connect_same_thread (vca_loaded_connection, boost::bind (&GainControl::vcas_loaded, this));
-               }
-       }
-#endif
-
-       return 0;
-}
-
-void
-GainControl::vcas_loaded ()
-{
-       if (masters_string.empty()) {
-               return;
-       }
-
-       vector<string> masters;
-       split (masters_string, masters, ',');
-
-       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->gain_control());
-               }
-       }
-
-       vca_loaded_connection.disconnect ();
-       masters_string.clear ();
+       return AutomationControl::set_state (node, version);
 }
 
index 301c7ba5c0c05e538b096e040d69ef07e2aa87b7..3e424a9603a63e1a25a98784fea41a1994a816ff 100644 (file)
@@ -2447,6 +2447,8 @@ Route::state(bool full_state)
                foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), ""));
        }
 
+       node->add_child_copy (Slavable::get_state());
+
        return *node;
 }
 
@@ -2517,21 +2519,16 @@ Route::set_state (const XMLNode& node, int version)
                        } else if (prop->value() == "Output") {
                                _output->set_state (*child, version);
                        }
-               }
 
-               if (child->name() == X_("Processor")) {
+               } else if (child->name() == X_("Processor")) {
                        processor_state.add_child_copy (*child);
-               }
-
-               if (child->name() == X_("Pannable")) {
+               } else if (child->name() == X_("Pannable")) {
                        if (_pannable) {
                                _pannable->set_state (*child, version);
                        } else {
                                warning << string_compose (_("Pannable state found for route (%1) without a panner!"), name()) << endmsg;
                        }
-               }
-
-               if (child->name() == Controllable::xml_node_name) {
+               }  else if (child->name() == Controllable::xml_node_name) {
                        if ((prop = child->property (X_("name"))) == 0) {
                                continue;
                        }
@@ -2547,6 +2544,8 @@ Route::set_state (const XMLNode& node, int version)
                        } else if (prop->value() == _solo_control->name()) {
                                _mute_control->set_state (*child, version);
                        }
+               } else if (child->name() == Slavable::xml_node_name) {
+                       Slavable::set_state (*child, version);
                }
        }
 
index 4d5ffbffa74ae5d93080238092f1f633e566072c..ebbd37e4f9a71bc26702b04599a98bf4074fcd90 100644 (file)
@@ -1486,6 +1486,10 @@ Session::set_state (const XMLNode& node, int version)
                goto out;
        }
 
+       /* Now that we have Routes and masters loaded, connect them if appropriate */
+
+       Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
+
        /* our diskstreams list is no longer needed as they are now all owned by their Route */
        _diskstreams_2X.clear ();
 
index 989c2ec6636e20a716d3e9e4b933b5998989b08b..7a7b8e291947bc4c85d66b4293357414426f5de5 100644 (file)
 
 */
 
+#include <vector>
+
 #include <glibmm/threads.h>
 
 #include "pbd/convert.h"
+#include "pbd/error.h"
 #include "pbd/xml++.h"
 
 #include "ardour/slavable.h"
 #include "ardour/vca.h"
+#include "ardour/vca_manager.h"
 
 #include "i18n.h"
 
+using namespace PBD;
 using namespace ARDOUR;
 
 std::string Slavable::xml_node_name = X_("Slavable");
+PBD::Signal1<void,VCAManager*> Slavable::Assign; /* signal sent once
+                                                  * assignment is possible */
 
 Slavable::Slavable ()
 {
-
+       Assign.connect_same_thread (assign_connection, boost::bind (&Slavable::do_assign, this, _1));
 }
 
 XMLNode&
-Slavable::state () const
+Slavable::get_state () const
 {
        XMLNode* node = new XMLNode (xml_node_name);
        XMLNode* child;
@@ -45,7 +52,7 @@ Slavable::state () const
        Glib::Threads::RWLock::ReaderLock lm (master_lock);
        for (std::set<uint32_t>::const_iterator i = _masters.begin(); i != _masters.end(); ++i) {
                child = new XMLNode (X_("Master"));
-               child->add_property (X_("number"), PBD::to_string (*i, std::dec));
+               child->add_property (X_("number"), to_string (*i, std::dec));
                node->add_child_nocopy (*child);
        }
 
@@ -53,16 +60,62 @@ Slavable::state () const
 }
 
 int
-Slavable::assign (Session& s, XMLNode const& node)
+Slavable::set_state (XMLNode const& node, int version)
+{
+       if (node.name() != xml_node_name) {
+               return -1;
+       }
+
+       XMLNodeList const& children (node.children());
+       Glib::Threads::RWLock::WriterLock lm (master_lock);
+
+       for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+               if ((*i)->name() == X_("Master")) {
+                       XMLProperty const* prop = (*i)->property (X_("number"));
+                       if (prop) {
+                               uint32_t n = atoi (prop->value());
+                               _masters.insert (n);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int
+Slavable::do_assign (VCAManager* manager)
 {
+       std::vector<boost::shared_ptr<VCA> > vcas;
+
+       {
+               Glib::Threads::RWLock::ReaderLock lm (master_lock);
+
+               for (std::set<uint32_t>::const_iterator i = _masters.begin(); i != _masters.end(); ++i) {
+                       boost::shared_ptr<VCA> v = manager->vca_by_number (*i);
+                       if (v) {
+                               vcas.push_back (v);
+                       } else {
+                               warning << string_compose (_("Master #%1 not found, assignment lost"), *i) << endmsg;
+                       }
+               }
+       }
+
+       /* now that we've released the lock, we can do the assignments */
+
+       for (std::vector<boost::shared_ptr<VCA> >::iterator v = vcas.begin(); v != vcas.end(); ++v) {
+               assign (*v);
+       }
+
+       assign_connection.disconnect ();
+
        return 0;
 }
 
 void
 Slavable::assign (boost::shared_ptr<VCA> v)
 {
+       Glib::Threads::RWLock::WriterLock lm (master_lock);
        if (assign_controls (v) == 0) {
-               Glib::Threads::RWLock::WriterLock lm (master_lock);
                _masters.insert (v->number());
        }
 }
@@ -70,7 +123,7 @@ Slavable::assign (boost::shared_ptr<VCA> v)
 void
 Slavable::unassign (boost::shared_ptr<VCA> v)
 {
-       (void) unassign_controls (v);
        Glib::Threads::RWLock::WriterLock lm (master_lock);
+       (void) unassign_controls (v);
        _masters.erase (v->number());
 }
index 2ab84d55705bb1410afdf24689c9b49292c2ef23..72c0a2cdcb71719e949ed019ca5af0bc6f15e193 100644 (file)
@@ -106,6 +106,8 @@ VCA::get_state ()
        node->add_child_nocopy (_mute_control->get_state());
        node->add_child_nocopy (get_automation_xml_state());
 
+       node->add_child_nocopy (Slavable::get_state());
+
        return *node;
 }
 
@@ -141,6 +143,8 @@ VCA::set_state (XMLNode const& node, int version)
                        if (prop->value() == _mute_control->name()) {
                                _mute_control->set_state (**i, version);
                        }
+               } else if ((*i)->name() == Slavable::xml_node_name) {
+                       Slavable::set_state (**i, version);
                }
        }
 
index e0d7e0fc824d08ebec4fa698962ea65da711524c..e6143ea0b2c1eb3e30967a44993b845ef6b6a315 100644 (file)
@@ -21,6 +21,7 @@
 #include "pbd/error.h"
 #include "pbd/replace_all.h"
 
+#include "ardour/slavable.h"
 #include "ardour/vca.h"
 #include "ardour/vca_manager.h"
 
@@ -175,7 +176,6 @@ VCAManager::set_state (XMLNode const& node, int version)
 
        _vcas_loaded = true;
 
-       VCAsLoaded (); /* EMIT SIGNAL */
        VCAAdded (vcal); /* EMIT SIGNAL */
 
        return 0;