mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-24 15:37:48 +01:00
[Summary] Apply Solo, Exclusive Solo, Momentary Solo and Solo isolated to all selected tracks
[Feature reviewed] MKosharnyy [Reviewed] GZharun
This commit is contained in:
parent
bd7bb37206
commit
0655bd6d9a
7 changed files with 275 additions and 65 deletions
|
|
@ -126,15 +126,12 @@ RouteUI::init ()
|
|||
main_mute_check = 0;
|
||||
solo_safe_check = 0;
|
||||
solo_isolated_check = 0;
|
||||
_mute_release = 0;
|
||||
_momentary_solo = false;
|
||||
_was_muted_before_momentary_soloed = false;
|
||||
denormal_menu_item = 0;
|
||||
step_edit_item = 0;
|
||||
multiple_mute_change = false;
|
||||
multiple_solo_change = false;
|
||||
_i_am_the_modifier = 0;
|
||||
|
||||
_momentary_solo = 0;
|
||||
|
||||
setup_invert_buttons ();
|
||||
|
||||
_session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
|
||||
|
|
@ -482,8 +479,6 @@ RouteUI::solo_press(GdkEventButton* ev)
|
|||
return true;
|
||||
}
|
||||
|
||||
multiple_solo_change = false;
|
||||
|
||||
/* Goal here is to use Ctrl as the modifier on all platforms.
|
||||
This is questionable design, but here's how we do it.
|
||||
*/
|
||||
|
|
@ -499,61 +494,102 @@ RouteUI::solo_press(GdkEventButton* ev)
|
|||
#endif
|
||||
int momentary_mask = alt_modifier | Keyboard::TertiaryModifier; /* Alt+Shift */
|
||||
|
||||
if (Keyboard::is_context_menu_event (ev))
|
||||
{
|
||||
if (Keyboard::is_context_menu_event (ev)) {
|
||||
if (solo_menu == 0) {
|
||||
build_solo_menu ();
|
||||
}
|
||||
solo_menu->popup (1, ev->time);
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
if ( ev->button == 1 )
|
||||
{
|
||||
if (Keyboard::modifier_state_equals (ev->state, control_modifier))
|
||||
{
|
||||
if (Keyboard::modifier_state_equals (ev->state, control_modifier)) {
|
||||
|
||||
// control-click: toggle solo isolated status
|
||||
|
||||
_route->set_solo_isolated (!_route->solo_isolated(), this);
|
||||
if ( is_selected () ) {
|
||||
boost::shared_ptr<ARDOUR::RouteList> selected_route_list = get_selected_route_list ();
|
||||
_session->set_solo_isolated_force (selected_route_list, !_route->solo_isolated(), Session::rt_cleanup, true);
|
||||
} else {
|
||||
_route->set_solo_isolated_force (!_route->solo_isolated(), _session);
|
||||
}
|
||||
} else
|
||||
if (Keyboard::modifier_state_equals (ev->state, alt_modifier))
|
||||
{
|
||||
if (Keyboard::modifier_state_equals (ev->state, alt_modifier)) {
|
||||
|
||||
// alt-click: toogle Solo X-Or
|
||||
|
||||
DisplaySuspender ds;
|
||||
if (Config->get_solo_control_is_listen_control()) {
|
||||
_session->set_listen (_session->get_routes(), false, Session::rt_cleanup, true);
|
||||
} else {
|
||||
// Tracks Live doesn't use monitor bus so far
|
||||
//if (Config->get_solo_control_is_listen_control()) {
|
||||
// _session->set_listen (_session->get_routes(), false, Session::rt_cleanup, true);
|
||||
//} else {
|
||||
_session->set_solo (_session->get_routes(), false, Session::rt_cleanup, true);
|
||||
}
|
||||
//}
|
||||
|
||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
||||
rl->push_back (route());
|
||||
|
||||
if (Config->get_solo_control_is_listen_control()) {
|
||||
_session->set_listen (rl, true);
|
||||
} else {
|
||||
if ( is_selected () ) {
|
||||
rl = get_selected_route_list ();
|
||||
} else {
|
||||
rl->push_back (_route);
|
||||
}
|
||||
|
||||
// Tracks Live doesn't use monitor bus so far
|
||||
//if (Config->get_solo_control_is_listen_control()) {
|
||||
// _session->set_listen (rl, true);
|
||||
//} else {
|
||||
_session->set_solo (rl, true);
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (Keyboard::modifier_state_equals (ev->state, momentary_mask))
|
||||
{
|
||||
//}
|
||||
} else {
|
||||
if (Keyboard::modifier_state_equals (ev->state, momentary_mask)) {
|
||||
|
||||
// alt+shift-click: toogle momentary solo
|
||||
_momentary_solo = true;
|
||||
_was_muted_before_momentary_soloed = _route->muted ();
|
||||
|
||||
_momentary_solo = new SoloMuteRelease(true);
|
||||
// is used for muting tracks back after momentary solo release
|
||||
_momentary_solo->routes_on = boost::shared_ptr<ARDOUR::RouteList>(new ARDOUR::RouteList);
|
||||
// is used for unsoloing tracks after momentary solo release
|
||||
_momentary_solo->routes_off = boost::shared_ptr<ARDOUR::RouteList>(new ARDOUR::RouteList);
|
||||
|
||||
if ( is_selected () ) {
|
||||
|
||||
// is used for unsoloing tracks after momentary solo release
|
||||
_momentary_solo->routes_off = get_selected_route_list ();
|
||||
|
||||
for (RouteList::iterator it = _momentary_solo->routes_off->begin(); it != _momentary_solo->routes_off->end(); ++it) {
|
||||
if ( (*it)->muted() )
|
||||
_momentary_solo->routes_on->push_back ( *it );
|
||||
}
|
||||
} else {
|
||||
// is used for unsoloing tracks after momentary solo release
|
||||
_momentary_solo->routes_off->push_back (_route);
|
||||
if (_route->muted ())
|
||||
_momentary_solo->routes_on->push_back (_route);
|
||||
}
|
||||
}
|
||||
|
||||
/* click: solo this route */
|
||||
|
||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
||||
rl->push_back (route());
|
||||
if ( is_selected () ) {
|
||||
|
||||
boost::shared_ptr<ARDOUR::RouteList> selected_route_list = get_selected_route_list ();
|
||||
// DisplaySuspender ds;
|
||||
|
||||
DisplaySuspender ds;
|
||||
if (Config->get_solo_control_is_listen_control()) {
|
||||
_session->set_listen (rl, !_route->listening_via_monitor());
|
||||
} else {
|
||||
_session->set_solo (rl, !_route->self_soloed());
|
||||
}
|
||||
// Tracks Live doesn't use monitor bus so far
|
||||
//if (Config->get_solo_control_is_listen_control()) {
|
||||
// _session->set_listen (selected_route_list, !_route->listening_via_monitor(), Session::rt_cleanup, true);
|
||||
//} else {
|
||||
|
||||
_session->set_solo (selected_route_list, !_route->self_soloed(), Session::rt_cleanup, true);
|
||||
//}
|
||||
} else {
|
||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
||||
rl->push_back (_route);
|
||||
|
||||
// Tracks Live doesn't use monitor bus so far
|
||||
//if (Config->get_solo_control_is_listen_control()) {
|
||||
// _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, true);
|
||||
//} else {
|
||||
_session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, true);
|
||||
//}
|
||||
}
|
||||
}
|
||||
} // if ( ev->button == 1 )
|
||||
}
|
||||
|
|
@ -566,25 +602,20 @@ RouteUI::solo_release (GdkEventButton*)
|
|||
{
|
||||
if ( _momentary_solo )
|
||||
{
|
||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
||||
rl->push_back (route());
|
||||
// Tracks Live doesn't use monitor bus so far
|
||||
//if (Config->get_solo_control_is_listen_control()) {
|
||||
// _session->set_listen (rl, false);
|
||||
//} else {
|
||||
|
||||
if (Config->get_solo_control_is_listen_control()) {
|
||||
_session->set_listen (rl, false);
|
||||
} else {
|
||||
_session->set_solo (rl, false);
|
||||
}
|
||||
// unsolo tracks after momentary solo release
|
||||
_session->set_solo (_momentary_solo->routes_off, false);
|
||||
//}
|
||||
|
||||
_momentary_solo = false;
|
||||
// mute tracks back after momentary solo release
|
||||
_session->set_mute (_momentary_solo->routes_on, true);
|
||||
|
||||
if ( _was_muted_before_momentary_soloed )
|
||||
{
|
||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
||||
rl->push_back (_route);
|
||||
|
||||
_session->set_mute (rl, true);
|
||||
_was_muted_before_momentary_soloed = false;
|
||||
}
|
||||
delete _momentary_solo;
|
||||
_momentary_solo = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -129,8 +129,6 @@ class RouteUI : public Gtk::EventBox, public WavesUI, public virtual AxisView
|
|||
|
||||
bool ignore_toggle;
|
||||
bool wait_for_release;
|
||||
bool multiple_mute_change;
|
||||
bool multiple_solo_change;
|
||||
WavesButton& master_mute_button;
|
||||
WavesButton& mute_button;
|
||||
WavesButton& solo_button;
|
||||
|
|
@ -265,7 +263,7 @@ class RouteUI : public Gtk::EventBox, public WavesUI, public virtual AxisView
|
|||
static PBD::Signal1<void, boost::shared_ptr<ARDOUR::Route> > BusSendDisplayChanged;
|
||||
|
||||
bool dnd_in_progress() {return _dnd_operation_in_progress; }
|
||||
|
||||
|
||||
protected:
|
||||
PBD::ScopedConnectionList route_connections;
|
||||
bool self_destruct;
|
||||
|
|
@ -305,12 +303,9 @@ class RouteUI : public Gtk::EventBox, public WavesUI, public virtual AxisView
|
|||
bool exclusive;
|
||||
};
|
||||
|
||||
SoloMuteRelease* _mute_release;
|
||||
SoloMuteRelease* _momentary_solo;
|
||||
bool is_selected ();
|
||||
boost::shared_ptr<ARDOUR::RouteList> get_selected_route_list ();
|
||||
|
||||
bool _momentary_solo;
|
||||
bool _was_muted_before_momentary_soloed;
|
||||
|
||||
void setup_invert_buttons ();
|
||||
void set_invert_button_state ();
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou
|
|||
bool self_soloed () const { return _self_solo; }
|
||||
|
||||
void set_solo_isolated (bool yn, void *src);
|
||||
void set_solo_isolated_force (bool yn, void *src);
|
||||
bool solo_isolated() const;
|
||||
|
||||
void set_solo_safe (bool yn, void *src);
|
||||
|
|
@ -521,6 +522,7 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou
|
|||
uint32_t _soloed_by_others_upstream;
|
||||
uint32_t _soloed_by_others_downstream;
|
||||
uint32_t _solo_isolated;
|
||||
bool _forced_solo_isolated;
|
||||
|
||||
bool _denormal_protection;
|
||||
|
||||
|
|
|
|||
|
|
@ -697,6 +697,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
void set_listen (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_record_enabled (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_solo_isolated (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_solo_isolated_force (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_monitoring (boost::shared_ptr<RouteList>, MonitorChoice, SessionEvent::RTeventCallback after = rt_cleanup, bool group_override = false);
|
||||
void set_exclusive_input_active (boost::shared_ptr<RouteList> rt, bool onoff, bool flip_others=false);
|
||||
|
||||
|
|
@ -1464,6 +1465,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
void route_listen_changed (void *src, boost::weak_ptr<Route>);
|
||||
void route_mute_changed (void *src);
|
||||
void route_solo_changed (bool self_solo_change, void *src, boost::weak_ptr<Route>);
|
||||
void routes_solo_changed (boost::shared_ptr<RouteList> solo_change_routes);
|
||||
void route_solo_isolated_changed (void *src, boost::weak_ptr<Route>);
|
||||
void update_route_solo_state (boost::shared_ptr<RouteList> r = boost::shared_ptr<RouteList>());
|
||||
|
||||
|
|
@ -1702,6 +1704,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
|||
void rt_set_mute (boost::shared_ptr<RouteList>, bool yn, bool group_override);
|
||||
void rt_set_listen (boost::shared_ptr<RouteList>, bool yn, bool group_override);
|
||||
void rt_set_solo_isolated (boost::shared_ptr<RouteList>, bool yn, bool group_override);
|
||||
void rt_set_solo_isolated_force (boost::shared_ptr<RouteList>, bool yn, bool group_override);
|
||||
void rt_set_record_enabled (boost::shared_ptr<RouteList>, bool yn, bool group_override);
|
||||
void rt_set_monitoring (boost::shared_ptr<RouteList>, MonitorChoice, bool group_override);
|
||||
|
||||
|
|
|
|||
|
|
@ -921,6 +921,12 @@ Route::set_solo_isolated (bool yn, void *src)
|
|||
_solo_isolated++;
|
||||
} else {
|
||||
if (_solo_isolated > 0) {
|
||||
|
||||
// do not drop to 0 if we are forced to be in solo isolated mode
|
||||
if (_forced_solo_isolated && _solo_isolated == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
_solo_isolated--;
|
||||
if (_solo_isolated == 0) {
|
||||
_mute_master->set_solo_ignore (false);
|
||||
|
|
@ -934,6 +940,43 @@ Route::set_solo_isolated (bool yn, void *src)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Route::set_solo_isolated_force (bool yn, void *src)
|
||||
{
|
||||
if (is_master() || is_monitor() || is_auditioner()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
if (yn)
|
||||
{
|
||||
_forced_solo_isolated = true;
|
||||
|
||||
if (_solo_isolated == 0) {
|
||||
_solo_isolated++;
|
||||
_mute_master->set_solo_ignore (true);
|
||||
changed = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_forced_solo_isolated = false;
|
||||
|
||||
if (_solo_isolated > 0) {
|
||||
_solo_isolated--;
|
||||
if (_solo_isolated == 0) {
|
||||
_mute_master->set_solo_ignore (false);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
solo_isolated_changed (src);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Route::solo_isolated () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3397,6 +3397,7 @@ Session::route_listen_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
|
|||
|
||||
update_route_solo_state ();
|
||||
}
|
||||
|
||||
void
|
||||
Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
|
||||
{
|
||||
|
|
@ -3558,6 +3559,120 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
|
|||
set_dirty();
|
||||
}
|
||||
|
||||
void
|
||||
Session::routes_solo_changed (boost::shared_ptr<RouteList> solo_change_routes)
|
||||
{
|
||||
if (solo_update_disabled) {
|
||||
// We know already
|
||||
DEBUG_TRACE (DEBUG::Solo, "solo update disabled - changed ignored\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (solo_change_routes->empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<RouteList> non_solo_change_routes (new RouteList);
|
||||
boost::shared_ptr<RouteList> r = routes.reader ();
|
||||
int32_t delta;
|
||||
|
||||
std::set_difference (r->begin(), r->end(),
|
||||
solo_change_routes->begin(), solo_change_routes->end(),
|
||||
std::back_inserter(*non_solo_change_routes) );
|
||||
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("propagate solo change, delta = %1\n", delta));
|
||||
|
||||
solo_update_disabled = true;
|
||||
RouteList uninvolved;
|
||||
|
||||
for (RouteList::iterator route = solo_change_routes->begin(); route != solo_change_routes->begin(); ++route) {
|
||||
|
||||
if ((*route)->self_soloed() ) {
|
||||
delta = 1;
|
||||
} else {
|
||||
delta = -1;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1\n", (*route)->name()));
|
||||
|
||||
for (RouteList::iterator i = non_solo_change_routes->begin(); i != non_solo_change_routes->end(); ++i) {
|
||||
bool via_sends_only;
|
||||
bool in_signal_flow;
|
||||
|
||||
if ((*i) == *route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
in_signal_flow = false;
|
||||
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed from %1\n", (*i)->name()));
|
||||
|
||||
if ((*i)->feeds (*route, &via_sends_only)) {
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a feed from %1\n", (*i)->name()));
|
||||
if (!via_sends_only) {
|
||||
if (!(*route)->soloed_by_others_upstream()) {
|
||||
(*i)->mod_solo_by_others_downstream (delta);
|
||||
}
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a send-only feed from %1\n", (*i)->name()));
|
||||
}
|
||||
in_signal_flow = true;
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tno feed from %1\n", (*i)->name()));
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed to %1\n", (*i)->name()));
|
||||
|
||||
if ((*route)->feeds (*i, &via_sends_only)) {
|
||||
/* propagate solo upstream only if routing other than
|
||||
sends is involved, but do consider the other route
|
||||
(*i) to be part of the signal flow even if only
|
||||
sends are involved.
|
||||
*/
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 feeds %2 via sends only %3 sboD %4 sboU %5\n",
|
||||
(*route)->name(),
|
||||
(*i)->name(),
|
||||
via_sends_only,
|
||||
(*route)->soloed_by_others_downstream(),
|
||||
(*route)->soloed_by_others_upstream()));
|
||||
if (!via_sends_only) {
|
||||
if (!(*route)->soloed_by_others_downstream()) {
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
|
||||
(*i)->mod_solo_by_others_upstream (delta);
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Solo, "\talready soloed by others downstream\n");
|
||||
}
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tfeed to %1 ignored, sends-only\n", (*i)->name()));
|
||||
}
|
||||
in_signal_flow = true;
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Solo, "\tno feed to\n");
|
||||
}
|
||||
|
||||
if (!in_signal_flow) {
|
||||
uninvolved.push_back (*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
solo_update_disabled = false;
|
||||
DEBUG_TRACE (DEBUG::Solo, "propagation complete\n");
|
||||
|
||||
update_route_solo_state ();
|
||||
|
||||
/* now notify that the mute state of the routes not involved in the signal
|
||||
pathway of the just-solo-changed route may have altered.
|
||||
*/
|
||||
|
||||
for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
|
||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1\n", (*i)->name() ));
|
||||
(*i)->mute_changed (this);
|
||||
}
|
||||
|
||||
SoloChanged (); /* EMIT SIGNAL */
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void
|
||||
Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,12 +62,15 @@ Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeve
|
|||
void
|
||||
Session::rt_set_solo (boost::shared_ptr<RouteList> rl, bool yn, bool /* group_override */)
|
||||
{
|
||||
solo_update_disabled = true;
|
||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||
if (!(*i)->is_auditioner()) {
|
||||
(*i)->set_solo (yn, this);
|
||||
}
|
||||
}
|
||||
|
||||
solo_update_disabled = false;
|
||||
|
||||
routes_solo_changed (rl);
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
|
|
@ -176,6 +179,24 @@ Session::rt_set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, bool /*
|
|||
set_dirty();
|
||||
}
|
||||
|
||||
void
|
||||
Session::set_solo_isolated_force (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
|
||||
{
|
||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo_isolated_force));
|
||||
}
|
||||
|
||||
void
|
||||
Session::rt_set_solo_isolated_force (boost::shared_ptr<RouteList> rl, bool yn, bool /*group_override*/)
|
||||
{
|
||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||
if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner()) {
|
||||
(*i)->set_solo_isolated_force (yn, this);
|
||||
}
|
||||
}
|
||||
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
void
|
||||
Session::set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue