yet more work on Ye Fabled Solo Architecture. now do forward and backward propagation...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 27 Apr 2010 03:10:53 +0000 (03:10 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 27 Apr 2010 03:10:53 +0000 (03:10 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@7001 d708f5d6-7413-0410-9779-e7cbd77b26cf

13 files changed:
gtk2_ardour/ardour3_ui_dark.rc.in
gtk2_ardour/ardour_ui2.cc
gtk2_ardour/editor_routes.cc
gtk2_ardour/editor_routes.h
gtk2_ardour/mixer_strip.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_ui.cc
gtk2_ardour/route_ui.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/route.cc
libs/ardour/session.cc
libs/gtkmm2ext/stateful_button.cc

index f338a736dccb8bafc0116b95d06e504aef1440ae..8458d463165c58e7e8ef7da235e4cbf6c093b40b 100644 (file)
@@ -395,6 +395,15 @@ style "mixer_solo_button_alternate" = "solo_button_alternate"
        xthickness = 0
        ythickness = 0
 }
+
+style "mixer_solo_button_alternate2" = "solo_button_alternate2"
+{
+       font_name = "@FONT_SMALLER@"
+       xthickness = 0
+       ythickness = 0
+}
+
+
 style "mixer_solo_button_active" = "solo_button_active"
 {
        font_name = "@FONT_SMALLER@"
@@ -1457,6 +1466,7 @@ widget "*SoloButton-alternate2" style:highest "solo_button_alternate2"
 widget "*SoloButton-active" style:highest "solo_button_active"
 widget "*MixerSoloButton" style:highest "mixer_solo_button"
 widget "*MixerSoloButton-alternate" style:highest "mixer_solo_button_alternate"
+widget "*MixerSoloButton-alternate2" style:highest "mixer_solo_button_alternate2"
 widget "*MixerSoloButton-active" style:highest "mixer_solo_button_active"
 widget "*TrackLoopButton*" style:highest "track_loop_button"
 widget "*PanAutomationLineSelector*" style:highest "multiline_combo"
index 8aa28e2685ab1267dd8280fecd31c20fce7d2929..9991a1dc1427924e3e4ada4e8d2e483c34e3c4cc 100644 (file)
@@ -494,8 +494,6 @@ ARDOUR_UI::reattach_tearoff (Box* b, Widget* w, int32_t n)
 void
 ARDOUR_UI::soloing_changed (bool onoff)
 {
-        cerr << "solo change, " << onoff << endl;
-
        if (solo_alert_button.get_active() != onoff) {
                solo_alert_button.set_active (onoff);
        }
index 3d5cb3522c8f44f69e75b5579499909270612d13..81a1635e772f29ffa337de32e078b41e5621246e 100644 (file)
@@ -461,14 +461,14 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
                }
 
                (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
-               (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
+               (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
                (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
                (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
        }
 
        update_rec_display ();
        update_mute_display ();
-       update_solo_display ();
+       update_solo_display (true);
        update_solo_isolate_display ();
        update_solo_safe_display ();
        resume_redisplay ();
@@ -1026,7 +1026,7 @@ EditorRoutes::update_mute_display ()
 }
 
 void
-EditorRoutes::update_solo_display ()
+EditorRoutes::update_solo_display (bool /* selfsoloed */)
 {
        TreeModel::Children rows = _model->children();
        TreeModel::Children::iterator i;
@@ -1098,7 +1098,6 @@ EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_t
 void
 EditorRoutes::solo_changed_so_update_mute ()
 {
-       ENSURE_GUI_THREAD (*this, &EditorRoutes::solo_changed_so_update_mute)
        update_mute_display ();
 }
 
index b37607aad9d49ab2040bbbbb77d60a0bba41c64d..d0798ee5bc34c2a9c88311d8f1a76bb4b7a7bfae 100644 (file)
@@ -74,7 +74,7 @@ private:
        void handle_gui_changes (std::string const &, void *);
        void update_rec_display ();
        void update_mute_display ();
-       void update_solo_display ();
+       void update_solo_display (bool);
        void update_solo_isolate_display ();
        void update_solo_safe_display ();
        void set_all_tracks_visibility (bool);
index cb030287cab247e6c399cf9afece491ec698d51a..6f3d10d94b8ba5d47e8face69e6876be6da23369 100644 (file)
@@ -328,7 +328,7 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        /* map the current state */
 
        mute_changed (0);
-       solo_changed (0);
+       update_solo_display ();
 
        delete input_selector;
        input_selector = 0;
@@ -435,7 +435,7 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        /* now force an update of all the various elements */
 
        mute_changed (0);
-       solo_changed (0);
+        update_solo_display ();
        name_changed ();
        comment_changed (0);
        route_group_changed ();
index bf999d23d691baea135548fa734087233297f13f..0c52b96dc3eb0aff504d403e9de5ee9418e0d219 100644 (file)
@@ -133,7 +133,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh
        }
 
        mute_changed (0);
-       solo_changed (0);
+        update_solo_display ();
 
        timestretch_rect = 0;
        no_redraw = false;
index ee66bf4c903c7069edc1310d297ece92b8271fe0..816343a2cb1a953f3564623c7dd17f91863a7ace 100644 (file)
@@ -209,10 +209,12 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
 
        _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
        _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
-       _route->solo_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::solo_changed, this, _1), gui_context());
-       _route->solo_safe_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::solo_changed, this, _1), gui_context());
-       _route->listen_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::listen_changed, this, _1), gui_context());
-       _route->solo_isolated_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::solo_changed, this, _1), gui_context());
+
+       _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
+       _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
+       _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
+       _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
+
         _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
        _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
 
