show VCA master mute state in RouteUI, even if Config->get_show_solo_mutes() is false...
[ardour.git] / libs / ardour / route_controls.cc
index 71e44ef91c13431ae3444282715cb6c471bb7ac0..ad5408d06d416765628c4b0fe47e1097b36019a0 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 
 #include "ardour/automation_control.h"
+#include "ardour/parameter_descriptor.h"
 #include "ardour/route.h"
 #include "ardour/session.h"
 
@@ -40,13 +41,11 @@ Route::set_control (AutomationType type, double val, PBD::Controllable::GroupCon
        case GainAutomation:
                /* route must mediate group control */
                set_gain (val, group_override);
-               return;
                break;
 
        case TrimAutomation:
                /* route must mediate group control */
                set_trim (val, group_override);
-               return;
                break;
 
        case RecEnableAutomation:
@@ -54,7 +53,6 @@ Route::set_control (AutomationType type, double val, PBD::Controllable::GroupCon
                rl.reset (new RouteList);
                rl->push_back (shared_from_this());
                _session.set_record_enabled (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
-               return;
                break;
 
        case SoloAutomation:
@@ -64,17 +62,15 @@ Route::set_control (AutomationType type, double val, PBD::Controllable::GroupCon
                if (Config->get_solo_control_is_listen_control()) {
                        _session.set_listen (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
                } else {
-                       _session.set_solo (rl, val >= 0.5 ? true : false);
+                       _session.set_solo (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
                }
-
-               return;
                break;
 
        case MuteAutomation:
                /* session must mediate group control */
                rl.reset (new RouteList);
                rl->push_back (shared_from_this());
-               _session.set_mute (rl, !muted(), Session::rt_cleanup, group_override);
+               _session.set_mute (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
                return;
                break;
 
@@ -98,6 +94,26 @@ Route::RouteAutomationControl::RouteAutomationControl (const std::string& name,
 {
 }
 
+double
+Route::BooleanRouteAutomationControl::get_masters_value_locked () const
+{
+       /* masters (read/write) lock must be held */
+
+       /* if any master is enabled (val > 0.0) then we consider the master
+          value to be 1.0
+       */
+
+       for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
+               if (mr->second.master()->get_value()) {
+                       return 1.0;
+               }
+       }
+
+       return 0.0;
+}
+
+
+
 Route::GainControllable::GainControllable (Session& s, AutomationType atype, boost::shared_ptr<Route> r)
        : GainControl (s, Evoral::Parameter(atype))
        , _route (r)
@@ -106,13 +122,38 @@ Route::GainControllable::GainControllable (Session& s, AutomationType atype, boo
 }
 
 Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
-       : RouteAutomationControl (name, SoloAutomation, boost::shared_ptr<AutomationList>(), r)
+       : BooleanRouteAutomationControl (name, SoloAutomation, boost::shared_ptr<AutomationList>(), r)
 {
        boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloAutomation)));
        gl->set_interpolation(Evoral::ControlList::Discrete);
        set_list (gl);
 }
 
+void
+Route::SoloControllable::master_changed (bool from_self, PBD::Controllable::GroupControlDisposition gcd)
+{
+       boost::shared_ptr<Route> r = _route.lock ();
+
+       if (!r) {
+               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.
+        */
+
+       r->mod_solo_by_others_upstream (master_soloed ? 1 : -1);
+
+       AutomationControl::master_changed (false, gcd);
+}
+
 void
 Route::SoloControllable::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
 {
@@ -124,22 +165,11 @@ Route::SoloControllable::set_value (double val, PBD::Controllable::GroupControlD
 void
 Route::SoloControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
 {
-       const bool bval = ((val >= 0.5) ? true : false);
-
-       boost::shared_ptr<RouteList> rl (new RouteList);
-
        boost::shared_ptr<Route> r = _route.lock ();
        if (!r) {
                return;
        }
-
-       rl->push_back (r);
-
-       if (Config->get_solo_control_is_listen_control()) {
-               _session.set_listen (rl, bval, Session::rt_cleanup, group_override);
-       } else {
-               _session.set_solo (rl, bval, Session::rt_cleanup, group_override);
-       }
+       r->set_control (SoloAutomation, val, group_override);
 }
 
 void
@@ -153,7 +183,18 @@ Route::SoloControllable::set_value_unchecked (double val)
 double
 Route::SoloControllable::get_value () const
 {
+       if (slaved()) {
+               Glib::Threads::RWLock::ReaderLock lm (master_lock);
+               return get_masters_value_locked () ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
+       }
+
+       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
+               // Playing back automation, get the value from the list
+               return AutomationControl::get_value();
+       }
+
        boost::shared_ptr<Route> r = _route.lock ();
+
        if (!r) {
                return 0;
        }
@@ -166,7 +207,7 @@ Route::SoloControllable::get_value () const
 }
 
 Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr<Route> r)
-       : RouteAutomationControl (name, MuteAutomation, boost::shared_ptr<AutomationList>(), r)
+       : BooleanRouteAutomationControl (name, MuteAutomation, boost::shared_ptr<AutomationList>(), r)
        , _route (r)
 {
        boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
@@ -182,6 +223,7 @@ Route::MuteControllable::set_superficial_value(bool muted)
 
        const bool to_list = _list && ((AutomationList*)_list.get ())->automation_write ();
        const double where = _session.audible_frame ();
+
        if (to_list) {
                /* Note that we really need this:
                 *  if (as == Touch && _list->in_new_write_pass ()) {
@@ -198,6 +240,24 @@ Route::MuteControllable::set_superficial_value(bool muted)
        Control::set_double (muted, where, to_list);
 }
 
+void
+Route::MuteControllable::master_changed (bool from_self, PBD::Controllable::GroupControlDisposition gcd)
+{
+       bool master_muted;
+
+       {
+               Glib::Threads::RWLock::ReaderLock lm (master_lock);
+               master_muted = (bool) get_masters_value_locked ();
+       }
+
+       boost::shared_ptr<Route> r (_route.lock());
+       if (r) {
+               r->mute_master()->mod_muted_by_others (master_muted ? 1 : -1);
+       }
+
+       AutomationControl::master_changed (false, gcd);
+}
+
 void
 Route::MuteControllable::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
 {
@@ -216,29 +276,31 @@ Route::MuteControllable::set_value_unchecked (double val)
 void
 Route::MuteControllable::_set_value (double val, Controllable::GroupControlDisposition group_override)
 {
-       const bool bval = ((val >= 0.5) ? true : false);
-
        boost::shared_ptr<Route> r = _route.lock ();
+
        if (!r) {
                return;
        }
 
        if (_list && ((AutomationList*)_list.get())->automation_playback()) {
                // Set superficial/automation value to drive controller (and possibly record)
+               const bool bval = ((val >= 0.5) ? true : false);
                set_superficial_value (bval);
                // Playing back automation, set route mute directly
                r->set_mute (bval, Controllable::NoGroup);
        } else {
-               // Set from user, queue mute event
-               boost::shared_ptr<RouteList> rl (new RouteList);
-               rl->push_back (r);
-               _session.set_mute (rl, bval, Session::rt_cleanup, group_override);
+               r->set_control (MuteAutomation, val, group_override);
        }
 }
 
 double
 Route::MuteControllable::get_value () const
 {
+       if (slaved()) {
+               Glib::Threads::RWLock::ReaderLock lm (master_lock);
+               return get_masters_value_locked () ? 1.0 : 0.0;
+       }
+
        if (_list && ((AutomationList*)_list.get())->automation_playback()) {
                // Playing back automation, get the value from the list
                return AutomationControl::get_value();
@@ -246,11 +308,12 @@ Route::MuteControllable::get_value () const
 
        // Not playing back automation, get the actual route mute value
        boost::shared_ptr<Route> r = _route.lock ();
-       return (r && r->muted()) ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
+       return (r && r->muted()) ? 1.0 : 0.0;
 }
 
 Route::PhaseControllable::PhaseControllable (std::string name, boost::shared_ptr<Route> r)
-       : RouteAutomationControl (name, PhaseAutomation, boost::shared_ptr<AutomationList>(), r)
+       : BooleanRouteAutomationControl (name, PhaseAutomation, boost::shared_ptr<AutomationList>(), r)
+       , _current_phase (0)
 {
        boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(PhaseAutomation)));
        gl->set_interpolation(Evoral::ControlList::Discrete);
@@ -274,6 +337,9 @@ double
 Route::PhaseControllable::get_value () const
 {
        boost::shared_ptr<Route> r = _route.lock ();
+       if (!r) {
+               return 0.0;
+       }
        return (double) r->phase_invert (_current_phase);
 }
 
@@ -289,3 +355,77 @@ Route::PhaseControllable::channel () const
        return _current_phase;
 }
 
+Route::SoloIsolateControllable::SoloIsolateControllable (std::string name, boost::shared_ptr<Route> r)
+       : BooleanRouteAutomationControl (name, SoloIsolateAutomation, boost::shared_ptr<AutomationList>(), r)
+{
+       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloIsolateAutomation)));
+       gl->set_interpolation(Evoral::ControlList::Discrete);
+       set_list (gl);
+}
+
+
+double
+Route::SoloIsolateControllable::get_value () const
+{
+       boost::shared_ptr<Route> r = _route.lock ();
+       if (!r) {
+               return 0.0; /* "false" */
+       }
+
+       return r->solo_isolated() ? 1.0 : 0.0;
+}
+
+void
+Route::SoloIsolateControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
+{
+       _set_value (val, gcd);
+}
+
+void
+Route::SoloIsolateControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition)
+{
+       boost::shared_ptr<Route> r = _route.lock ();
+       if (!r) {
+               return;
+       }
+
+       /* no group semantics yet */
+       r->set_solo_isolated (val >= 0.5 ? true : false);
+}
+
+Route::SoloSafeControllable::SoloSafeControllable (std::string name, boost::shared_ptr<Route> r)
+       : BooleanRouteAutomationControl (name, SoloSafeAutomation, boost::shared_ptr<AutomationList>(), r)
+{
+       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloSafeAutomation)));
+       gl->set_interpolation(Evoral::ControlList::Discrete);
+       set_list (gl);
+}
+
+void
+Route::SoloSafeControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
+{
+       _set_value (val, gcd);
+}
+
+void
+Route::SoloSafeControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition)
+{
+       boost::shared_ptr<Route> r = _route.lock ();
+       if (!r) {
+               return;
+       }
+
+       /* no group semantics yet */
+       r->set_solo_safe (val >= 0.5 ? true : false);
+}
+
+double
+Route::SoloSafeControllable::get_value () const
+{
+       boost::shared_ptr<Route> r = _route.lock ();
+       if (!r) {
+               return 0.0; /* "false" */
+       }
+
+       return r->solo_safe() ? 1.0 : 0.0;
+}