new API for route solo/mute state mgmt
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 9 Mar 2016 18:11:53 +0000 (13:11 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 May 2016 19:30:40 +0000 (15:30 -0400)
Route now calls back into Session when solo/mute/listen state changes. All other interested
parties must use the Route::{solo,mute,...}_control()->Changed() to be notified of changes.

The Session requires more information than the Changed signal can provide, in order to
propagate solo/mute changes across the entire Session correctly.

Note that this uses an experimental use of CRTP to isolate a public API within Session

libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/session_solo_notifications.h [new file with mode: 0644]
libs/ardour/midi_track.cc
libs/ardour/route.cc
libs/ardour/session.cc

index 89026651700c57f4338b8655dab06fa262b996ba..b976e63c694069ad4fd94c5ae8f400f3dbcaf2b0 100644 (file)
@@ -350,14 +350,8 @@ public:
        framecnt_t signal_latency() const { return _signal_latency; }
 
        PBD::Signal0<void>       active_changed;
-       PBD::Signal0<void>       phase_invert_changed;
        PBD::Signal0<void>       denormal_protection_changed;
-       PBD::Signal1<void,PBD::Controllable::GroupControlDisposition>  listen_changed;
-       PBD::Signal2<void,bool,PBD::Controllable::GroupControlDisposition>  solo_changed;
-       PBD::Signal0<void>       solo_safe_changed;
-       PBD::Signal0<void>       solo_isolated_changed;
        PBD::Signal0<void>       comment_changed;
-       PBD::Signal0<void>       mute_changed;
        PBD::Signal0<void>       mute_points_changed;
 
        /** track numbers - assigned by session
index 2976fec8f3307a48534101bd3a501c9275feda54..b3852b631d0821c53cb4d5ea0d755f0d473f311f 100644 (file)
@@ -67,6 +67,7 @@
 #include "ardour/rc_configuration.h"
 #include "ardour/session_configuration.h"
 #include "ardour/session_event.h"
+#include "ardour/session_solo_notifications.h"
 #include "ardour/interpolation.h"
 #include "ardour/plugin.h"
 #include "ardour/route.h"
@@ -165,7 +166,7 @@ private:
 };
 
 /** Ardour Session */
-class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionList, public SessionEventManager
+class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionList, public SessionEventManager, public SessionSoloNotifications<Session>
 {
   public:
        enum RecordState {
@@ -1683,12 +1684,14 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
        void reassign_track_numbers ();
        uint32_t _track_number_decimals;
 
-       /* mixer stuff */
+       /* solo/mute/notifications (see SessionSoloNotifications object) */
+
+       friend class SessionSoloNotifications;
+       void _route_listen_changed (PBD::Controllable::GroupControlDisposition, boost::shared_ptr<Route>);
+       void _route_mute_changed ();
+       void _route_solo_changed (bool self_solo_change, PBD::Controllable::GroupControlDisposition group_override, boost::shared_ptr<Route>);
+       void _route_solo_isolated_changed (boost::shared_ptr<Route>);
 
-       void route_listen_changed (PBD::Controllable::GroupControlDisposition, boost::weak_ptr<Route>);
-       void route_mute_changed ();
-       void route_solo_changed (bool self_solo_change, PBD::Controllable::GroupControlDisposition group_override, boost::weak_ptr<Route>);
-       void route_solo_isolated_changed (boost::weak_ptr<Route>);
        void update_route_solo_state (boost::shared_ptr<RouteList> r = boost::shared_ptr<RouteList>());
 
        void listen_position_changed ();
diff --git a/libs/ardour/ardour/session_solo_notifications.h b/libs/ardour/ardour/session_solo_notifications.h
new file mode 100644 (file)
index 0000000..bfb2e7d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    Copyright (C) 2016 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_session_solo_notifications_h__
+#define __libardour_session_solo_notifications_h__
+
+#include <boost/shared_ptr.hpp>
+#include "pbd/controllable.h"
+
+namespace ARDOUR {
+
+class Route;
+
+template<typename T>
+class SessionSoloNotifications
+{
+    public:
+       void solo_changed (bool self_solo_change, PBD::Controllable::GroupControlDisposition gcd, boost::shared_ptr<Route> route) {
+               static_cast<T*>(this)->_route_solo_changed (self_solo_change, gcd, route);
+       }
+
+       void listen_changed (PBD::Controllable::GroupControlDisposition gcd, boost::shared_ptr<Route> route) {
+               static_cast<T*>(this)->_route_listen_changed (gcd, route);
+       }
+
+       void mute_changed () {
+               static_cast<T*>(this)->_route_mute_changed ();
+       }
+
+       void solo_isolated_changed (boost::shared_ptr<Route> route) {
+               static_cast<T*>(this)->_route_solo_isolated_changed (route);
+       }
+};
+
+} /* namespace */
+
+#endif /* __libardour_session_solo_notifications_h__ */
index 3d1d8d00931bae27f62417488d0a91a4735ca60d..9a38f9f05a9c30ead8d94fd5019e3076b04fe9c4 100644 (file)
@@ -999,4 +999,3 @@ MidiTrack::monitoring_state () const
        }
        return ms;
 }
-
index 94111e602eb47e7b3026bb9d68c6fb16d90ef286..569f00fbc770c020e8d2798f0994dbfd3695491f 100644 (file)
@@ -830,7 +830,8 @@ Route::set_listen (bool yn, Controllable::GroupControlDisposition group_override
                        }
                        _mute_master->set_soloed_by_others (false);
 
-                       listen_changed (group_override); /* EMIT SIGNAL */
+                       _session.listen_changed (group_override, shared_from_this());
+                       _solo_control->Changed(); /* EMIT SIGNAL */
                }
        }
 }