@@ -691,19 +693,6 @@ RouteUI::send_blink (bool onoff)
        }
 }
 
-void
-RouteUI::solo_changed(void* /*src*/)
-{
-       Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteUI::update_solo_display, this));
-}
-
-
-void
-RouteUI::listen_changed(void* /*src*/)
-{
-       Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteUI::update_solo_display, this));
-}
-
 int
 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
 {
@@ -740,7 +729,7 @@ RouteUI::solo_visual_state_with_isolate (boost::shared_ptr<Route> r)
                if (r->listening()) {
                        return 1;
                } else {
-                       return 0;
+                        return 0;
                }
 
        } 
index bbe18bfc4fb7865302a8e6dfdba8bf4c50a251fe..1dae38d9d9d4f6083b47088db67539f1bbf41082 100644 (file)
@@ -131,7 +131,7 @@ class RouteUI : public virtual AxisView
        void create_sends (ARDOUR::Placement);
        void create_selected_sends (ARDOUR::Placement);
 
-       void solo_changed(void*);
+       void solo_changed(bool, void*);
        void solo_changed_so_update_mute ();
        void mute_changed(void*);
        void listen_changed(void*);
index f9ba1a8e8adf82e6abc2e6b6855aeb9f449df32d..606810389622f6933166755085c910bc2d704012 100644 (file)
@@ -238,7 +238,7 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
        PBD::Signal0<void>       phase_invert_changed;
        PBD::Signal0<void>       denormal_protection_changed;
        PBD::Signal1<void,void*> listen_changed;
-       PBD::Signal1<void,void*> solo_changed;
+       PBD::Signal2<void,bool,void*> solo_changed;
        PBD::Signal1<void,void*> solo_safe_changed;
        PBD::Signal1<void,void*> solo_isolated_changed;
        PBD::Signal1<void,void*> comment_changed;
@@ -273,8 +273,39 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
        int listen_via (boost::shared_ptr<Route>, Placement p, bool active, bool aux);
        void drop_listen (boost::shared_ptr<Route>);
 
