From 2bc2aea009d967fa23f9b04f0dbd2919e68aecb4 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 10 Jun 2017 14:36:03 +0200 Subject: Implement slaved boolean automation and update mute special-case --- libs/ardour/ardour/mute_control.h | 2 +- libs/ardour/ardour/slavable_automation_control.h | 12 ++-- libs/ardour/automation_control.cc | 1 + libs/ardour/mute_control.cc | 58 ++++++++++++-------- libs/ardour/slavable_automation_control.cc | 70 +++++++++++++++++++++++- libs/evoral/evoral/ControlList.hpp | 2 +- 6 files changed, 116 insertions(+), 29 deletions(-) diff --git a/libs/ardour/ardour/mute_control.h b/libs/ardour/ardour/mute_control.h index aeeccceab6..d54ff2dc34 100644 --- a/libs/ardour/ardour/mute_control.h +++ b/libs/ardour/ardour/mute_control.h @@ -71,7 +71,7 @@ public: void automation_run (framepos_t start, pframes_t nframes); protected: - void master_changed (bool, PBD::Controllable::GroupControlDisposition, boost::shared_ptr); + bool handle_master_change (boost::shared_ptr); void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override); void pre_remove_master (boost::shared_ptr); diff --git a/libs/ardour/ardour/slavable_automation_control.h b/libs/ardour/ardour/slavable_automation_control.h index acb5ad7471..ceafc79193 100644 --- a/libs/ardour/ardour/slavable_automation_control.h +++ b/libs/ardour/ardour/slavable_automation_control.h @@ -27,7 +27,7 @@ namespace ARDOUR { class LIBARDOUR_API SlavableAutomationControl : public AutomationControl { - public: +public: SlavableAutomationControl(ARDOUR::Session&, const Evoral::Parameter& parameter, const ParameterDescriptor& desc, @@ -80,10 +80,10 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl bool find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const; - protected: +protected: class MasterRecord { - public: + public: MasterRecord (boost::shared_ptr gc, double r) : _master (gc) , _yn (false) @@ -101,7 +101,7 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl PBD::ScopedConnection connection; - private: + private: boost::shared_ptr _master; /* holds most recently seen master value for boolean/toggle controls */ bool _yn; @@ -117,6 +117,10 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl void actually_set_value (double value, PBD::Controllable::GroupControlDisposition); void update_boolean_masters_records (boost::shared_ptr); + virtual bool handle_master_change (boost::shared_ptr); + virtual bool boolean_automation_run_locked (framepos_t start, pframes_t len); + bool boolean_automation_run (framepos_t start, pframes_t len); + virtual void master_changed (bool from_self, GroupControlDisposition gcd, boost::shared_ptr); virtual double get_masters_value_locked () const; virtual void pre_remove_master (boost::shared_ptr) {} diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc index 7e74ce7cf7..4e81de8aaf 100644 --- a/libs/ardour/automation_control.cc +++ b/libs/ardour/automation_control.cc @@ -207,6 +207,7 @@ AutomationControl::set_automation_state (AutoState as) alist()->set_automation_state (as); if (_desc.toggled) { + Changed (false, Controllable::NoGroup); // notify slaves, update boolean masters return; // No watch for boolean automation } diff --git a/libs/ardour/mute_control.cc b/libs/ardour/mute_control.cc index 6d5b1e42f0..71bcf3517c 100644 --- a/libs/ardour/mute_control.cc +++ b/libs/ardour/mute_control.cc @@ -52,7 +52,7 @@ MuteControl::post_add_master (boost::shared_ptr m) if (!muted_by_self() && !get_boolean_masters()) { _muteable.mute_master()->set_muted_by_masters (true); - Changed (false, Controllable::NoGroup); + Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ } } } @@ -67,9 +67,10 @@ MuteControl::pre_remove_master (boost::shared_ptr m) return; } - if (m->get_value()) { - if (!muted_by_self() && (get_boolean_masters() == 1)) { - Changed (false, Controllable::NoGroup); + if (m->get_value() && get_boolean_masters() == 1) { + _muteable.mute_master()->set_muted_by_masters (false); + if (!muted_by_self()) { + Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ } } } @@ -89,31 +90,33 @@ MuteControl::actually_set_value (double val, Controllable::GroupControlDispositi SlavableAutomationControl::actually_set_value (val, gcd); } -void -MuteControl::master_changed (bool self_change, Controllable::GroupControlDisposition gcd, boost::shared_ptr m) +bool +MuteControl::handle_master_change (boost::shared_ptr m) { bool send_signal = false; boost::shared_ptr mc = boost::dynamic_pointer_cast (m); + if (!mc) { + return false; + } if (m->get_value()) { /* this master is now enabled */ - if (!muted_by_self() && get_boolean_masters() == 0) { + if (get_boolean_masters() == 0) { _muteable.mute_master()->set_muted_by_masters (true); - send_signal = true; + if (!muted_by_self()) { + send_signal = true; + } } } else { /* this master is disabled and there was only 1 enabled before */ - if (!muted_by_self() && get_boolean_masters() == 1) { + if (get_boolean_masters() == 1) { _muteable.mute_master()->set_muted_by_masters (false); - send_signal = true; + if (!muted_by_self()) { + send_signal = true; + } } } - - update_boolean_masters_records (m); - - if (send_signal) { - Changed (false, Controllable::NoGroup); - } + return send_signal; } double @@ -177,19 +180,30 @@ MuteControl::muted_by_others_soloing () const } void -MuteControl::automation_run (framepos_t start, pframes_t) +MuteControl::automation_run (framepos_t start, pframes_t len) { - if (!list() || !automation_playback()) { + boolean_automation_run (start, len); + + if (muted_by_masters ()) { + // already muted, no need to check further return; } - bool valid = false; - const float mute = list()->rt_safe_eval (start, valid); + bool valid = false; + bool mute = false; + + if (list() && automation_playback()) { + mute = list()->rt_safe_eval (start, valid) >= 0.5; + } + + if (!valid) { + return; + } - if (mute >= 0.5 && !muted()) { + if (mute && !muted()) { set_value_unchecked (1.0); // mute Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ - } else if (mute < 0.5 && muted ()) { + } else if (!mute && muted()) { set_value_unchecked (0.0); // unmute Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ } diff --git a/libs/ardour/slavable_automation_control.cc b/libs/ardour/slavable_automation_control.cc index c912d16370..8a7a8ba00f 100644 --- a/libs/ardour/slavable_automation_control.cc +++ b/libs/ardour/slavable_automation_control.cc @@ -312,8 +312,16 @@ SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr m) { + Glib::Threads::RWLock::ReaderLock lm (master_lock, Glib::Threads::TRY_LOCK); + if (!lm.locked ()) { + /* boolean_automation_run_locked () special case */ + return; + } + bool send_signal = handle_master_change (m); update_boolean_masters_records (m); - Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ + if (send_signal) { + Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ + } } void @@ -450,6 +458,66 @@ SlavableAutomationControl::find_next_event_locked (double now, double end, Evora return rv; } +bool +SlavableAutomationControl::handle_master_change (boost::shared_ptr) +{ + return true; // emit Changed +} + +bool +SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len) +{ + bool rv = false; + if (!_desc.toggled) { + return false; + } + for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) { + boost::shared_ptr ac (mr->second.master()); + if (!ac->automation_playback ()) { + continue; + } + if (!ac->toggled ()) { + continue; + } + boost::shared_ptr sc = boost::dynamic_pointer_cast(ac); + if (sc) { + rv |= sc->boolean_automation_run (start, len); + } + boost::shared_ptr alist (ac->list()); + bool valid = false; + const bool yn = alist->rt_safe_eval (start, valid) >= 0.5; + if (!valid) { + continue; + } + /* ideally we'd call just master_changed() which calls update_boolean_masters_records() + * but that takes the master_lock, which is already locked */ + if (mr->second.yn() != yn) { + rv |= handle_master_change (ac); + mr->second.set_yn (yn); + /* notify the GUI, without recursion: + * master_changed() above will ignore the change if the lock is held. + */ + ac->set_value_unchecked (yn ? 1. : 0.); + ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ + } + } + return rv; +} + +bool +SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len) +{ + bool change = false; + { + Glib::Threads::RWLock::ReaderLock lm (master_lock); + change = boolean_automation_run_locked (start, len); + } + if (change) { + Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ + } + return change; +} + bool SlavableAutomationControl::slaved_to (boost::shared_ptr m) const { diff --git a/libs/evoral/evoral/ControlList.hpp b/libs/evoral/evoral/ControlList.hpp index b58c186c21..2a80ad5bd4 100644 --- a/libs/evoral/evoral/ControlList.hpp +++ b/libs/evoral/evoral/ControlList.hpp @@ -225,7 +225,7 @@ public: * @param ok boolean reference if returned value is valid * @returns parameter value */ - double rt_safe_eval (double where, bool& ok) { + double rt_safe_eval (double where, bool& ok) const { Glib::Threads::RWLock::ReaderLock lm (_lock, Glib::Threads::TRY_LOCK); -- cgit v1.2.3