save/restore VCA master state inside slaves, so that a reloaded session ends up back...
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 6 Feb 2017 15:18:09 +0000 (16:18 +0100)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 6 Feb 2017 15:49:08 +0000 (16:49 +0100)
gtk2_ardour/control_slave_ui.cc
gtk2_ardour/group_tabs.cc
gtk2_ardour/mixer_strip.cc
libs/ardour/ardour/gain_control.h
libs/ardour/ardour/slavable.h
libs/ardour/ardour/slavable_automation_control.h
libs/ardour/gain_control.cc
libs/ardour/route_group.cc
libs/ardour/slavable.cc
libs/ardour/slavable_automation_control.cc

index ef1b0a2f6e78ae9de7052b066702c238e150c8ee..9ea6136e5f29fe36cf263af977742d58d53d7307 100644 (file)
@@ -128,7 +128,7 @@ ControlSlaveUI::vca_menu_toggle (Gtk::CheckMenuItem* menuitem, uint32_t n)
        if (!menuitem->get_active()) {
                sl->unassign (vca);
        } else {
-               sl->assign (vca);
+               sl->assign (vca, false);
        }
 }
 
index 94e7c8cfea23eb566d12dba134d40beb2f86013e..9d10a442d43a3523b1f486edc6acab84a8c75563 100644 (file)
@@ -500,7 +500,7 @@ GroupTabs::assign_some_to_master (uint32_t which, RouteList rl)
        }
 
        for (RouteList::iterator r = rl.begin(); r != rl.end(); ++r) {
-               (*r)->assign (master);
+               (*r)->assign (master, false);
        }
 }
 
index 1a82d7025b8ab536da2bd56c5cc4896e95db3bd0..e233a1674873141bd953b1141e76841c07535c14 100644 (file)
@@ -431,7 +431,7 @@ MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
 {
        boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
        if (sl)
-               sl->assign(vca);
+               sl->assign(vca, false);
 }
 
 void
index f72320f1dd59ca47417dfcde3d53d6d816131862..53f429b88ae44c03411778e35072388ed3cc0fca 100644 (file)
@@ -48,9 +48,6 @@ class LIBARDOUR_API GainControl : public SlavableAutomationControl {
        double lower_db;
        double range_db;
 
-       int set_state (XMLNode const&, int);
-       XMLNode& get_state();
-
        void inc_gain (gain_t);
 
   private:
index 5af954d51ce7ee62ef56702b58ccf22dce8cb179..15d3e41991b21405f273fffb366aec5b7af6c015 100644 (file)
@@ -49,7 +49,7 @@ class LIBARDOUR_API Slavable
        XMLNode& get_state () const;
        int set_state (XMLNode const&, int);
 
-       void assign (boost::shared_ptr<VCA>);
+       void assign (boost::shared_ptr<VCA>, bool loading);
        void unassign (boost::shared_ptr<VCA>);
 
        PBD::Signal2<void,boost::shared_ptr<VCA>,bool> AssignmentChange;
@@ -62,7 +62,7 @@ class LIBARDOUR_API Slavable
        static PBD::Signal1<void,VCAManager*> Assign;
 
     protected:
-       virtual int assign_controls (boost::shared_ptr<VCA>);
+       virtual int assign_controls (boost::shared_ptr<VCA>, bool loading);
        virtual int unassign_controls (boost::shared_ptr<VCA>);
 
     private:
index 7e46dd5a74e7995abee60518a399ec09d59497ea..857a8956e12d5451c09e6f75f28b4ab5fbdc604f 100644 (file)
@@ -36,9 +36,11 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl
                                  PBD::Controllable::Flag                   flags=PBD::Controllable::Flag (0)
                );
 
+       ~SlavableAutomationControl ();
+
        double get_value () const;
 
-       void add_master (boost::shared_ptr<AutomationControl>);
+       void add_master (boost::shared_ptr<AutomationControl>, bool loading);
        void remove_master (boost::shared_ptr<AutomationControl>);
        void clear_masters ();
        bool slaved_to (boost::shared_ptr<AutomationControl>) const;
@@ -57,6 +59,11 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl
 
        PBD::Signal0<void> MasterStatusChange;
 
+       void use_saved_master_ratios ();
+
+       int set_state (XMLNode const&, int);
+       XMLNode& get_state();
+
     protected:
 
        class MasterRecord {
@@ -111,7 +118,7 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl
        virtual void   pre_remove_master (boost::shared_ptr<AutomationControl>) {}
        virtual void   post_add_master (boost::shared_ptr<AutomationControl>) {}
 
-
+       XMLNode* _masters_node; /* used to store master ratios in ::set_state() for later use */
 };
 
 } // namespace ARDOUR