-       bool feeds (boost::shared_ptr<Route>, bool* via_send_only = 0);
-       std::set<boost::weak_ptr<Route> > fed_by;
+       /** 
+        * return true if this route feeds the first argument via at least one
+        * (arbitrarily long) signal pathway.
+        */
+        bool feeds (boost::shared_ptr<Route>, bool* via_send_only = 0);
+
+       /** 
+        * return true if this route feeds the first argument directly, via
+        * either its main outs or a send.
+        */
+       bool direct_feeds (boost::shared_ptr<Route>, bool* via_send_only = 0);
+
+        struct FeedRecord {
+            boost::weak_ptr<Route> r;
+            bool sends_only;
+
+            FeedRecord (boost::shared_ptr<Route> rp, bool sendsonly)
+                    : r (rp)
+                    , sends_only (sendsonly) {}
+        };
+
+        struct FeedRecordCompare {
+            bool operator() (const FeedRecord& a, const FeedRecord& b) const {
+                    return a.r < b.r;
+            }
+        };
+
+        typedef std::set<FeedRecord,FeedRecordCompare> FedBy;
+
+        const FedBy& fed_by() const { return _fed_by; }
+        void clear_fed_by ();
+        bool add_fed_by (boost::shared_ptr<Route>, bool sends_only);
+        bool not_fed() const { return _fed_by.empty(); }
 
        /* Controls (not all directly owned by the Route */
 
@@ -393,6 +424,7 @@ class Route : public SessionObject, public AutomatableControls, public RouteGrou
        bool           _have_internal_generator;
        bool           _solo_safe;
        DataType       _default_type;
+        FedBy          _fed_by;
 
         virtual ChanCount input_streams () const;
 
index 8f0a2504ebccd4042e948bd3916ec3c26f1df531..014b49b318a224725047cb3285474a76ba536414 100644 (file)
@@ -1218,7 +1218,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
        void route_listen_changed (void *src, boost::weak_ptr<Route>);
        void route_mute_changed (void *src);
-       void route_solo_changed (void *src, boost::weak_ptr<Route>);
+       void route_solo_changed (bool self_solo_change, void *src, boost::weak_ptr<Route>);
        void update_route_solo_state (boost::shared_ptr<RouteList> r = boost::shared_ptr<RouteList>());
 
        void listen_position_changed ();
index c57594da3723b44cf3923b806ec0c876b8b85ae4..325e6c42fa82b8a508782bbeaa4a04ea44025e6a 100644 (file)
@@ -581,7 +581,7 @@ Route::set_solo (bool yn, void *src)
        if (self_soloed() != yn) {
                set_self_solo (yn);
                set_delivery_solo ();
-               solo_changed (src); /* EMIT SIGNAL */
+               solo_changed (true, src); /* EMIT SIGNAL */
                _solo_control->Changed (); /* EMIT SIGNAL */
        }
 }
@@ -610,7 +610,7 @@ Route::mod_solo_by_others (int32_t delta)
        }
 
        set_delivery_solo ();
-        solo_changed (this);
+        solo_changed (false, this);
 }
 
 void
@@ -649,7 +649,7 @@ Route::set_solo_isolated (bool yn, void *src)
        boost::shared_ptr<RouteList> routes = _session.get_routes ();
        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
                bool sends_only;
-               bool does_feed = feeds (*i, &sends_only);
+               bool does_feed = direct_feeds (*i, &sends_only);
                
                if (does_feed && !sends_only) {
                        (*i)->set_solo_isolated (yn, (*i)->route_group());
@@ -2465,7 +2465,53 @@ Route::set_comment (string cmt, void *src)
 }
 
 bool
