X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsolo_control.cc;h=a961fa0b1f7419118a22dde7bfa29fb4e6ea54fa;hb=4bdbe77414b956e27f2c1631e67189c70409a3d1;hp=e8fbb6664372660b94e88b0179d1dff6b034265c;hpb=b2b5c965c854d222f70080de5fcafb10b75ff40b;p=ardour.git diff --git a/libs/ardour/solo_control.cc b/libs/ardour/solo_control.cc index e8fbb66643..a961fa0b1f 100644 --- a/libs/ardour/solo_control.cc +++ b/libs/ardour/solo_control.cc @@ -36,6 +36,7 @@ SoloControl::SoloControl (Session& session, std::string const & name, Soloable& , _self_solo (false) , _soloed_by_others_upstream (0) , _soloed_by_others_downstream (0) + , _transition_into_solo (false) { _list->set_interpolation (Evoral::ControlList::Discrete); /* solo changes must be synchronized by the process cycle */ @@ -48,45 +49,32 @@ SoloControl::set_self_solo (bool yn) DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn)); _self_solo = yn; set_mute_master_solo (); + + _transition_into_solo = 0; + + if (yn) { + if (get_masters_value() == 0) { + _transition_into_solo = 1; + } + } else { + if (get_masters_value() == 0) { + _transition_into_solo = -1; + } + } } void SoloControl::set_mute_master_solo () { - _muteable.mute_master()->set_soloed_by_self (self_soloed()); + _muteable.mute_master()->set_soloed_by_self (self_soloed() || get_masters_value()); if (Config->get_solo_control_is_listen_control()) { _muteable.mute_master()->set_soloed_by_others (false); } else { - _muteable.mute_master()->set_soloed_by_others (soloed_by_others_downstream() || soloed_by_others_upstream()); + _muteable.mute_master()->set_soloed_by_others (soloed_by_others_downstream() || soloed_by_others_upstream() || get_masters_value()); } } -void -SoloControl::master_changed (bool from_self, PBD::Controllable::GroupControlDisposition gcd) -{ - if (_soloable.is_safe() || !_soloable.can_solo()) { - return; - } - - bool master_soloed; - - { - Glib::Threads::RWLock::ReaderLock lm (master_lock); - master_soloed = (bool) get_masters_value_locked (); - } - - /* Master is considered equivalent to an upstream solo control, not - * direct control over self-soloed. - */ - - mod_solo_by_others_upstream (master_soloed ? 1 : -1); - - /* no need to call AutomationControl::master_changed() since it just - emits Changed() which we already did in mod_solo_by_others_upstream() - */ -} - void SoloControl::mod_solo_by_others_downstream (int32_t delta) { @@ -110,6 +98,7 @@ SoloControl::mod_solo_by_others_downstream (int32_t delta) DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream)); set_mute_master_solo (); + _transition_into_solo = 0; Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */ } @@ -164,6 +153,7 @@ SoloControl::mod_solo_by_others_upstream (int32_t delta) } set_mute_master_solo (); + _transition_into_solo = 0; Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */ } @@ -180,16 +170,14 @@ SoloControl::actually_set_value (double val, PBD::Controllable::GroupControlDisp be retrieved by AutomationControl::get_value (), and emits Changed */ - AutomationControl::actually_set_value (val, group_override); - _session.set_dirty (); + SlavableAutomationControl::actually_set_value (val, group_override); } double SoloControl::get_value () const { if (slaved()) { - Glib::Threads::RWLock::ReaderLock lm (master_lock); - return get_masters_value_locked () ? 1.0 : 0.0; + return self_soloed() || get_masters_value (); } if (_list && boost::dynamic_pointer_cast(_list)->automation_playback()) { @@ -197,7 +185,7 @@ SoloControl::get_value () const return AutomationControl::get_value(); } - return self_soloed() ? 1.0 : 0.0; + return soloed(); } void @@ -220,7 +208,7 @@ SoloControl::clear_all_solo_state () _soloed_by_others_downstream = 0; set_self_solo (false); - + _transition_into_solo = 0; /* Session does not need to propagate */ Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */ } @@ -260,3 +248,96 @@ SoloControl::get_state () return node; } + +void +SoloControl::master_changed (bool /*from self*/, GroupControlDisposition, boost::shared_ptr m) +{ + bool send_signal = false; + + _transition_into_solo = 0; + + /* Notice that we call get_boolean_masters() BEFORE we call + * update_boolean_masters_records(), in order to know what + * our master state was BEFORE it gets changed. + */ + + + if (m->get_value()) { + /* this master is now enabled */ + if (!self_soloed() && get_boolean_masters() == 0) { + /* not self-soloed, wasn't soloed by masters before */ + send_signal = true; + _transition_into_solo = 1; + } + } else { + if (!self_soloed() && get_boolean_masters() == 1) { + /* not self-soloed, soloed by just 1 master before */ + _transition_into_solo = -1; + send_signal = true; + } + } + + update_boolean_masters_records (m); + + if (send_signal) { + set_mute_master_solo (); + Changed (false, Controllable::UseGroup); + } + +} + +void +SoloControl::post_add_master (boost::shared_ptr m) +{ + if (m->get_value()) { + + /* boolean masters records are not updated until AFTER + * ::post_add_master() is called, so we can use them to check + * on whether any master was already enabled before the new + * one was added. + */ + + if (!self_soloed() && !get_boolean_masters()) { + _transition_into_solo = 1; + Changed (false, Controllable::NoGroup); + } + } +} + +void +SoloControl::pre_remove_master (boost::shared_ptr m) +{ + if (!m) { + /* null control ptr means we're removing all masters. Nothing + * to do. Changed will be emitted in + * SlavableAutomationControl::clear_masters() + */ + return; + } + + if (m->get_value()) { + if (!self_soloed() && (get_boolean_masters() == 1)) { + /* we're not self-soloed, this master is, and we're + removing + it. SlavableAutomationControl::remove_master() will + ensure that we reset our own value after actually + removing the master, so that our state does not + change (this is a precondition of the + SlavableAutomationControl API). This will emit + Changed(), and we need to make sure that any + listener knows that there has been no transition. + */ + _transition_into_solo = 0; + } else { + _transition_into_solo = 1; + } + } else { + _transition_into_solo = 0; + } +} + +bool +SoloControl::can_solo () const +{ + return _soloable.can_solo (); +}