rearrange inheritance so that Automatable IS-A Slavable
[ardour.git] / libs / ardour / slavable.cc
index 989c2ec6636e20a716d3e9e4b933b5998989b08b..4a759f5fef41a20abd567a74d314e731cf16ec3b 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/slavable_automation_control.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 +53,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 +61,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 +124,63 @@ 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());
 }
+
+int
+Slavable::assign_controls (boost::shared_ptr<VCA> vca)
+{
+       boost::shared_ptr<SlavableAutomationControl> slave;
+       boost::shared_ptr<AutomationControl> master;
+       AutomationType types[] = {
+               GainAutomation,
+               SoloAutomation,
+               MuteAutomation,
+               RecEnableAutomation,
+               MonitoringAutomation,
+               NullAutomation
+       };
+
+       for (uint32_t n = 0; types[n] != NullAutomation; ++n) {
+
+               slave = boost::dynamic_pointer_cast<SlavableAutomationControl> (automation_control (types[n]));
+               master = vca->automation_control (types[n]);
+
+               if (slave && master) {
+                       slave->add_master (master);
+               }
+       }
+
+       return 0;
+}
+
+int
+Slavable::unassign_controls (boost::shared_ptr<VCA> vca)
+{
+       boost::shared_ptr<SlavableAutomationControl> slave;
+       boost::shared_ptr<AutomationControl> master;
+       AutomationType types[] = {
+               GainAutomation,
+               SoloAutomation,
+               MuteAutomation,
+               RecEnableAutomation,
+               MonitoringAutomation,
+               NullAutomation
+       };
+
+       for (uint32_t n = 0; types[n] != NullAutomation; ++n) {
+
+               slave = boost::dynamic_pointer_cast<SlavableAutomationControl> (automation_control (types[n]));
+               if (!vca) {
+                       /* unassign from all */
+                       slave->clear_masters ();
+               } else {
+                       slave->remove_master (master);
+               }
+       }
+
+       return 0;
+}
+