X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fslavable.cc;h=cb34630522926d0cbaa9d195954264f09749a968;hb=a1b4f9b8abf2887b17bce05403ea7eab2421f26a;hp=7a7b8e291947bc4c85d66b4293357414426f5de5;hpb=1e9b2abe730b89ff212ef61cee9e7112bf7c8f50;p=ardour.git diff --git a/libs/ardour/slavable.cc b/libs/ardour/slavable.cc index 7a7b8e2919..cb34630522 100644 --- a/libs/ardour/slavable.cc +++ b/libs/ardour/slavable.cc @@ -26,10 +26,11 @@ #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" +#include "pbd/i18n.h" using namespace PBD; using namespace ARDOUR; @@ -52,7 +53,7 @@ Slavable::get_state () const Glib::Threads::RWLock::ReaderLock lm (master_lock); for (std::set::const_iterator i = _masters.begin(); i != _masters.end(); ++i) { child = new XMLNode (X_("Master")); - child->add_property (X_("number"), to_string (*i, std::dec)); + child->set_property (X_("number"), *i); node->add_child_nocopy (*child); } @@ -71,9 +72,8 @@ Slavable::set_state (XMLNode const& node, int version) 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()); + uint32_t n; + if ((*i)->get_property (X_("number"), n)) { _masters.insert (n); } } @@ -82,6 +82,18 @@ Slavable::set_state (XMLNode const& node, int version) return 0; } + +/* Gain, solo & mute are currently the only controls that are + * automatically slaved to the master's own equivalent controls. + */ + +static AutomationType auto_slave_types[] = { + GainAutomation, + SoloAutomation, + MuteAutomation, + NullAutomation +}; + int Slavable::do_assign (VCAManager* manager) { @@ -102,8 +114,22 @@ Slavable::do_assign (VCAManager* manager) /* now that we've released the lock, we can do the assignments */ - for (std::vector >::iterator v = vcas.begin(); v != vcas.end(); ++v) { - assign (*v); + if (!vcas.empty()) { + + for (std::vector >::iterator v = vcas.begin(); v != vcas.end(); ++v) { + assign (*v, true); + } + + for (uint32_t n = 0; auto_slave_types[n] != NullAutomation; ++n) { + + boost::shared_ptr slave; + + slave = boost::dynamic_pointer_cast (automation_control (auto_slave_types[n])); + + if (slave) { + slave->use_saved_master_ratios (); + } + } } assign_connection.disconnect (); @@ -112,18 +138,94 @@ Slavable::do_assign (VCAManager* manager) } void -Slavable::assign (boost::shared_ptr v) +Slavable::assign (boost::shared_ptr v, bool loading) { - Glib::Threads::RWLock::WriterLock lm (master_lock); - if (assign_controls (v) == 0) { - _masters.insert (v->number()); + assert (v); + { + Glib::Threads::RWLock::WriterLock lm (master_lock); + if (assign_controls (v, loading) == 0) { + _masters.insert (v->number()); + } + + /* Do NOT use ::unassign() because it will store a + * boost::shared_ptr in the functor, leaving a dangling ref to the + * VCA. + */ + + + v->Drop.connect_same_thread (unassign_connections, boost::bind (&Slavable::weak_unassign, this, boost::weak_ptr(v))); + v->DropReferences.connect_same_thread (unassign_connections, boost::bind (&Slavable::weak_unassign, this, boost::weak_ptr(v))); + } + + AssignmentChange (v, true); +} + +void +Slavable::weak_unassign (boost::weak_ptr v) +{ + boost::shared_ptr sv (v.lock()); + if (sv) { + unassign (sv); } } void Slavable::unassign (boost::shared_ptr v) { - Glib::Threads::RWLock::WriterLock lm (master_lock); - (void) unassign_controls (v); - _masters.erase (v->number()); + { + Glib::Threads::RWLock::WriterLock lm (master_lock); + + (void) unassign_controls (v); + if (v) { + _masters.erase (v->number()); + } else { + _masters.clear (); + } + } + AssignmentChange (v, false); +} + +int +Slavable::assign_controls (boost::shared_ptr vca, bool loading) +{ + boost::shared_ptr slave; + boost::shared_ptr master; + + for (uint32_t n = 0; auto_slave_types[n] != NullAutomation; ++n) { + + slave = boost::dynamic_pointer_cast (automation_control (auto_slave_types[n])); + master = vca->automation_control (auto_slave_types[n]); + + if (slave && master) { + slave->add_master (master, loading); + } + } + + return 0; +} + +int +Slavable::unassign_controls (boost::shared_ptr vca) +{ + boost::shared_ptr slave; + boost::shared_ptr master; + + for (uint32_t n = 0; auto_slave_types[n] != NullAutomation; ++n) { + + slave = boost::dynamic_pointer_cast (automation_control (auto_slave_types[n])); + + if (!vca) { + /* unassign from all */ + if (slave) { + slave->clear_masters (); + } + } else { + master = vca->automation_control (auto_slave_types[n]); + if (slave && master) { + slave->remove_master (master); + } + } + } + + return 0; }