index d100273640087e372f75dde70bf7b39bfba3c79e..21e1ba5f85c77e100c39f0f45b9b11fb2e183637 100644 (file)
@@ -133,7 +133,6 @@ GainControl::recompute_masters_ratios (double val)
           Mr(n) is the new ratio number for the slaves
        */
 
-
        const double nmasters = _masters.size();
        double masters_total_gain_coefficient = 1.0;
 
@@ -148,37 +147,3 @@ GainControl::recompute_masters_ratios (double val)
        }
 }
 
-XMLNode&
-GainControl::get_state ()
-{
-       XMLNode& node (AutomationControl::get_state());
-
-#if 0
-       /* store VCA master IDs */
-
-       string str;
-
-       {
-               Glib::Threads::RWLock::ReaderLock lm (master_lock);
-               for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
-                       if (!str.empty()) {
-                               str += ',';
-                       }
-                       str += PBD::to_string (mr->first, std::dec);
-               }
-       }
-
-       if (!str.empty()) {
-               node.add_property (X_("masters"), str);
-       }
-#endif
-
-       return node;
-}
-
-int
-GainControl::set_state (XMLNode const& node, int version)
-{
-       return AutomationControl::set_state (node, version);
-}
-
index 1a7b98050cfe8fb961bb747ecee01a3d641a5599..519c88c84ff0b40b17fed7774fdc2ca75d297471 100644 (file)
@@ -180,7 +180,7 @@ RouteGroup::add (boost::shared_ptr<Route> r)
        boost::shared_ptr<VCA> vca (group_master.lock());
 
        if (vca) {
-               r->assign  (vca);
+               r->assign  (vca, false);
        }
 
        _session.set_dirty ();
@@ -623,7 +623,7 @@ RouteGroup::assign_master (boost::shared_ptr<VCA> master)
        }
 
        for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) {
-               (*r)->assign (master);
+               (*r)->assign (master, false);
        }
 
        group_master = master;
index 61a11f257d7e3494bfb02fb705d63331f5624fc3..35063fa35f7927661a93717192107aa5d742536b 100644 (file)
@@ -84,6 +84,17 @@ Slavable::set_state (XMLNode const& node, int version)
 }
 
 
+/* 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)
 {
@@ -104,8 +115,22 @@ Slavable::do_assign (VCAManager* manager)
 
        /* 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);
+       if (!vcas.empty()) {
+
+               for (std::vector<boost::shared_ptr<VCA> >::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<SlavableAutomationControl> slave;
+
+                       slave = boost::dynamic_pointer_cast<SlavableAutomationControl> (automation_control (auto_slave_types[n]));
+
+                       if (slave) {
+                               slave->use_saved_master_ratios ();
+                       }
+               }
        }
 
        assign_connection.disconnect ();
@@ -114,12 +139,12 @@ Slavable::do_assign (VCAManager* manager)
 }
 
 void
-Slavable::assign (boost::shared_ptr<VCA> v)
+Slavable::assign (boost::shared_ptr<VCA> v, bool loading)
 {
        assert (v);
        {
                Glib::Threads::RWLock::WriterLock lm (master_lock);
-               if (assign_controls (v) == 0) {
+               if (assign_controls (v, loading) == 0) {
                        _masters.insert (v->number());
                }
 
@@ -161,19 +186,8 @@ Slavable::unassign (boost::shared_ptr<VCA> v)
        AssignmentChange (v, false);
 }
 
-/* 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::assign_controls (boost::shared_ptr<VCA> vca)
+Slavable::assign_controls (boost::shared_ptr<VCA> vca, bool loading)
 {
        boost::shared_ptr<SlavableAutomationControl> slave;
        boost::shared_ptr<AutomationControl> master;
@@ -184,7 +198,7 @@ Slavable::assign_controls (boost::shared_ptr<VCA> vca)
                master = vca->automation_control (auto_slave_types[n]);
 
                if (slave && master) {
-                       slave->add_master (master);
+                       slave->add_master (master, loading);
                }
        }
 
index 31e81a293129481c9f033f1abbd797d1556de193..b76f91b13bb967d5bd11848e914a2e812662b0e3 100644 (file)
@@ -20,6 +20,8 @@
 #define __libardour_slavable_automation_control_h__
 
 #include "pbd/enumwriter.h"
+#include "pbd/error.h"
+#include "pbd/i18n.h"
 
 #include "ardour/slavable_automation_control.h"
 #include "ardour/session.h"
@@ -35,9 +37,18 @@ SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
                                                      const std::string&                        name,
                                                      Controllable::Flag                        flags)
        : AutomationControl (s, parameter, desc, l, name, flags)
+       , _masters_node (0)
 {
 }
 
+SlavableAutomationControl::~SlavableAutomationControl ()
+{
+       if (_masters_node) {
+               delete _masters_node;
+               _masters_node = 0;
+       }
+}
+
 double
 SlavableAutomationControl::get_masters_value_locked () const
 {
@@ -116,7 +127,7 @@ SlavableAutomationControl::actually_set_value (double val, Controllable::GroupCo
 }
 
 void
-SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
+SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
 {
        std::pair<Masters::iterator,bool> res;
 
@@ -131,7 +142,9 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
 
                if (res.second) {
 
-                       recompute_masters_ratios (current_value);
+                       if (!loading) {
+                               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
@@ -143,11 +156,11 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> 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. 
+                          AutomationControl.
 
                           Note that this also makes it safe to store a
                           boost::shared_ptr<AutomationControl> in the functor,
-                          since we know we will destroy the functor when the 
+                          since we know we will destroy the functor when the
                           connection is destroyed, which happens when we
                           disconnect from the master (for any reason).
 
@@ -157,7 +170,6 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
                        */
 
                        m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
