summaryrefslogtreecommitdiff
path: root/libs/ardour/automation_control.cc
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/ardour/automation_control.cc
parent74f8a812765ba197173489407e4d30b0b4f94d66 (diff)
redesign control slave/master system, move code from GainControl to AutomationControl
Diffstat (limited to 'libs/ardour/automation_control.cc')
-rw-r--r--libs/ardour/automation_control.cc129
1 files changed, 128 insertions, 1 deletions
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();
+}
+