From 653ae4acd639fef149314fe6f8c7a0d862afae40 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Apr 2016 16:49:47 -0400 Subject: universal change in the design of the way Route/Track controls are designed and used. The controls now own their own state, rather than proxy for state in their owners. Massive changes all over the code to accomodate this. Many things are not finished. Consider this a backup safety commit --- libs/ardour/automation_control.cc | 210 ++++++++------------------------------ 1 file changed, 45 insertions(+), 165 deletions(-) (limited to 'libs/ardour/automation_control.cc') diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc index b00c615625..7efaa07f23 100644 --- a/libs/ardour/automation_control.cc +++ b/libs/ardour/automation_control.cc @@ -20,14 +20,17 @@ #include #include + +#include "pbd/memento_command.h" +#include "pbd/stacktrace.h" + +#include "ardour/audioengine.h" #include "ardour/automation_control.h" #include "ardour/automation_watch.h" +#include "ardour/control_group.h" #include "ardour/event_type_map.h" #include "ardour/session.h" -#include "pbd/memento_command.h" -#include "pbd/stacktrace.h" - #include "i18n.h" #ifdef COMPILER_MSVC @@ -69,42 +72,38 @@ AutomationControl::writable() const return true; } +/** Get the current effective `user' value based on automation state */ double -AutomationControl::get_masters_value_locked () const +AutomationControl::get_value() const { - 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); + bool from_list = _list && boost::dynamic_pointer_cast(_list)->automation_playback(); + return Control::get_double (from_list, _session.transport_frame()); } -double -AutomationControl::get_value_locked() const +void +AutomationControl::set_value (double val, PBD::Controllable::GroupControlDisposition gcd) { - /* read or write masters lock must be held */ - - if (_masters.empty()) { - return Control::get_double (false, _session.transport_frame()); + if (!writable()) { + return; } - return get_masters_value_locked (); -} + /* enforce strict double/boolean value mapping */ -/** Get the current effective `user' value based on automation state */ -double -AutomationControl::get_value() const -{ - bool from_list = _list && ((AutomationList*)_list.get())->automation_playback(); + if (_desc.toggled) { + if (val != 0.0) { + val = 1.0; + } + } + + if (check_rt (val, gcd)) { + /* change has been queued to take place in an RT context */ + return; + } - if (!from_list) { - Glib::Threads::RWLock::ReaderLock lm (master_lock); - return get_value_locked (); + if (_group && _group->use_me (gcd)) { + _group->set_group_value (shared_from_this(), val); } else { - return Control::get_double (from_list, _session.transport_frame()); + actually_set_value (val, gcd); } } @@ -113,12 +112,15 @@ AutomationControl::get_value() const * @param value `user' value */ void -AutomationControl::set_value (double value, PBD::Controllable::GroupControlDisposition gcd) +AutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd) { - bool to_list = _list && ((AutomationList*)_list.get())->automation_write(); + bool to_list = _list && boost::dynamic_pointer_cast(_list)->automation_write(); Control::set_double (value, _session.transport_frame(), to_list); + AutomationType at = (AutomationType) _parameter.type(); + + std::cerr << "++++ Changed (" << enum_2_string (at) << ", " << enum_2_string (gcd) << ") = " << value << " @ " << this << std::endl; Changed (true, gcd); } @@ -263,147 +265,25 @@ AutomationControl::interface_to_internal (double val) const return val; } - -void -AutomationControl::add_master (boost::shared_ptr m) -{ - double current_value; - double new_value; - std::pair res; - - { - Glib::Threads::RWLock::WriterLock lm (master_lock); - current_value = get_value_locked (); - - /* ratio will be recomputed below */ - - res = _masters.insert (make_pair (m->id(), MasterRecord (m, 1.0))); - - if (res.second) { - - 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 - 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. - - Note that we fix the "from_self" argument that will - be given to our own Changed signal to "false", - because the change came from the master. - */ - - - m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&AutomationControl::master_changed, this, _1, _2)); - } - - new_value = get_value_locked (); - } - - if (res.second) { - /* this will notify everyone that we're now slaved to the master */ - MasterStatusChange (); /* EMIT SIGNAL */ - } - - if (new_value != current_value) { - /* force a call to to ::master_changed() to carry the - * consequences that would occur if the master assumed - * its current value WHILE we were slaved. - */ - master_changed (false, Controllable::NoGroup); - /* effective value changed by master */ - Changed (false, Controllable::NoGroup); - } - -} - -void -AutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd) -{ - /* our value has (likely) changed, but not because we were - * modified. Just the master. - */ - - Changed (false, gcd); /* EMIT SIGNAL */ -} - -void -AutomationControl::master_going_away (boost::weak_ptr wm) -{ - boost::shared_ptr m = wm.lock(); - if (m) { - remove_master (m); - } -} - -void -AutomationControl::remove_master (boost::shared_ptr m) -{ - double current_value; - double new_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); - } - new_value = get_value_locked (); - } - - if (erased) { - MasterStatusChange (); /* EMIT SIGNAL */ - } - - if (new_value != current_value) { - Changed (false, Controllable::NoGroup); - } -} - void -AutomationControl::clear_masters () +AutomationControl::set_group (boost::shared_ptr cg) { - double current_value; - double new_value; - bool had_masters = false; - - { - Glib::Threads::RWLock::WriterLock lm (master_lock); - current_value = get_value_locked (); - if (!_masters.empty()) { - had_masters = true; - } - _masters.clear (); - new_value = get_value_locked (); - } - - if (had_masters) { - MasterStatusChange (); /* EMIT SIGNAL */ - } - - if (new_value != current_value) { - Changed (false, Controllable::NoGroup); + if (_group) { + _group->remove_control (shared_from_this()); } + _group = cg; } bool -AutomationControl::slaved_to (boost::shared_ptr m) const +AutomationControl::check_rt (double val, Controllable::GroupControlDisposition gcd) { - Glib::Threads::RWLock::ReaderLock lm (master_lock); - return _masters.find (m->id()) != _masters.end(); -} + if ((flags() & Controllable::RealTime) && !AudioEngine::instance()->in_process_thread()) { + /* queue change in RT context */ + std::cerr << "::set_value (" << val << ", " << enum_2_string (gcd) << ") called for " << enum_2_string ((AutomationType) _parameter.type()) << ", queueing in RT context\n"; + _session.set_control (shared_from_this(), val, gcd); + return true; + } -bool -AutomationControl::slaved () const -{ - Glib::Threads::RWLock::ReaderLock lm (master_lock); - return !_masters.empty(); + return false; } -- cgit v1.2.3