save/restore VCA master state inside slaves, so that a reloaded session ends up back in the same state
This commit is contained in:
parent
4161a60244
commit
edd1061c3d
@ -128,7 +128,7 @@ ControlSlaveUI::vca_menu_toggle (Gtk::CheckMenuItem* menuitem, uint32_t n)
|
|||||||
if (!menuitem->get_active()) {
|
if (!menuitem->get_active()) {
|
||||||
sl->unassign (vca);
|
sl->unassign (vca);
|
||||||
} else {
|
} else {
|
||||||
sl->assign (vca);
|
sl->assign (vca, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +500,7 @@ GroupTabs::assign_some_to_master (uint32_t which, RouteList rl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (RouteList::iterator r = rl.begin(); r != rl.end(); ++r) {
|
for (RouteList::iterator r = rl.begin(); r != rl.end(); ++r) {
|
||||||
(*r)->assign (master);
|
(*r)->assign (master, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +431,7 @@ MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
|
|||||||
{
|
{
|
||||||
boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
|
boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
|
||||||
if (sl)
|
if (sl)
|
||||||
sl->assign(vca);
|
sl->assign(vca, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -48,9 +48,6 @@ class LIBARDOUR_API GainControl : public SlavableAutomationControl {
|
|||||||
double lower_db;
|
double lower_db;
|
||||||
double range_db;
|
double range_db;
|
||||||
|
|
||||||
int set_state (XMLNode const&, int);
|
|
||||||
XMLNode& get_state();
|
|
||||||
|
|
||||||
void inc_gain (gain_t);
|
void inc_gain (gain_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -49,7 +49,7 @@ class LIBARDOUR_API Slavable
|
|||||||
XMLNode& get_state () const;
|
XMLNode& get_state () const;
|
||||||
int set_state (XMLNode const&, int);
|
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>);
|
void unassign (boost::shared_ptr<VCA>);
|
||||||
|
|
||||||
PBD::Signal2<void,boost::shared_ptr<VCA>,bool> AssignmentChange;
|
PBD::Signal2<void,boost::shared_ptr<VCA>,bool> AssignmentChange;
|
||||||
@ -62,7 +62,7 @@ class LIBARDOUR_API Slavable
|
|||||||
static PBD::Signal1<void,VCAManager*> Assign;
|
static PBD::Signal1<void,VCAManager*> Assign;
|
||||||
|
|
||||||
protected:
|
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>);
|
virtual int unassign_controls (boost::shared_ptr<VCA>);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -36,9 +36,11 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl
|
|||||||
PBD::Controllable::Flag flags=PBD::Controllable::Flag (0)
|
PBD::Controllable::Flag flags=PBD::Controllable::Flag (0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
~SlavableAutomationControl ();
|
||||||
|
|
||||||
double get_value () const;
|
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 remove_master (boost::shared_ptr<AutomationControl>);
|
||||||
void clear_masters ();
|
void clear_masters ();
|
||||||
bool slaved_to (boost::shared_ptr<AutomationControl>) const;
|
bool slaved_to (boost::shared_ptr<AutomationControl>) const;
|
||||||
@ -57,6 +59,11 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl
|
|||||||
|
|
||||||
PBD::Signal0<void> MasterStatusChange;
|
PBD::Signal0<void> MasterStatusChange;
|
||||||
|
|
||||||
|
void use_saved_master_ratios ();
|
||||||
|
|
||||||
|
int set_state (XMLNode const&, int);
|
||||||
|
XMLNode& get_state();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
class MasterRecord {
|
class MasterRecord {
|
||||||
@ -111,7 +118,7 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl
|
|||||||
virtual void pre_remove_master (boost::shared_ptr<AutomationControl>) {}
|
virtual void pre_remove_master (boost::shared_ptr<AutomationControl>) {}
|
||||||
virtual void post_add_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
|
} // namespace ARDOUR
|
||||||
|
@ -133,7 +133,6 @@ GainControl::recompute_masters_ratios (double val)
|
|||||||
Mr(n) is the new ratio number for the slaves
|
Mr(n) is the new ratio number for the slaves
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
const double nmasters = _masters.size();
|
const double nmasters = _masters.size();
|
||||||
double masters_total_gain_coefficient = 1.0;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ RouteGroup::add (boost::shared_ptr<Route> r)
|
|||||||
boost::shared_ptr<VCA> vca (group_master.lock());
|
boost::shared_ptr<VCA> vca (group_master.lock());
|
||||||
|
|
||||||
if (vca) {
|
if (vca) {
|
||||||
r->assign (vca);
|
r->assign (vca, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_session.set_dirty ();
|
_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) {
|
for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) {
|
||||||
(*r)->assign (master);
|
(*r)->assign (master, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
group_master = master;
|
group_master = master;
|
||||||
|
@ -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
|
int
|
||||||
Slavable::do_assign (VCAManager* manager)
|
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 */
|
/* 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) {
|
if (!vcas.empty()) {
|
||||||
assign (*v);
|
|
||||||
|
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 ();
|
assign_connection.disconnect ();
|
||||||
@ -114,12 +139,12 @@ Slavable::do_assign (VCAManager* manager)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Slavable::assign (boost::shared_ptr<VCA> v)
|
Slavable::assign (boost::shared_ptr<VCA> v, bool loading)
|
||||||
{
|
{
|
||||||
assert (v);
|
assert (v);
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (master_lock);
|
Glib::Threads::RWLock::WriterLock lm (master_lock);
|
||||||
if (assign_controls (v) == 0) {
|
if (assign_controls (v, loading) == 0) {
|
||||||
_masters.insert (v->number());
|
_masters.insert (v->number());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,19 +186,8 @@ Slavable::unassign (boost::shared_ptr<VCA> v)
|
|||||||
AssignmentChange (v, false);
|
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
|
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<SlavableAutomationControl> slave;
|
||||||
boost::shared_ptr<AutomationControl> master;
|
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]);
|
master = vca->automation_control (auto_slave_types[n]);
|
||||||
|
|
||||||
if (slave && master) {
|
if (slave && master) {
|
||||||
slave->add_master (master);
|
slave->add_master (master, loading);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#define __libardour_slavable_automation_control_h__
|
#define __libardour_slavable_automation_control_h__
|
||||||
|
|
||||||
#include "pbd/enumwriter.h"
|
#include "pbd/enumwriter.h"
|
||||||
|
#include "pbd/error.h"
|
||||||
|
#include "pbd/i18n.h"
|
||||||
|
|
||||||
#include "ardour/slavable_automation_control.h"
|
#include "ardour/slavable_automation_control.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
@ -35,9 +37,18 @@ SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
|
|||||||
const std::string& name,
|
const std::string& name,
|
||||||
Controllable::Flag flags)
|
Controllable::Flag flags)
|
||||||
: AutomationControl (s, parameter, desc, l, name, flags)
|
: AutomationControl (s, parameter, desc, l, name, flags)
|
||||||
|
, _masters_node (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SlavableAutomationControl::~SlavableAutomationControl ()
|
||||||
|
{
|
||||||
|
if (_masters_node) {
|
||||||
|
delete _masters_node;
|
||||||
|
_masters_node = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
SlavableAutomationControl::get_masters_value_locked () const
|
SlavableAutomationControl::get_masters_value_locked () const
|
||||||
{
|
{
|
||||||
@ -116,7 +127,7 @@ SlavableAutomationControl::actually_set_value (double val, Controllable::GroupCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
std::pair<Masters::iterator,bool> res;
|
||||||
|
|
||||||
@ -131,7 +142,9 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
|
|||||||
|
|
||||||
if (res.second) {
|
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
|
/* note that we bind @param m as a weak_ptr<AutomationControl>, thus
|
||||||
avoiding holding a reference to the control in the binding
|
avoiding holding a reference to the control in the binding
|
||||||
@ -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));
|
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();
|
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__ */
|
#endif /* __libardour_slavable_automation_control_h__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user