@@ -850,7 +851,6 @@ Route::set_solo_safe (bool yn, Controllable::GroupControlDisposition /* group_ov
 {
        if (_solo_safe != yn) {
                _solo_safe = yn;
-               solo_safe_changed (); /* EMIT SIGNAL */
                _solo_safe_control->Changed(); /* EMIT SIGNAL */
        }
 }
@@ -893,7 +893,8 @@ Route::clear_all_solo_state ()
 
        if (emit_changed) {
                set_mute_master_solo ();
-               solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
+               _session.solo_changed (false, Controllable::UseGroup, shared_from_this());
+               _solo_control->Changed (); /* EMIT SIGNAL */
        }
 }
 
@@ -920,7 +921,7 @@ Route::set_solo (bool yn, Controllable::GroupControlDisposition group_override)
 
        if (self_soloed() != yn) {
                set_self_solo (yn);
-               solo_changed (true, group_override); /* EMIT SIGNAL */
+               _session.solo_changed (true, group_override, shared_from_this());
                _solo_control->Changed (); /* EMIT SIGNAL */
        }
 
@@ -998,7 +999,8 @@ Route::mod_solo_by_others_upstream (int32_t delta)
        }
 
        set_mute_master_solo ();
-       solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
+       _session.solo_changed (false, Controllable::UseGroup, shared_from_this());
+       _solo_control->Changed (); /* EMIT SIGNAL */
 }
 
 void
@@ -1020,7 +1022,8 @@ Route::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 ();
-       solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
+       _session.solo_changed (false, Controllable::UseGroup, shared_from_this());
+       _solo_control->Changed (); /* EMIT SIGNAL */
 }
 
 void
@@ -1050,7 +1053,8 @@ Route::mod_solo_isolated_by_upstream (bool yn)
        if (solo_isolated() != old) {
                /* solo isolated status changed */
                _mute_master->set_solo_ignore (solo_isolated());
-               solo_isolated_changed (); /* EMIT SIGNAL */
+               _session.solo_isolated_changed (shared_from_this());
+               _solo_isolate_control->Changed(); /* EMIT SIGNAL */
        }
 }
 
@@ -1106,7 +1110,7 @@ Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_o
 
        /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
 
-       solo_isolated_changed (); /* EMIT SIGNAL */
+       _session.solo_isolated_changed (shared_from_this());
        _solo_isolate_control->Changed(); /* EMIT SIGNAL */
 }
 