-                       cerr << this << enum_2_string ((AutomationType) _parameter.type()) << " now listening to Changed from " << m << endl;
                }
        }
 
@@ -330,4 +342,109 @@ SlavableAutomationControl::slaved () const
        return !_masters.empty();
 }
 
+void
+SlavableAutomationControl::use_saved_master_ratios ()
+{
+       if (!_masters_node) {
+               return;
+       }
+
+       Glib::Threads::RWLock::ReaderLock lm (master_lock);
+
+       /* use stored state, do not recompute */
+
+       if (_desc.toggled) {
+
+               XMLNodeList nlist = _masters_node->children();
+               XMLNodeIterator niter;
+
+               for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+                       XMLProperty const * id_prop = (*niter)->property (X_("id"));
+                       if (!id_prop) {
+                               continue;
+                       }
+                       XMLProperty const * yn_prop = (*niter)->property (X_("yn"));
+                       if (!yn_prop) {
+                               continue;
+                       }
+                       Masters::iterator mi = _masters.find (ID (id_prop->value()));
+                       if (mi != _masters.end()) {
+                               mi->second.set_yn (string_is_affirmative (yn_prop->value()));
+                       }
+               }
+
+       } else {
+
+               XMLProperty const * prop = _masters_node->property (X_("ratio"));
+
+               if (prop) {
+
+                       gain_t ratio;
+                       sscanf (prop->value().c_str(), "%g", &ratio);
+
+                       for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
+                               mr->second.reset_ratio (ratio);
+                       }
+               } else {
+                       PBD::error << string_compose (_("programming error: %1"), X_("missing ratio information for control slave"))<< endmsg;
+               }
+       }
+
+       delete _masters_node;
+       _masters_node = 0;
+
+       return;
+}
+
+
+XMLNode&
+SlavableAutomationControl::get_state ()
+{
+       XMLNode& node (AutomationControl::get_state());
+
+       /* store VCA master ratios */
+
+       {
+               Glib::Threads::RWLock::ReaderLock lm (master_lock);
+
+               if (!_masters.empty()) {
+
+                       XMLNode* masters_node = new XMLNode (X_("masters"));
+
+                       if (_desc.toggled) {
+                               for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
+                                       XMLNode* mnode = new XMLNode (X_("master"));
+                                       mnode->add_property (X_("id"), mr->second.master()->id().to_s());
+                                       mnode->add_property (X_("yn"), mr->second.yn());
+                                       masters_node->add_child_nocopy (*mnode);
+                               }
+                       } else {
+                               XMLNode* masters_node = new XMLNode (X_("masters"));
+                               /* ratio is the same for all masters, so just store one */
+                               masters_node->add_property (X_("ratio"), PBD::to_string (_masters.begin()->second.ratio(), std::dec));
+                       }
+
+                       node.add_child_nocopy (*masters_node);
+               }
+       }
+
+       return node;
+}
+
+int
+SlavableAutomationControl::set_state (XMLNode const& node, int version)
+{
+       XMLNodeList nlist = node.children();
+       XMLNodeIterator niter;
+
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+               if ((*niter)->name() == X_("masters")) {
+                       _masters_node = new XMLNode (**niter);
+               }
+       }
+
+       return AutomationControl::set_state (node, version);
+}
+
+
 #endif /* __libardour_slavable_automation_control_h__ */