mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 08:14:58 +01:00
Implement slaved boolean automation and update mute special-case
This commit is contained in:
parent
50c5425004
commit
2bc2aea009
6 changed files with 116 additions and 29 deletions
|
|
@ -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>);
|
||||
|
|
|
|||
|
|
@ -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>) {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (mute >= 0.5 && !muted()) {
|
||||
if (list() && automation_playback()) {
|
||||
mute = list()->rt_safe_eval (start, valid) >= 0.5;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -450,6 +458,66 @@ SlavableAutomationControl::find_next_event_locked (double now, double end, Evora
|
|||
return rv;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue