a variety of changes that get closer to correctly functioning behaviour for VCA solo...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 15 Apr 2016 04:38:03 +0000 (00:38 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 May 2016 19:30:41 +0000 (15:30 -0400)
13 files changed:
gtk2_ardour/route_ui.cc
gtk2_ardour/vca_master_strip.cc
libs/ardour/ardour/automation_control.h
libs/ardour/ardour/gain_control.h
libs/ardour/ardour/mute_control.h
libs/ardour/ardour/mute_master.h
libs/ardour/ardour/route.h
libs/ardour/gain_control.cc
libs/ardour/mute_control.cc
libs/ardour/mute_master.cc
libs/ardour/route.cc
libs/ardour/slavable_automation_control.cc
libs/ardour/solo_control.cc

index 91b14d9c7868075681198060b9a0c1d69c60b751..3f00966c31eee03daa2bae6e10978b3b488a4f35 100644 (file)
@@ -415,7 +415,7 @@ RouteUI::mute_press (GdkEventButton* ev)
                                }
 
                                DisplaySuspender ds;
-                               _session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
+                               _session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
 
                        } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
 
@@ -444,7 +444,7 @@ RouteUI::mute_press (GdkEventButton* ev)
                                        }
 
                                        DisplaySuspender ds;
-                                       _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::InverseGroup);
+                                       _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
                                }
 
                        } else {
@@ -458,7 +458,7 @@ RouteUI::mute_press (GdkEventButton* ev)
                                        _mute_release->routes = rl;
                                }
 
-                               _session->set_control (_route->mute_control(), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
+                               _session->set_control (_route->mute_control(), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
 
                        }
                }
@@ -1225,10 +1225,12 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
 
        if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
 
-               if (r->muted ()) {
+               std::cerr << r->name() << " self " << r->mute_control()->muted_by_self() << " others " << r->muted_by_others() << " soloing " << r->muted_by_others_soloing() << std::endl;
+
+               if (r->mute_control()->muted_by_self ()) {
                        /* full mute */
                        return Gtkmm2ext::ExplicitActive;
-               } else if (r->muted_by_others_soloing () || r->mute_control()->get_masters_value()) {
+               } else if (r->muted_by_others_soloing () || r->muted_by_others()) {
                        /* this will reflect both solo mutes AND master mutes */
                        return Gtkmm2ext::ImplicitActive;
                } else {
@@ -1238,15 +1240,11 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
 
        } else {
 
-               if (r->muted()) {
+               if (r->mute_control()->muted_by_self()) {
                        /* full mute */
                        return Gtkmm2ext::ExplicitActive;
                } else if (r->muted_by_others()) {
-                       /* note the direct use of MuteMaster API here. We are
-                          not interested in showing
-                          others-soloed-so-this-muted status in this
-                          conditional branch.
-                       */
+                       /* this shows only master mutes, not mute-by-others-soloing */
                        return Gtkmm2ext::ImplicitActive;
                } else {
                        /* no mute at all */
index 1b1572cf7402d5a9a006bb93ef204e36e2ea5a9e..6f43228424b360191393f3f4d932bb7e0e2df13b 100644 (file)
@@ -131,6 +131,8 @@ VCAMasterStrip::VCAMasterStrip (Session* s, boost::shared_ptr<VCA> v)
        _vca->solo_control()->Changed.connect (vca_connections, invalidator (*this), boost::bind (&VCAMasterStrip::solo_changed, this), gui_context());
        _vca->mute_control()->Changed.connect (vca_connections, invalidator (*this), boost::bind (&VCAMasterStrip::mute_changed, this), gui_context());
 
+       /* only need to connect to one of these to update VCA status */
+
        _vca->gain_control()->MasterStatusChange.connect (vca_connections,
                                                  invalidator (*this),
                                                  boost::bind (&VCAMasterStrip::update_vca_display, this),
@@ -198,14 +200,20 @@ VCAMasterStrip::set_selected (bool yn)
 bool
 VCAMasterStrip::solo_release (GdkEventButton*)
 {
-       _vca->solo_control()->set_value (_vca->solo_control()->get_value() ? 0.0 : 1.0, Controllable::NoGroup);
+       /* We use NoGroup because VCA controls are never part of a group. This
+          is redundant, but clear.
+       */
+       _vca->solo_control()->set_value (_vca->solo_control()->self_soloed() ? 0.0 : 1.0, Controllable::NoGroup);
        return true;
 }
 
 bool
 VCAMasterStrip::mute_release (GdkEventButton*)
 {
-       _vca->mute_control()->set_value (_vca->mute_control()->get_value() ? 0.0 : 1.0, Controllable::NoGroup);
+       /* We use NoGroup because VCA controls are never part of a group. This
+          is redundant, but clear.
+       */
+       _vca->mute_control()->set_value (_vca->mute_control()->muted_by_self() ? 0.0 : 1.0, Controllable::NoGroup);
        return true;
 }
 
@@ -229,8 +237,11 @@ VCAMasterStrip::set_solo_text ()
 void
 VCAMasterStrip::mute_changed ()
 {
-       if (_vca->mute_control()->muted()) {
+       std::cerr << "Mute changed for " << _vca->number() << std::endl;
+       if (_vca->mute_control()->muted_by_self()) {
                mute_button.set_active_state (ExplicitActive);
+       } else if (_vca->mute_control()->muted_by_others()) {
+               mute_button.set_active_state (ImplicitActive);
        } else {
                mute_button.set_active_state (Gtkmm2ext::Off);
        }
@@ -239,7 +250,7 @@ VCAMasterStrip::mute_changed ()
 void
 VCAMasterStrip::solo_changed ()
 {
-       if (_vca->solo_control()->soloed()) {
+       if (_vca->solo_control()->soloed() || _vca->solo_control()->get_masters_value()) {
                solo_button.set_active_state (ExplicitActive);
        } else {
                solo_button.set_active_state (Gtkmm2ext::Off);
@@ -257,10 +268,14 @@ VCAMasterStrip::vca_menu_toggle (CheckMenuItem* menuitem, uint32_t n)
                        vca_unassign ();
                } else {
                        _vca->gain_control()->remove_master (vca->gain_control());
+                       _vca->solo_control()->remove_master (vca->solo_control());
+                       _vca->mute_control()->remove_master (vca->mute_control());
                }
        } else {
                if (vca) {
                        _vca->gain_control()->add_master (vca->gain_control());
+                       _vca->mute_control()->add_master (vca->mute_control());
+                       _vca->solo_control()->add_master (vca->solo_control());
                }
        }
 }
@@ -269,6 +284,8 @@ void
 VCAMasterStrip::vca_unassign ()
 {
        _vca->gain_control()->clear_masters ();
+       _vca->solo_control()->clear_masters ();
+       _vca->mute_control()->clear_masters ();
 }
 
 bool
index f576cb52c0285da3977a64de611d40e4da9f07a7..6195f90a683036dae0be62f8dc010075c5b95617 100644 (file)
@@ -152,8 +152,6 @@ class SlavableAutomationControl : public AutomationControl
                          boost::shared_ptr<ARDOUR::AutomationList> l=boost::shared_ptr<ARDOUR::AutomationList>(),
                          const std::string&                        name="");
 
-       ~SlavableAutomationControl ();
-
        double get_value () const;
 
        void add_master (boost::shared_ptr<AutomationControl>);
@@ -200,7 +198,7 @@ class SlavableAutomationControl : public AutomationControl
        virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
        virtual double get_masters_value_locked () const;
        double get_value_locked() const;
-
+       void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
 };
 
 
index f68ec00452513423dbeada87e965fd4086ddf272..32d1ad1229a1c81ac4eb916b0396bed4a330dd54 100644 (file)
@@ -59,8 +59,6 @@ class LIBARDOUR_API GainControl : public SlavableAutomationControl {
 
        void vcas_loaded();
        void recompute_masters_ratios (double val);
-
-       void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
 };
 
 } /* namespace */
index 8e5e3fd27ad5d2c9d08e872499dcde06abe841d8..f7a7814f0059fa6319f8215c987dbb18a97499c3 100644 (file)
@@ -53,6 +53,7 @@ class LIBARDOUR_API MuteControl : public SlavableAutomationControl
         */
 
        bool muted () const;
+       bool muted_by_self () const;
 
        bool muted_by_others_soloing () const;
        bool muted_by_others () const;
@@ -61,6 +62,7 @@ class LIBARDOUR_API MuteControl : public SlavableAutomationControl
        MuteMaster::MutePoint mute_points () const;
 
   protected:
+       void master_changed (bool, PBD::Controllable::GroupControlDisposition);
        void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override);
 
   private:
index d147a587716d8a349c51272043b58d785ee16b0a..d8b2bf0021639ba63bc9b77ebd1dc1357a09aaf5 100644 (file)
@@ -70,7 +70,7 @@ class LIBARDOUR_API MuteMaster : public SessionHandleRef, public PBD::Stateful
        void set_solo_ignore (bool yn) { _solo_ignore = yn; }
 
        void mod_muted_by_others (int32_t delta);
-       bool muted_by_others () const { return _muted_by_others; }
+       int32_t muted_by_others () const { return _muted_by_others; }
 
        PBD::Signal0<void> MutePointChanged;
 
index 6c0380963df8f5210dab3b0ea6cebc6205e78177..9f66b95b6cb6574ec8f7fd08e6072b20f8f98b82 100644 (file)
@@ -460,8 +460,9 @@ public:
 
        bool can_be_muted_by_others () const { return !is_master(); }
        bool muted () const { return _mute_control->muted(); }
+       bool muted_by_others () const { return _mute_control->muted_by_others(); }
+       bool muted_by_self () const { return _mute_control->muted_by_self(); }
        bool muted_by_others_soloing () const;
-       bool muted_by_others () const;
 
        boost::shared_ptr<SoloIsolateControl> solo_isolate_control() const {
                return _solo_isolate_control;
index 508ddd12a6ca100eb2c587997bfbac51866e3919..3ffeb057da8fc1d0cc26a128375b15998470a3f7 100644 (file)
@@ -43,28 +43,6 @@ GainControl::GainControl (Session& session, const Evoral::Parameter &param, boos
        range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
 }
 
-void
-GainControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
-{
-       val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
-
-       {
-               Glib::Threads::RWLock::WriterLock lm (master_lock);
-
-               if (!_masters.empty()) {
-                       recompute_masters_ratios (val);
-               }
-       }
-
-       /* this sets the Evoral::Control::_user_value for us, which will
-          be retrieved by AutomationControl::get_value ()
-       */
-
-       AutomationControl::actually_set_value (val, group_override);
-
-       _session.set_dirty ();
-}
-
 double
 GainControl::internal_to_interface (double v) const
 {
index a639cbda7a848f153660659497e78b0f9781d75b..8d35b024458730c5e9ceb83eee860b269dce4299 100644 (file)
@@ -42,7 +42,7 @@ MuteControl::MuteControl (Session& session, std::string const & name, Muteable&
 void
 MuteControl::actually_set_value (double val, Controllable::GroupControlDisposition gcd)
 {
-       if (muted() != bool (val)) {
+       if (muted_by_self() != bool (val)) {
                _muteable.mute_master()->set_muted_by_self (val);
 
                /* allow the Muteable to respond to the mute change
@@ -54,12 +54,63 @@ MuteControl::actually_set_value (double val, Controllable::GroupControlDispositi
        AutomationControl::actually_set_value (val, gcd);
 }
 
+void
+MuteControl::master_changed (bool self_change, Controllable::GroupControlDisposition gcd)
+{
+       double m = get_masters_value ();
+       const int32_t old_muted_by_others = _muteable.mute_master()->muted_by_others ();
+       std::cerr << "master " << (self_change ? " self " : " not-self") << " changed to " << m << " old others = " << old_muted_by_others << std::endl;
+
+       _muteable.mute_master()->mod_muted_by_others (m ? 1 : -1);
+
+       if (m) {
+               /* master(s) are now muted. If we are self-muted, this
+                  doesn't change our status. If we are not self-muted,
+                  then it changes our status if either:
+
+                  - the master had its own self-muted status changed OR
+                  - the total number of masters that are muted used to be zero
+               */
+
+               if (!muted_by_self()) {
+                       if (self_change || old_muted_by_others == 0) {
+                               /* note false as the first argument - our own
+                                  value was not changed
+                               */
+                               Changed (false, gcd);
+                       } else {
+                               cerr << " no Change signal\n";
+                       }
+               } else {
+                       cerr << "muted by self, not relevant\n";
+               }
+       } else {
+               /* no master(s) are now muted. If we are self-muted, this
+                  doesn't change our status. If we are not self-muted,
+                  then it changes our status if either:
+
+                  - the master had its own self-muted status changed OR
+                  - the total number of masters that are muted used to be non-zero
+               */
+
+               if (!muted_by_self()) {
+                       if (self_change || old_muted_by_others != 0) {
+                               Changed (false, gcd);
+                       } else {
+                               cerr << " No change signal\n";
+                       }
+               } else {
+                       cerr << "muted by self, not relevant\n";
+               }
+       }
+}
+
 double
 MuteControl::get_value () const
 {
-       if (slaved()) {
+       if (slaved ()) {
                Glib::Threads::RWLock::ReaderLock lm (master_lock);
-               return get_masters_value_locked () ? 1.0 : 0.0;
+               return get_masters_value_locked ();
        }
 
        if (_list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback()) {
@@ -89,6 +140,12 @@ MuteControl::mute_points () const
 
 bool
 MuteControl::muted () const
+{
+       return _muteable.mute_master()->muted_by_self() || _muteable.mute_master()->muted_by_others();
+}
+
+bool
+MuteControl::muted_by_self () const
 {
        return _muteable.mute_master()->muted_by_self();
 }
@@ -96,5 +153,5 @@ MuteControl::muted () const
 bool
 MuteControl::muted_by_others () const
 {
-       return _muteable.mute_master()->muted_by_others () || get_masters_value();
+       return _muteable.mute_master()->muted_by_others ();
 }
index 6817374dc7ad18c0b76ac604e2771110b1e0241e..c13131c11b324f5d6bf1a220b600697102ccbca4 100644 (file)
@@ -173,4 +173,5 @@ void
 MuteMaster::mod_muted_by_others (int32_t delta)
 {
        _muted_by_others = max (0, _muted_by_others + delta);
+       std::cerr << this << " mod others by " << delta << " to get " << _muted_by_others << endl;
 }
index a45e30a91b4bab0ddf8c4d9255047bc5416a055d..7da7e42abf6953ea43df120a2a489f2a14b8055b 100644 (file)
@@ -5481,27 +5481,13 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
 bool
 Route::muted_by_others_soloing () const
 {
-       // This method is only used by route_ui for display state.
-       // The DSP version is MuteMaster::muted_by_others_at()
-
        if (!can_be_muted_by_others ()) {
                return false;
        }
 
-       return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
-}
-
-bool
-Route::muted_by_others () const
-{
-       // This method is only used by route_ui for display state.
-       // The DSP version is MuteMaster::muted_by_others_at()
-
-       if (!can_be_muted_by_others()) {
-               return false;
-       }
+       /* XXX something needed here re: mute-overrides-solo */
 
-       return _mute_master->muted_by_others();
+       return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
 }
 
 void
index 07a2d5633a70779b0b15986b3acaf6455b150409..624fa484caf973d943e016ba27091f650172bd6b 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __libardour_slavable_automation_control_h__
 #define __libardour_slavable_automation_control_h__
 
+#include "pbd/enumwriter.h"
+
 #include "ardour/automation_control.h"
 #include "ardour/session.h"
 
@@ -35,29 +37,26 @@ SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
 {
 }
 
-SlavableAutomationControl::~SlavableAutomationControl ()
-{
-
-}
-
 double
 SlavableAutomationControl::get_masters_value_locked () const
 {
-       gain_t v = _desc.normal;
+       double v = _desc.normal;
 
-       for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
-               if (_desc.toggled) {
-                       /* if any master is enabled, the slaves are too */
+       if (_desc.toggled) {
+               for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
                        if (mr->second.master()->get_value()) {
                                return _desc.upper;
                        }
-               } else {
-                       /* get current master value, scale by our current ratio with that master */
-                       v *= mr->second.master()->get_value () * mr->second.ratio();
                }
+               return _desc.lower;
+       }
+
+       for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
+               /* get current master value, scale by our current ratio with that master */
+               v *= mr->second.master()->get_value () * mr->second.ratio();
        }
 
-       return min (_desc.upper, v);
+       return min ((double) _desc.upper, v);
 }
 
 double
@@ -69,6 +68,16 @@ SlavableAutomationControl::get_value_locked() const
                return Control::get_double (false, _session.transport_frame());
        }
 
+       if (_desc.toggled) {
+               /* for boolean/toggle controls, if this slave OR any master is
+                * enabled, this slave is enabled. So check our own value
+                * first, because if we are enabled, we can return immediately.
+                */
+               if (Control::get_double (false, _session.transport_frame())) {
+                       return _desc.upper;
+               }
+       }
+
        return get_masters_value_locked ();
 }
 
@@ -86,6 +95,27 @@ SlavableAutomationControl::get_value() const
        }
 }
 
+void
+SlavableAutomationControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
+{
+       val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
+
+       {
+               Glib::Threads::RWLock::WriterLock lm (master_lock);
+
+               if (!_masters.empty()) {
+                       recompute_masters_ratios (val);
+               }
+       }
+
+       /* this sets the Evoral::Control::_user_value for us, which will
+          be retrieved by AutomationControl::get_value ()
+       */
+       AutomationControl::actually_set_value (val, group_override);
+
+       _session.set_dirty ();
+}
+
 void
 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
 {
@@ -103,7 +133,9 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
 
                if (res.second) {
 
-                       recompute_masters_ratios (current_value);
+                       if (_desc.toggled) {
+                               recompute_masters_ratios (current_value);
+                       }
 
                        /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
                           avoiding holding a reference to the control in the binding
@@ -145,13 +177,17 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
 void
 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd)
 {
-       cerr << this << enum_2_string ((AutomationType)_parameter.type()) << " master changed, relay changed along\n";
-
        /* our value has (likely) changed, but not because we were
         * modified. Just the master.
         */
 
-       Changed (false, gcd); /* EMIT SIGNAL */
+       /* propagate master state into our own control so that if we stop
+        * being slaved, our value doesn't change, and propagate to any
+        * group this control is part of.
+        */
+
+       cerr << this << ' ' << enum_2_string ((AutomationType) _parameter.type()) << " pass along " << get_masters_value() << " from master to group\n";
+       actually_set_value (get_masters_value(), Controllable::UseGroup);
 }
 
 void
@@ -168,6 +204,7 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
 {
        double current_value;
        double new_value;
+       bool masters_left;
        Masters::size_type erased = 0;
 
        {
@@ -177,6 +214,7 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
                if (erased) {
                        recompute_masters_ratios (current_value);
                }
+               masters_left = _masters.size ();
                new_value = get_value_locked ();
        }
 
@@ -185,7 +223,12 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
        }
 
        if (new_value != current_value) {
-               Changed (false, Controllable::NoGroup);
+               if (masters_left == 0) {
+                       /* no masters left, make sure we keep the same value
+                          that we had before.
+                       */
+                       actually_set_value (current_value, Controllable::UseGroup);
+               }
        }
 }
 
index 936cc2263a50ca80f5c59a8d2a037a7c1eef9766..76e7ca536a007ac20b0b57315abea281b7fef27b 100644 (file)
@@ -155,8 +155,7 @@ 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