From edd1061c3d8822ab586e2bbc80894e125b521a52 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 6 Feb 2017 16:18:09 +0100 Subject: save/restore VCA master state inside slaves, so that a reloaded session ends up back in the same state --- gtk2_ardour/control_slave_ui.cc | 2 +- gtk2_ardour/group_tabs.cc | 2 +- gtk2_ardour/mixer_strip.cc | 2 +- libs/ardour/ardour/gain_control.h | 3 - libs/ardour/ardour/slavable.h | 4 +- libs/ardour/ardour/slavable_automation_control.h | 11 +- libs/ardour/gain_control.cc | 35 ------- libs/ardour/route_group.cc | 4 +- libs/ardour/slavable.cc | 48 ++++++--- libs/ardour/slavable_automation_control.cc | 127 ++++++++++++++++++++++- 10 files changed, 169 insertions(+), 69 deletions(-) diff --git a/gtk2_ardour/control_slave_ui.cc b/gtk2_ardour/control_slave_ui.cc index ef1b0a2f6e..9ea6136e5f 100644 --- a/gtk2_ardour/control_slave_ui.cc +++ b/gtk2_ardour/control_slave_ui.cc @@ -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); } } diff --git a/gtk2_ardour/group_tabs.cc b/gtk2_ardour/group_tabs.cc index 94e7c8cfea..9d10a442d4 100644 --- a/gtk2_ardour/group_tabs.cc +++ b/gtk2_ardour/group_tabs.cc @@ -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); } } diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 1a82d7025b..e233a16748 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -431,7 +431,7 @@ MixerStrip::vca_assign (boost::shared_ptr vca) { boost::shared_ptr sl = boost::dynamic_pointer_cast ( route() ); if (sl) - sl->assign(vca); + sl->assign(vca, false); } void diff --git a/libs/ardour/ardour/gain_control.h b/libs/ardour/ardour/gain_control.h index f72320f1dd..53f429b88a 100644 --- a/libs/ardour/ardour/gain_control.h +++ b/libs/ardour/ardour/gain_control.h @@ -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: diff --git a/libs/ardour/ardour/slavable.h b/libs/ardour/ardour/slavable.h index 5af954d51c..15d3e41991 100644 --- a/libs/ardour/ardour/slavable.h +++ b/libs/ardour/ardour/slavable.h @@ -49,7 +49,7 @@ class LIBARDOUR_API Slavable XMLNode& get_state () const; int set_state (XMLNode const&, int); - void assign (boost::shared_ptr); + void assign (boost::shared_ptr, bool loading); void unassign (boost::shared_ptr); PBD::Signal2,bool> AssignmentChange; @@ -62,7 +62,7 @@ class LIBARDOUR_API Slavable static PBD::Signal1 Assign; protected: - virtual int assign_controls (boost::shared_ptr); + virtual int assign_controls (boost::shared_ptr, bool loading); virtual int unassign_controls (boost::shared_ptr); private: diff --git a/libs/ardour/ardour/slavable_automation_control.h b/libs/ardour/ardour/slavable_automation_control.h index 7e46dd5a74..857a8956e1 100644 --- a/libs/ardour/ardour/slavable_automation_control.h +++ b/libs/ardour/ardour/slavable_automation_control.h @@ -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); + void add_master (boost::shared_ptr, bool loading); void remove_master (boost::shared_ptr); void clear_masters (); bool slaved_to (boost::shared_ptr) const; @@ -57,6 +59,11 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl PBD::Signal0 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) {} virtual void post_add_master (boost::shared_ptr) {} - + XMLNode* _masters_node; /* used to store master ratios in ::set_state() for later use */ }; } // namespace ARDOUR diff --git a/libs/ardour/gain_control.cc b/libs/ardour/gain_control.cc index d100273640..21e1ba5f85 100644 --- a/libs/ardour/gain_control.cc +++ b/libs/ardour/gain_control.cc @@ -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); -} - diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc index 1a7b98050c..519c88c84f 100644 --- a/libs/ardour/route_group.cc +++ b/libs/ardour/route_group.cc @@ -180,7 +180,7 @@ RouteGroup::add (boost::shared_ptr r) boost::shared_ptr 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 master) } for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) { - (*r)->assign (master); + (*r)->assign (master, false); } group_master = master; diff --git a/libs/ardour/slavable.cc b/libs/ardour/slavable.cc index 61a11f257d..35063fa35f 100644 --- a/libs/ardour/slavable.cc +++ b/libs/ardour/slavable.cc @@ -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 >::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 (); @@ -114,12 +139,12 @@ Slavable::do_assign (VCAManager* manager) } void -Slavable::assign (boost::shared_ptr v) +Slavable::assign (boost::shared_ptr 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 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) +Slavable::assign_controls (boost::shared_ptr vca, bool loading) { boost::shared_ptr slave; boost::shared_ptr master; @@ -184,7 +198,7 @@ Slavable::assign_controls (boost::shared_ptr vca) master = vca->automation_control (auto_slave_types[n]); if (slave && master) { - slave->add_master (master); + slave->add_master (master, loading); } } diff --git a/libs/ardour/slavable_automation_control.cc b/libs/ardour/slavable_automation_control.cc index 31e81a2931..b76f91b13b 100644 --- a/libs/ardour/slavable_automation_control.cc +++ b/libs/ardour/slavable_automation_control.cc @@ -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 m) +SlavableAutomationControl::add_master (boost::shared_ptr m, bool loading) { std::pair res; @@ -131,7 +142,9 @@ SlavableAutomationControl::add_master (boost::shared_ptr 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, thus avoiding holding a reference to the control in the binding @@ -143,11 +156,11 @@ SlavableAutomationControl::add_master (boost::shared_ptr 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 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 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__ */ -- cgit v1.2.3