diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2010-04-27 03:10:53 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2010-04-27 03:10:53 +0000 |
commit | a8e354ed7bb38f8be8bfdda33841f3f238e8bbab (patch) | |
tree | e2ab48a8b041c1146f33e87de60689314e52a1e1 /libs | |
parent | 56469c195640b561119852fd6d27a4b56e5af7e2 (diff) |
yet more work on Ye Fabled Solo Architecture. now do forward and backward propagation of solo status from a soloed track. tweak GUI appearance
git-svn-id: svn://localhost/ardour2/branches/3.0@7001 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/route.h | 38 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 2 | ||||
-rw-r--r-- | libs/ardour/route.cc | 54 | ||||
-rw-r--r-- | libs/ardour/session.cc | 99 | ||||
-rw-r--r-- | libs/gtkmm2ext/stateful_button.cc | 1 |
5 files changed, 159 insertions, 35 deletions
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index f9ba1a8e8a..6068103896 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -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; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 8f0a2504eb..014b49b318 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -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 (); diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index c57594da37..325e6c42fa 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -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)); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index f41b4f8fba..b213439aba 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -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; diff --git a/libs/gtkmm2ext/stateful_button.cc b/libs/gtkmm2ext/stateful_button.cc index d8bb1f212f..0548b8392b 100644 --- a/libs/gtkmm2ext/stateful_button.cc +++ b/libs/gtkmm2ext/stateful_button.cc @@ -74,7 +74,6 @@ StateButton::set_visual_state (int n) } set_widget_name (name); - visual_state = n; } |