diff options
-rw-r--r-- | gtk2_ardour/ardour3_ui_dark.rc.in | 10 | ||||
-rw-r--r-- | gtk2_ardour/ardour_ui2.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_routes.cc | 7 | ||||
-rw-r--r-- | gtk2_ardour/editor_routes.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/mixer_strip.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/route_time_axis.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/route_ui.cc | 25 | ||||
-rw-r--r-- | gtk2_ardour/route_ui.h | 2 | ||||
-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 |
13 files changed, 184 insertions, 64 deletions
diff --git a/gtk2_ardour/ardour3_ui_dark.rc.in b/gtk2_ardour/ardour3_ui_dark.rc.in index f338a736dc..8458d46316 100644 --- a/gtk2_ardour/ardour3_ui_dark.rc.in +++ b/gtk2_ardour/ardour3_ui_dark.rc.in @@ -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" diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc index 8aa28e2685..9991a1dc14 100644 --- a/gtk2_ardour/ardour_ui2.cc +++ b/gtk2_ardour/ardour_ui2.cc @@ -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); } diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index 3d5cb3522c..81a1635e77 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -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 (); } diff --git a/gtk2_ardour/editor_routes.h b/gtk2_ardour/editor_routes.h index b37607aad9..d0798ee5bc 100644 --- a/gtk2_ardour/editor_routes.h +++ b/gtk2_ardour/editor_routes.h @@ -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); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index cb030287ca..6f3d10d94b 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -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 (); diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index bf999d23d6..0c52b96dc3 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -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; diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index ee66bf4c90..816343a2cb 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -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; } } diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index bbe18bfc4f..1dae38d9d9 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -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*); 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; } |