@@ -1123,7 +1127,7 @@ Route::set_mute_points (MuteMaster::MutePoint mp)
        mute_points_changed (); /* EMIT SIGNAL */
 
        if (_mute_master->muted_by_self()) {
-               mute_changed (); /* EMIT SIGNAL */
+               _session.mute_changed ();
                _mute_control->Changed (); /* EMIT SIGNAL */
        }
 }
@@ -1143,7 +1147,7 @@ Route::set_mute (bool yn, Controllable::GroupControlDisposition group_override)
                */
                act_on_mute ();
                /* tell everyone else */
-               mute_changed (); /* EMIT SIGNAL */
+               _session.mute_changed ();
                _mute_control->Changed (); /* EMIT SIGNAL */
        }
 }
@@ -4643,7 +4647,6 @@ Route::set_phase_invert (uint32_t c, bool yn)
 {
        if (_phase_invert[c] != yn) {
                _phase_invert[c] = yn;
-               phase_invert_changed (); /* EMIT SIGNAL */
                _phase_control->Changed(); /* EMIT SIGNAL */
                _session.set_dirty ();
        }
@@ -4654,7 +4657,7 @@ Route::set_phase_invert (boost::dynamic_bitset<> p)
 {
        if (_phase_invert != p) {
                _phase_invert = p;
-               phase_invert_changed (); /* EMIT SIGNAL */
+               _phase_control->Changed (); /* EMIT SIGNAL */
                _session.set_dirty ();
        }
 }
index 86d698a2cb932993d6a60479ff208930659aea1b..417edf83b76ef04bb0b7476983111c1c4ca82e00 100644 (file)
@@ -3411,10 +3411,12 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                boost::weak_ptr<Route> wpr (*x);
                boost::shared_ptr<Route> r (*x);
 
-               r->listen_changed.connect_same_thread (*this, boost::bind (&Session::route_listen_changed, this, _1, wpr));
-               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2, wpr));
-               r->solo_isolated_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, wpr));
-               r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this));
+               /* we don't connect to control Changed signals for
+                * solo/mute/listen. The Route calls back to use, via
+                * the SessionSoloNotifications API, passing us more
+                * information than would be available from a control Changed signal.
+                */
+               
                r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2));
                r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1));
 
@@ -3692,20 +3694,14 @@ Session::remove_route (boost::shared_ptr<Route> route)
 }
 
 void
-Session::route_mute_changed ()
+Session::_route_mute_changed ()
 {
        set_dirty ();
 }
 
 void
-Session::route_listen_changed (Controllable::GroupControlDisposition group_override, boost::weak_ptr<Route> wpr)
+Session::_route_listen_changed (Controllable::GroupControlDisposition group_override, boost::shared_ptr<Route> route)
 {
-       boost::shared_ptr<Route> route = wpr.lock();
-       if (!route) {
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_listen_changed")) << endmsg;
-               return;
-       }
-
        if (route->listening_via_monitor ()) {
 
                if (Config->get_exclusive_solo()) {
@@ -3747,17 +3743,10 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
 
        update_route_solo_state ();
 }
+
 void
-Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
+Session::_route_solo_isolated_changed (boost::shared_ptr<Route> route)
 {
-       boost::shared_ptr<Route> route = wpr.lock ();
-
-       if (!route) {
-               /* should not happen */
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_isolated_changed")) << endmsg;
-               return;
-       }
-
        bool send_changed = false;
 
        if (route->solo_isolated()) {
@@ -3778,7 +3767,7 @@ Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
 }
 
 void
-Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDisposition group_override,  boost::weak_ptr<Route> wpr)
+Session::_route_solo_changed (bool self_solo_change, Controllable::GroupControlDisposition group_override,  boost::shared_ptr<Route> route)
 {
        DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1\n", self_solo_change));
 
@@ -3787,9 +3776,6 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                return;
        }
 
-       boost::shared_ptr<Route> route = wpr.lock ();
-       assert (route);
-
        boost::shared_ptr<RouteList> r = routes.reader ();
        int32_t delta;
 
@@ -3938,7 +3924,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
        for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
                DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
                (*i)->act_on_mute ();
-               (*i)->mute_changed ();
+               (*i)->mute_control()->Changed (); /* EMIT SIGNAL */
        }
 
        SoloChanged (); /* EMIT SIGNAL */