propagate solo/iso when disconnecting ports.
authorRobin Gareus <robin@gareus.org>
Tue, 6 Oct 2015 15:30:32 +0000 (17:30 +0200)
committerRobin Gareus <robin@gareus.org>
Tue, 6 Oct 2015 16:16:12 +0000 (18:16 +0200)
libs/ardour/route.cc

index 5393bcc6820dbf5c03e583421338e51b0aaf4887..89fd1d35dbf5b749868d063de40533810db5cdec 100644 (file)
@@ -950,6 +950,8 @@ void
 Route::mod_solo_isolated_by_upstream (bool yn, void* src)
 {
        bool old = solo_isolated ();
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod_solo_isolated_by_upstream cur: %2 d: %3\n",
+                               name(), _solo_isolated_by_upstream, yn ? "+1" : "-1"));
 
        if (!yn) {
                if (_solo_isolated_by_upstream >= 1) {
@@ -963,7 +965,7 @@ Route::mod_solo_isolated_by_upstream (bool yn, void* src)
 
        if (solo_isolated() != old) {
                /* solo isolated status changed */
-               _mute_master->set_solo_ignore (yn);
+               _mute_master->set_solo_ignore (solo_isolated());
                solo_isolated_changed (src);
        }
 }
@@ -991,7 +993,7 @@ Route::set_solo_isolated (bool yn, void *src)
        } else {
                if (_solo_isolated == true) {
                        _solo_isolated = false;
-            _mute_master->set_solo_ignore (false);
+                       _mute_master->set_solo_ignore (false);
                        changed = true;
                }
        }
@@ -3252,56 +3254,87 @@ Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool /*did_
 void
 Route::input_change_handler (IOChange change, void * /*src*/)
 {
-       bool need_to_queue_solo_change = true;
-
        if ((change.type & IOChange::ConfigurationChanged)) {
                /* This is called with the process lock held if change
                   contains ConfigurationChanged
                */
-               need_to_queue_solo_change = false;
                configure_processors (0);
                _phase_invert.resize (_input->n_ports().n_audio ());
                io_changed (); /* EMIT SIGNAL */
        }
 
-       if (!_input->connected() && _soloed_by_others_upstream) {
-               if (need_to_queue_solo_change) {
-                       _session.cancel_solo_after_disconnect (shared_from_this(), true);
-               } else {
-                       cancel_solo_after_disconnect (true);
-               }
-#if 1
-       } else if (_soloed_by_others_upstream) {
-               bool cancel_solo = true;
+       if (_soloed_by_others_upstream || _solo_isolated_by_upstream) {
+               int sbou = 0;
+               int ibou = 0;
                boost::shared_ptr<RouteList> routes = _session.get_routes ();
+               if (_input->connected()) {
+                       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+                               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                                       continue;
+                               }
+                               bool sends_only;
+                               bool does_feed = (*i)->direct_feeds_according_to_reality (shared_from_this(), &sends_only);
+                               if (does_feed && !sends_only) {
+                                       if ((*i)->soloed()) {
+                                               ++sbou;
+                                       }
+                                       if ((*i)->solo_isolated()) {
+                                               ++ibou;
+                                       }
+                               }
+                       }
+               }
+
+               int delta  = sbou - _soloed_by_others_upstream;
+               int idelta = ibou - _solo_isolated_by_upstream;
+
+               if (idelta < -1) {
+                       PBD::warning << string_compose (
+                                       _("Invalid Solo-Isolate propagation: from:%1 new:%2 - old:%3 = delta:%4"),
+                                       _name, ibou, _solo_isolated_by_upstream, idelta)
+                                    << endmsg;
+
+               }
+
+               if (_soloed_by_others_upstream) {
+                       // ignore new connections (they're not propagated)
+                       if (delta <= 0) {
+                               mod_solo_by_others_upstream (delta);
+                       }
+               }
+
+               if (_solo_isolated_by_upstream) {
+                       // solo-isolate currently only propagates downstream
+                       if (idelta < 0) {
+                               mod_solo_isolated_by_upstream (false, this);
+                       }
+                       // TODO think: mod_solo_isolated_by_upstream() does not take delta arg,
+                       // but idelta can't be smaller than -1, can it?
+                       //_solo_isolated_by_upstream = ibou;
+               }
+
+               // Session::route_solo_changed  does not propagate indirect solo-changes
+               // propagate downstream to tracks
                for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
                        if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
                                continue;
                        }
                        bool sends_only;