-Route::feeds (boost::shared_ptr<Route> other, bool* only_send)
+Route::add_fed_by (boost::shared_ptr<Route> other, bool via_sends_only)
+{
+        FeedRecord fr (other, via_sends_only);
+
+        pair<FedBy::iterator,bool> result =  _fed_by.insert (fr);
+
+        if (!result.second) {
+
+                /* already a record for "other" - make sure sends-only information is correct */
+                if (!via_sends_only && result.first->sends_only) {
+                        FeedRecord* frp = const_cast<FeedRecord*>(&(*result.first));
+                        frp->sends_only = false;
+                }
+        }
+        
+        return result.second;
+}
+
+void
+Route::clear_fed_by ()
+{
+        _fed_by.clear ();
+}
+
+bool
+Route::feeds (boost::shared_ptr<Route> other, bool* via_sends_only)
+{
+        const FedBy& fed_by (other->fed_by());
+
+        for (FedBy::iterator f = fed_by.begin(); f != fed_by.end(); ++f) {
+                boost::shared_ptr<Route> sr = f->r.lock();
+
+                if (sr && (sr.get() == this)) {
+
+                        if (via_sends_only) {
+                                *via_sends_only = f->sends_only;
+                        }
+
+                        return true;
+                }
+        }
+
+        return false;
+}
+
+bool
+Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
 {
        DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name));
 
index f41b4f8fba1ac3352072fefada7ee26b037a1cf6..b213439abaa685bbac7816741f95f1c392483811 100644 (file)
@@ -1238,13 +1238,13 @@ Session::set_default_fade (float /*steepness*/, float /*fade_msecs*/)
 
 struct RouteSorter {
     bool operator() (boost::shared_ptr<Route> r1, boost::shared_ptr<Route> r2) {
-           if (r1->fed_by.find (r2) != r1->fed_by.end()) {
+           if (r2->feeds (r1)) {
                    return false;
-           } else if (r2->fed_by.find (r1) != r2->fed_by.end()) {
+           } else if (r1->feeds (r2)) {
                    return true;
            } else {
-                   if (r1->fed_by.empty()) {
-                           if (r2->fed_by.empty()) {
+                   if (r1->not_fed ()) {
+                           if (r2->not_fed ()) {
                                    /* no ardour-based connections inbound to either route. just use signal order */
                                    return r1->order_key(N_("signal")) < r2->order_key(N_("signal"));
                            } else {
@@ -1263,21 +1263,21 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase)
 {
        shared_ptr<Route> r2;
 
-       if ((r1->fed_by.find (rbase) != r1->fed_by.end()) && (rbase->fed_by.find (r1) != rbase->fed_by.end())) {
+       if (r1->feeds (rbase) && rbase->feeds (r1)) {
                info << string_compose(_("feedback loop setup between %1 and %2"), r1->name(), rbase->name()) << endmsg;
                return;
        }
 
        /* make a copy of the existing list of routes that feed r1 */
 
-       set<weak_ptr<Route> > existing = r1->fed_by;
-
+        Route::FedBy existing (r1->fed_by());
+                        
        /* for each route that feeds r1, recurse, marking it as feeding
           rbase as well.
        */
 
-       for (set<weak_ptr<Route> >::iterator i = existing.begin(); i != existing.end(); ++i) {
-               if (!(r2 = (*i).lock ())) {
+       for (Route::FedBy::iterator i = existing.begin(); i != existing.end(); ++i) {
+               if (!(r2 = i->r.lock ())) {
                        /* (*i) went away, ignore it */
                        continue;
                }
@@ -1286,7 +1286,7 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase)
                   base as being fed by r2
                */
 
-               rbase->fed_by.insert (r2);
+               rbase->add_fed_by (r2, i->sends_only);
 
                if (r2 != rbase) {
 
@@ -1294,7 +1294,7 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase)
                           stop here.
                        */
 
-                       if ((r1->fed_by.find (r2) != r1->fed_by.end()) && (r2->fed_by.find (r1) != r2->fed_by.end())) {
+                       if (r1->feeds (r2) && r2->feeds (r1)) {
                                continue;
                        }
 
@@ -1328,6 +1328,22 @@ Session::resort_routes ()
                /* writer goes out of scope and forces update */
        }
 
+#ifndef NDEBUG
+        boost::shared_ptr<RouteList> rl = routes.reader ();
+        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                DEBUG_TRACE (DEBUG::Graph, string_compose ("%1 fed by ...\n", (*i)->name()));
+                
+                const Route::FedBy& fb ((*i)->fed_by());
+
+                for (Route::FedBy::const_iterator f = fb.begin(); f != fb.end(); ++f) {
+                        boost::shared_ptr<Route> sf = f->r.lock();
+                        if (sf) {
+                                DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 (sends only ? %2)\n", sf->name(), f->sends_only));
+                        }
+                }
+        }
+#endif
+
 }
 void
 Session::resort_routes_using (shared_ptr<RouteList> r)
@@ -1336,7 +1352,7 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
 
        for (i = r->begin(); i != r->end(); ++i) {
 
-               (*i)->fed_by.clear ();
+               (*i)->clear_fed_by ();
 
                for (j = r->begin(); j != r->end(); ++j) {
 
@@ -1350,8 +1366,10 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
                                continue;
                        }
 
-                       if ((*j)->feeds (*i)) {
-                               (*i)->fed_by.insert (*j);
+                        bool via_sends_only;
+
+                       if ((*j)->direct_feeds (*i, &via_sends_only)) {
+                               (*i)->add_fed_by (*j, via_sends_only);
                        }
                }
        }
@@ -1363,13 +1381,11 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
        RouteSorter cmp;
        r->sort (cmp);
 
-#if 0
-       cerr << "finished route resort\n";
-
+#ifndef NDEBUG
+        DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               cerr << " " << (*i)->name() << " signal order = " << (*i)->order_key ("signal") << endl;
+               DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2\n", (*i)->name(), (*i)->order_key ("signal")));
        }
-       cerr << endl;
 #endif
 
 }
@@ -1882,7 +1898,7 @@ Session::add_routes (RouteList& new_routes, bool save)
                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, wpr));
+               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2, wpr));
                r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this, _1));
                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));
@@ -2122,8 +2138,13 @@ Session::route_listen_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
 }
 
 void
-Session::route_solo_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
+Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_ptr<Route> wpr)
 {
+        if (!self_solo_change) {
+                // session doesn't care about changes to soloed-by-others
+                return;
+        }
+
        if (solo_update_disabled) {
                // We know already
                return;
@@ -2146,22 +2167,48 @@ Session::route_solo_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
                delta = -1;
        }
 
-       /* now mod the solo level of all other routes except master/control outs/auditioner
-          so that they will be silent if appropriate.
-       */
-
        solo_update_disabled = true;
 
+        /* from IRC: 
+
+           <las> oofus_lt: solo a route, do NOT mute anything in the feed-forward chain for the route
+           <las> oofus_lt: and do solo-by-other everything in the feed-backward chain
+
+        */
+
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                bool via_sends_only;
 
                if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
                        continue;
-               } else if ((*i)->feeds (route, &via_sends_only)) {
+               } 
+
+                /* feed-backwards (other route to solo change route):
+
+                        if (*i) feeds the one whose solo status changed 
+                             it should be soloed by other if the change was -> solo OR de-soloed by other if change was -> !solo
+                        else 
+                             do nothing
+                            
+                 */
+
+                if ((*i)->feeds (route, &via_sends_only)) {
                        if (!via_sends_only) {
                                (*i)->mod_solo_by_others (delta);
                        }
                } 
+                
+                /* feed-forward (solo change route to other routes):
+                    
+                      if the route whose solo status changed feeds (*i)
+                             do nothing
+                      else 
+                             mute if the change was -> solo OR demute if change was -> !solo
+                 */
+
+                if (route->feeds (*i, &via_sends_only)) {
+                        (*i)->mod_solo_by_others (delta);
+                }
        }
 
        solo_update_disabled = false;
index d8bb1f212f6f7f012195762ac444a1215e79d38f..0548b8392b496c62fd7798c16e1ad0111adce573 100644 (file)
@@ -74,7 +74,6 @@ StateButton::set_visual_state (int n)
        }
 
        set_widget_name (name);
-
        visual_state = n;
 }