summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2017-02-06 16:18:09 +0100
committerPaul Davis <paul@linuxaudiosystems.com>2017-02-06 16:49:08 +0100
commitedd1061c3d8822ab586e2bbc80894e125b521a52 (patch)
tree37e171eb88ca33ade64cf07cbf98bb518a6c0f70
parent4161a602449ebfff5ff5a9327807100f799e3dd3 (diff)
save/restore VCA master state inside slaves, so that a reloaded session ends up back in the same state
-rw-r--r--gtk2_ardour/control_slave_ui.cc2
-rw-r--r--gtk2_ardour/group_tabs.cc2
-rw-r--r--gtk2_ardour/mixer_strip.cc2
-rw-r--r--libs/ardour/ardour/gain_control.h3
-rw-r--r--libs/ardour/ardour/slavable.h4
-rw-r--r--libs/ardour/ardour/slavable_automation_control.h11
-rw-r--r--libs/ardour/gain_control.cc35
-rw-r--r--libs/ardour/route_group.cc4
-rw-r--r--libs/ardour/slavable.cc48
-rw-r--r--libs/ardour/slavable_automation_control.cc127
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<ARDOUR::VCA> vca)
{
boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( 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<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:
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<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
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<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;
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<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);
}
}
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<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__ */