summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-06-10 14:36:03 +0200
committerRobin Gareus <robin@gareus.org>2017-06-10 14:38:21 +0200
commit2bc2aea009d967fa23f9b04f0dbd2919e68aecb4 (patch)
tree0a55e19ae21041caf0c543982c1780bf4a8f972e
parent50c54250040509080f7686b64739ef94e6d29e51 (diff)
Implement slaved boolean automation and update mute special-case
-rw-r--r--libs/ardour/ardour/mute_control.h2
-rw-r--r--libs/ardour/ardour/slavable_automation_control.h12
-rw-r--r--libs/ardour/automation_control.cc1
-rw-r--r--libs/ardour/mute_control.cc58
-rw-r--r--libs/ardour/slavable_automation_control.cc70
-rw-r--r--libs/evoral/evoral/ControlList.hpp2
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<AutomationControl>);
+ bool handle_master_change (boost::shared_ptr<AutomationControl>);
void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override);
void pre_remove_master (boost::shared_ptr<AutomationControl>);
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<AutomationControl> 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<AutomationControl> _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<AutomationControl>);
+ virtual bool handle_master_change (boost::shared_ptr<AutomationControl>);
+ 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<AutomationControl>);
virtual double get_masters_value_locked () const;
virtual void pre_remove_master (boost::shared_ptr<AutomationControl>) {}
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<AutomationControl> 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<AutomationControl> 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<AutomationControl> m)
+bool
+MuteControl::handle_master_change (boost::shared_ptr<AutomationControl> m)
{
bool send_signal = false;
boost::shared_ptr<MuteControl> mc = boost::dynamic_pointer_cast<MuteControl> (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<Aut
void
SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> 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
@@ -451,6 +459,66 @@ SlavableAutomationControl::find_next_event_locked (double now, double end, Evora
}
bool
+SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
+{
+ 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<AutomationControl> ac (mr->second.master());
+ if (!ac->automation_playback ()) {
+ continue;
+ }
+ if (!ac->toggled ()) {
+ continue;
+ }
+ boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
+ if (sc) {
+ rv |= sc->boolean_automation_run (start, len);
+ }
+ boost::shared_ptr<const Evoral::ControlList> 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<AutomationControl> m) const
{
Glib::Threads::RWLock::ReaderLock lm (master_lock);
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);