summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-03-08 23:29:17 -0500
committerPaul Davis <paul@linuxaudiosystems.com>2016-05-31 15:30:40 -0400
commitc660703f95a269a7f312e84564345f8961cb7e75 (patch)
treef09c8dc32e0afc1ed0fc2715d82697f2a82c06c4 /libs
parent74f8a812765ba197173489407e4d30b0b4f94d66 (diff)
redesign control slave/master system, move code from GainControl to AutomationControl
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/automation_control.h46
-rw-r--r--libs/ardour/ardour/gain_control.h41
-rw-r--r--libs/ardour/automation_control.cc129
-rw-r--r--libs/ardour/gain_control.cc162
-rw-r--r--libs/ardour/route.cc6
5 files changed, 186 insertions, 198 deletions
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
index 39fdb11397..de476288f0 100644
--- a/libs/ardour/ardour/automation_control.h
+++ b/libs/ardour/ardour/automation_control.h
@@ -21,10 +21,16 @@
#ifndef __ardour_automation_control_h__
#define __ardour_automation_control_h__
+#include <map>
+
+#include <glibmm/threads.h>
+
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include "pbd/controllable.h"
+
+#include "evoral/types.hpp"
#include "evoral/Control.hpp"
#include "ardour/libardour_visibility.h"
@@ -111,10 +117,48 @@ public:
const ARDOUR::Session& session() const { return _session; }
void commit_transaction (bool did_write);
-protected:
+ void add_master (boost::shared_ptr<AutomationControl>);
+ void remove_master (boost::shared_ptr<AutomationControl>);
+ void clear_masters ();
+ bool slaved_to (boost::shared_ptr<AutomationControl>) const;
+ bool slaved () const;
+ std::vector<PBD::ID> masters () const;
+
+ PBD::Signal0<void> MasterStatusChange;
+
+ protected:
ARDOUR::Session& _session;
const ParameterDescriptor _desc;
+
+
+ class MasterRecord {
+ public:
+ MasterRecord (boost::shared_ptr<AutomationControl> gc, double r)
+ : _master (gc)
+ , _ratio (r)
+ {}
+
+ boost::shared_ptr<AutomationControl> master() const { return _master; }
+ double ratio () const { return _ratio; }
+ void reset_ratio (double r) { _ratio = r; }
+
+ PBD::ScopedConnection connection;
+
+ private:
+ boost::shared_ptr<AutomationControl> _master;
+ double _ratio;
+
+ };
+
+ mutable Glib::Threads::RWLock master_lock;
+ typedef std::map<PBD::ID,MasterRecord> Masters;
+ Masters _masters;
+ PBD::ScopedConnectionList masters_connections;
+
+ void master_going_away (boost::weak_ptr<AutomationControl>);
+ virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
+ double get_value_locked() const;
};
diff --git a/libs/ardour/ardour/gain_control.h b/libs/ardour/ardour/gain_control.h
index e565dd33c9..4ec538e698 100644
--- a/libs/ardour/ardour/gain_control.h
+++ b/libs/ardour/ardour/gain_control.h
@@ -20,10 +20,8 @@
#define __ardour_gain_control_h__
#include <string>
-#include <map>
#include <boost/shared_ptr.hpp>
-#include <glibmm/threads.h>
#include "pbd/controllable.h"
@@ -41,7 +39,6 @@ class LIBARDOUR_API GainControl : public AutomationControl {
GainControl (Session& session, const Evoral::Parameter &param,
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>());
- double get_value () const;
void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
void set_value_unchecked (double);
@@ -54,51 +51,15 @@ class LIBARDOUR_API GainControl : public AutomationControl {
double lower_db;
double range_db;
- gain_t get_master_gain () const;
- void add_master (boost::shared_ptr<VCA>);
- void remove_master (boost::shared_ptr<VCA>);
- void clear_masters ();
- bool slaved_to (boost::shared_ptr<VCA>) const;
- bool slaved () const;
- std::vector<uint32_t> masters () const;
-
- PBD::Signal0<void> VCAStatusChange;
-
int set_state (XMLNode const&, int);
XMLNode& get_state();
private:
- class MasterRecord {
- public:
- MasterRecord (boost::shared_ptr<AutomationControl> gc, double r)
- : _master (gc)
- , _ratio (r)
- {}
-
- boost::shared_ptr<AutomationControl> master() const { return _master; }
- double ratio () const { return _ratio; }
- void reset_ratio (double r) { _ratio = r; }
-
- PBD::ScopedConnection connection;
-
- private:
- boost::shared_ptr<AutomationControl> _master;
- double _ratio;
-
- };
-
- mutable Glib::Threads::RWLock master_lock;
- typedef std::map<uint32_t,MasterRecord> Masters;
- Masters _masters;
- PBD::ScopedConnectionList masters_connections;
std::string masters_string;
PBD::ScopedConnection vca_loaded_connection;
- gain_t get_value_locked () const;
- gain_t get_master_gain_locked () const;
- void master_going_away (boost::weak_ptr<VCA>);
- void recompute_masters_ratios (double val);
void vcas_loaded();
+ void recompute_masters_ratios (double val);
void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
};
diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc
index 3629345d94..4317a18788 100644
--- a/libs/ardour/automation_control.cc
+++ b/libs/ardour/automation_control.cc
@@ -56,6 +56,7 @@ AutomationControl::AutomationControl(ARDOUR::Session& s
AutomationControl::~AutomationControl ()
{
+ DropReferences (); /* EMIT SIGNAL */
}
bool
@@ -73,9 +74,36 @@ double
AutomationControl::get_value() const
{
bool from_list = _list && ((AutomationList*)_list.get())->automation_playback();
- return Control::get_double (from_list, _session.transport_frame());
+
+ if (!from_list) {
+ Glib::Threads::RWLock::ReaderLock lm (master_lock);
+ return get_value_locked ();
+ } else {
+ return Control::get_double (from_list, _session.transport_frame());
+ }
+}
+
+double
+AutomationControl::get_value_locked() const
+{
+ /* read or write masters lock must be held */
+
+ if (_masters.empty()) {
+ return Control::get_double (false, _session.transport_frame());
+ }
+
+ gain_t v = 1.0;
+
+ for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
+ /* get current master value, scale by our current ratio with that master */
+ v *= mr->second.master()->get_value () * mr->second.ratio();
+ }
+
+ return min (_desc.upper, v);
}
+
+
/** Set the value and do the right thing based on automation state
* (e.g. record if necessary, etc.)
* @param value `user' value
@@ -232,3 +260,102 @@ AutomationControl::interface_to_internal (double val) const
}
+void
+AutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
+{
+ double current_value;
+ std::pair<Masters::iterator,bool> res;
+
+ {
+ Glib::Threads::RWLock::WriterLock lm (master_lock);
+ current_value = get_value_locked ();
+
+ /* ratio will be recomputed below */
+
+ res = _masters.insert (make_pair<PBD::ID,MasterRecord> (m->id(), MasterRecord (m, 1.0)));
+
+ if (res.second) {
+
+ 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
+ itself.
+ */
+
+ m->DropReferences.connect_same_thread (masters_connections, boost::bind (&AutomationControl::master_going_away, this, 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.
+ */
+
+ m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&PBD::Signal0<void>::operator(), &Changed));
+ }
+ }
+
+ if (res.second) {
+ MasterStatusChange (); /* EMIT SIGNAL */
+ }
+}
+
+void
+AutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
+{
+ boost::shared_ptr<AutomationControl> m = wm.lock();
+ if (m) {
+ remove_master (m);
+ }
+}
+
+void
+AutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
+{
+ double current_value;
+ Masters::size_type erased = 0;
+
+ {
+ Glib::Threads::RWLock::WriterLock lm (master_lock);
+ current_value = get_value_locked ();
+ erased = _masters.erase (m->id());
+ if (erased) {
+ recompute_masters_ratios (current_value);
+ }
+ }
+
+ if (erased) {
+ MasterStatusChange (); /* EMIT SIGNAL */
+ }
+}
+
+void
+AutomationControl::clear_masters ()
+{
+ bool had_masters = false;
+
+ {
+ Glib::Threads::RWLock::WriterLock lm (master_lock);
+ if (!_masters.empty()) {
+ had_masters = true;
+ }
+ _masters.clear ();
+ }
+
+ if (had_masters) {
+ MasterStatusChange (); /* EMIT SIGNAL */
+ }
+}
+
+bool
+AutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
+{
+ Glib::Threads::RWLock::ReaderLock lm (master_lock);
+ return _masters.find (m->id()) != _masters.end();
+}
+
+bool
+AutomationControl::slaved () const
+{
+ Glib::Threads::RWLock::ReaderLock lm (master_lock);
+ return !_masters.empty();
+}
+
diff --git a/libs/ardour/gain_control.cc b/libs/ardour/gain_control.cc
index 3415f7c620..456fd9b248 100644
--- a/libs/ardour/gain_control.cc
+++ b/libs/ardour/gain_control.cc
@@ -43,32 +43,6 @@ GainControl::GainControl (Session& session, const Evoral::Parameter &param, boos
range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
}
-gain_t
-GainControl::get_value_locked () const {
-
- /* read or write masters lock must be held */
-
- if (_masters.empty()) {
- return AutomationControl::get_value();
- }
-
- gain_t g = 1.0;
-
- for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
- /* get current master value, scale by our current ratio with that master */
- g *= mr->second.master()->get_value () * mr->second.ratio();
- }
-
- return min (Config->get_max_gain(), g);
-}
-
-double
-GainControl::get_value () const
-{
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return get_value_locked ();
-}
-
void
GainControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
{
@@ -97,6 +71,10 @@ GainControl::_set_value (double val, Controllable::GroupControlDisposition group
}
}
+ /* this sets the Evoral::Control::_user_value for us, which will
+ be retrieved by AutomationControl::get_value ()
+ */
+
AutomationControl::set_value (val, group_override);
_session.set_dirty ();
@@ -141,118 +119,6 @@ GainControl::get_user_string () const
return std::string(theBuf);
}
-gain_t
-GainControl::get_master_gain () const
-{
- Glib::Threads::RWLock::ReaderLock sm (master_lock, Glib::Threads::TRY_LOCK);
-
- if (sm.locked()) {
- return get_master_gain_locked ();
- }
-
- return 1.0;
-}
-
-gain_t
-GainControl::get_master_gain_locked () const
-{
- /* Master lock MUST be held (read or write lock is acceptable) */
-
- gain_t g = 1.0;
-
- for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
- /* get current master value, scale by our current ratio with that master */
- g *= mr->second.master()->get_value () * mr->second.ratio();
- }
-
- return g;
-}
-
-void
-GainControl::add_master (boost::shared_ptr<VCA> vca)
-{
- gain_t current_value;
- std::pair<Masters::iterator,bool> res;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- current_value = get_value_locked ();
-
- /* ratio will be recomputed below */
-
- res = _masters.insert (make_pair<uint32_t,MasterRecord> (vca->number(), MasterRecord (vca->gain_control(), 0.0)));
-
- if (res.second) {
-
- recompute_masters_ratios (current_value);
-
- /* note that we bind @param m as a weak_ptr<GainControl>, thus
- avoiding holding a reference to the control in the binding
- itself.
- */
-
- vca->DropReferences.connect_same_thread (masters_connections, boost::bind (&GainControl::master_going_away, this, vca));
-
- /* 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 VCA.
- */
-
- vca->gain_control()->Changed.connect_same_thread (res.first->second.connection, boost::bind (&PBD::Signal0<void>::operator(), &Changed));
- }
- }
-
- if (res.second) {
- VCAStatusChange (); /* EMIT SIGNAL */
- }
-}
-
-void
-GainControl::master_going_away (boost::weak_ptr<VCA> wv)
-{
- boost::shared_ptr<VCA> v = wv.lock();
- if (v) {
- remove_master (v);
- }
-}
-
-void
-GainControl::remove_master (boost::shared_ptr<VCA> vca)
-{
- gain_t current_value;
- Masters::size_type erased = 0;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- current_value = get_value_locked ();
- erased = _masters.erase (vca->number());
- if (erased) {
- recompute_masters_ratios (current_value);
- }
- }
-
- if (erased) {
- VCAStatusChange (); /* EMIT SIGNAL */
- }
-}
-
-void
-GainControl::clear_masters ()
-{
- bool had_masters = false;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- if (!_masters.empty()) {
- had_masters = true;
- }
- _masters.clear ();
- }
-
- if (had_masters) {
- VCAStatusChange (); /* EMIT SIGNAL */
- }
-}
-
void
GainControl::recompute_masters_ratios (double val)
{
@@ -301,25 +167,12 @@ GainControl::recompute_masters_ratios (double val)
}
}
-bool
-GainControl::slaved_to (boost::shared_ptr<VCA> vca) const
-{
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return _masters.find (vca->number()) != _masters.end();
-}
-
-bool
-GainControl::slaved () const
-{
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return !_masters.empty();
-}
-
XMLNode&
GainControl::get_state ()
{
XMLNode& node (AutomationControl::get_state());
+#if 0
/* store VCA master IDs */
string str;
@@ -337,6 +190,7 @@ GainControl::get_state ()
if (!str.empty()) {
node.add_property (X_("masters"), str);
}
+#endif
return node;
}
@@ -346,6 +200,7 @@ GainControl::set_state (XMLNode const& node, int version)
{
AutomationControl::set_state (node, version);
+#if 0
XMLProperty const* prop = node.property (X_("masters"));
/* Problem here if we allow VCA's to be slaved to other VCA's .. we
@@ -362,6 +217,7 @@ GainControl::set_state (XMLNode const& node, int version)
_session.vca_manager().VCAsLoaded.connect_same_thread (vca_loaded_connection, boost::bind (&GainControl::vcas_loaded, this));
}
}
+#endif
return 0;
}
@@ -379,7 +235,7 @@ GainControl::vcas_loaded ()
for (vector<string>::const_iterator m = masters.begin(); m != masters.end(); ++m) {
boost::shared_ptr<VCA> vca = _session.vca_manager().vca_by_number (PBD::atoi (*m));
if (vca) {
- add_master (vca);
+ add_master (vca->gain_control());
}
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 5332a70036..641bc8ef83 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -5892,13 +5892,13 @@ Route::slaved_to (boost::shared_ptr<VCA> vca) const
return false;
}
- return _gain_control->slaved_to (vca);
+ return _gain_control->slaved_to (vca->gain_control());
}
void
Route::vca_assign (boost::shared_ptr<VCA> vca)
{
- _gain_control->add_master (vca);
+ _gain_control->add_master (vca->gain_control());
vca->add_solo_target (shared_from_this());
vca->add_mute_target (shared_from_this());
}
@@ -5911,7 +5911,7 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
_gain_control->clear_masters ();
/* XXXX need to remove from solo/mute target lists */
} else {
- _gain_control->remove_master (vca);
+ _gain_control->remove_master (vca->gain_control());
vca->remove_solo_target (shared_from_this());
vca->remove_mute_target (shared_from_this());
}