-                       bool does_feed = (*i)->direct_feeds_according_to_reality (shared_from_this(), &sends_only);
-                       if (does_feed && !sends_only) {
-                               if ((*i)->soloed()) {
-                                       cancel_solo = false;
-                                       break;
-                               }
+                       bool does_feed = feeds (*i, &sends_only);
+                       if (delta <= 0 && does_feed && !sends_only) {
+                               (*i)->mod_solo_by_others_upstream (delta);
+                       }
+
+                       if (idelta < 0 && does_feed && !sends_only) {
+                               (*i)->mod_solo_isolated_by_upstream (false, this);
                        }
                }
-               if (cancel_solo) {
-                       cancel_solo_after_disconnect (true);
-               }
-#else
-       } else if (self_soloed()) {
-#endif
-               // TODO propagate upstream
-               // see commment in output_change_handler() below
        }
 }
 
 void
 Route::output_change_handler (IOChange change, void * /*src*/)
 {
-       bool need_to_queue_solo_change = true;
        if (_initial_io_setup) {
                return;
        }
@@ -3310,7 +3343,6 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                /* This is called with the process lock held if change
                   contains ConfigurationChanged
                */
-               need_to_queue_solo_change = false;
                configure_processors (0);
 
                if (is_master()) {
@@ -3320,49 +3352,54 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                io_changed (); /* EMIT SIGNAL */
        }
 
-       if (!_output->connected() && _soloed_by_others_downstream) {
-               if (need_to_queue_solo_change) {
-                       _session.cancel_solo_after_disconnect (shared_from_this(), false);
-               } else {
-                       cancel_solo_after_disconnect (false);
-               }
-#if 1
-       } else if (_soloed_by_others_downstream) {
-               bool cancel_solo = true;
+       if (_soloed_by_others_downstream) {
+               int sbod = 0;
                /* checking all all downstream routes for
                 * explicit of implict solo is a rather drastic measure,
                 * ideally the input_change_handler() of the other route
                 * would propagate the change to us.
                 */
                boost::shared_ptr<RouteList> routes = _session.get_routes ();
-               for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
-                       if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
-                               continue;
-                       }
-                       bool sends_only;
-                       bool does_feed = direct_feeds_according_to_reality (*i, &sends_only);
-                       if (does_feed && !sends_only) {
-                               if ((*i)->soloed()) {
-                                       cancel_solo = false;
-                                       break;
+               if (_output->connected()) {
+                       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+                               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                                       continue;
+                               }
+                               bool sends_only;
+                               bool does_feed = direct_feeds_according_to_reality (*i, &sends_only);
+                               if (does_feed && !sends_only) {
+                                       if ((*i)->soloed()) {
+                                               ++sbod;
+                                               break;
+                                       }
                                }
                        }
                }
-               if (cancel_solo) {
-                       cancel_solo_after_disconnect (false);
+               int delta = sbod - _soloed_by_others_downstream;
+               if (delta <= 0) {
+                       // do not allow new connections to change implicit solo (no propagation)
+                       mod_solo_by_others_downstream (delta);
+                       // Session::route_solo_changed() does not propagate indirect solo-changes
+                       // propagate upstream to tracks
+                       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+                               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                                       continue;
+                               }
+                               bool sends_only;
+                               bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
+                               if (delta != 0 && does_feed && !sends_only) {
+                                       (*i)->mod_solo_by_others_downstream (delta);
+                               }
+                       }
+
                }
-#else
-       } else if (self_soloed()) {
-               // TODO propagate change downstream to the disconnected routes
-               // Q: how to get the routes that were just disconnected. ?
-               // A: /maybe/ by diff feeds() aka fed_by() vs direct_feeds_according_to_reality() ?!?
-#endif
        }
 }
 
 void
 Route::cancel_solo_after_disconnect (bool upstream)
 {
+       assert (0); // no longer used -- TODO remove cruft
        if (upstream) {
                _soloed_by_others_upstream = 0;
        } else {