style "solo_button_alternate" = "small_button"
{
#
- # this is the "solo-safe" solo theme
+ # this is the "solo-isolated" solo theme
#
- bg[NORMAL] = { 0.19, 0.97, 0.69 } # solo-safe
- bg[ACTIVE] = { 0.19, 0.97, 0.69 } # solo-safe
- bg[SELECTED] = { 0.19, 0.97, 0.69 } # solo-safe
- bg[PRELIGHT] = { 0.19, 0.97, 0.69 } # solo-safe
+ bg[ACTIVE] = { 0.66, 0.97, 0.19 }
- fg[ACTIVE] = { 0, 0, 0 }
- fg[SELECTED] = { 0, 0, 0 }
- fg[NORMAL] = { 0, 0, 0 }
- fg[PRELIGHT] = { 0, 0, 0 }
+ fg[ACTIVE] = { 1.0, 0, 0 }
+ fg[SELECTED] = { 1.0, 0, 0 }
+ fg[NORMAL] = { 1.0, 0, 0 }
+ fg[PRELIGHT] = { 1.0, 0, 0 }
}
style "solo_button_alternate2" = "small_button"
, dim_all_button (_("dim"))
, mono_button (_("mono"))
, rude_solo_button (_("soloing"))
-
+ , rude_audition_button (_("auditioning"))
+ , exclusive_solo_button (_("Exclusive solo"))
{
Glib::RefPtr<Action> act;
rude_solo_button.set_name ("TransportSoloAlert");
rude_solo_button.show ();
- ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::solo_blink));
+ rude_audition_button.set_name ("TransportAuditioningAlert");
+ rude_audition_button.show ();
+
+ ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
+
rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo), false);
UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
+ rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
+ UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
solo_model_box.set_spacing (6);
solo_model_box.pack_start (solo_in_place_button, false, false);
solo_packer->pack_start (*spin_packer, true, true);
+ exclusive_solo_button.set_name (X_("MonitorCutButton"));
+
upper_packer.set_spacing (12);
upper_packer.pack_start (rude_solo_button, false, false);
+ upper_packer.pack_start (rude_audition_button, false, false);
upper_packer.pack_start (solo_model_box, false, false);
+ upper_packer.pack_start (exclusive_solo_button, false, false);
upper_packer.pack_start (*solo_packer, false, false);
act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
}
}
+void
+MonitorSection::do_blink (bool onoff)
+{
+ solo_blink (onoff);
+ audition_blink (onoff);
+}
+
+void
+MonitorSection::audition_blink (bool onoff)
+{
+ if (_session == 0) {
+ return;
+ }
+
+ if (_session->is_auditioning()) {
+ if (onoff) {
+ rude_audition_button.set_state (STATE_ACTIVE);
+ } else {
+ rude_audition_button.set_state (STATE_NORMAL);
+ }
+ } else {
+ rude_audition_button.set_active (false);
+ rude_audition_button.set_state (STATE_NORMAL);
+ }
+}
+
void
MonitorSection::solo_blink (bool onoff)
{
return true;
}
+bool
+MonitorSection::cancel_audition (GdkEventButton* ev)
+{
+ if (_session) {
+ _session->cancel_audition();
+ }
+ return true;
+}
+
void
MonitorSection::solo_cut_changed ()
{
BindableToggleButton dim_all_button;
BindableToggleButton mono_button;
BindableToggleButton rude_solo_button;
+ BindableToggleButton rude_audition_button;
+ BindableToggleButton exclusive_solo_button;
+ void do_blink (bool);
void solo_blink (bool);
+ void audition_blink (bool);
bool cancel_solo (GdkEventButton*);
+ bool cancel_audition (GdkEventButton*);
void solo_cut_changed ();
void update_solo_model ();
void parameter_changed (std::string);
return true;
}
- _mute_release = new SoloMuteRelease (_route->self_muted ());
+ _mute_release = new SoloMuteRelease (_route->muted ());
}
if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
_mute_release->routes = _session->get_routes ();
}
- _session->set_mute (_session->get_routes(), !_route->self_muted());
+ _session->set_mute (_session->get_routes(), !_route->muted());
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
_mute_release->routes = _session->get_routes ();
}
- _session->set_mute (_session->get_routes(), !_route->self_muted(), Session::rt_cleanup, true);
+ _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
}
} else {
_mute_release->routes = rl;
}
- _session->set_mute (rl, !_route->self_muted());
+ _session->set_mute (rl, !_route->muted());
}
}
if (Config->get_show_solo_mutes()) {
- if (r->self_muted ()) {
+ if (r->muted ()) {
/* full mute */
return 2;
} else if (s->soloing() && !r->soloed() && !r->solo_isolated()) {
} else {
- if (r->self_muted()) {
+ if (r->muted()) {
/* full mute */
return 2;
} else {
return;
}
- bool model = _route->self_muted();
+ bool model = _route->muted();
bool view = mute_button->get_active();
/* first make sure the button's "depressed" visual
MuteMaster (Session& s, const std::string& name);
~MuteMaster() {}
- bool self_muted() const { return _self_muted && (_mute_point != MutePoint (0)); }
- bool muted_by_others() const { return _muted_by_others && (_mute_point != MutePoint (0)); }
- bool muted() const { return (_self_muted || (_muted_by_others > 0)) && (_mute_point != MutePoint (0)); }
- bool muted_at (MutePoint mp) const { return (_self_muted || (_muted_by_others > 0)) && (_mute_point & mp); }
- bool self_muted_at (MutePoint mp) const { return _self_muted && (_mute_point & mp); }
- bool muted_by_others_at (MutePoint mp) const { return (_muted_by_others > 0) && (_mute_point & mp); }
+ bool muted() const { return _muted && (_mute_point != MutePoint (0)); }
+ bool muted_at (MutePoint mp) const { return _muted && (_mute_point & mp); }
bool muted_pre_fader() const { return muted_at (PreFader); }
bool muted_post_fader() const { return muted_at (PostFader); }
gain_t mute_gain_at (MutePoint) const;
- void set_self_muted (bool yn) { _self_muted = yn; }
- void mod_muted_by_others (int delta);
- void clear_muted_by_others ();
+ void set_muted (bool yn) { _muted = yn; }
void mute_at (MutePoint);
void unmute_at (MutePoint);
void set_mute_points (MutePoint);
MutePoint mute_points() const { return _mute_point; }
- void set_solo_level (SoloLevel);
+ void set_soloed (bool);
void set_solo_ignore (bool yn) { _solo_ignore = yn; }
PBD::Signal0<void> MutePointChanged;
private:
volatile MutePoint _mute_point;
- volatile bool _self_muted;
- volatile uint32_t _muted_by_others;
- volatile SoloLevel _solo_level;
+ volatile bool _muted;
+ volatile bool _soloed;
volatile bool _solo_ignore;
};
MuteMaster::MutePoint mute_points() const { return _mute_points; }
bool muted () const;
- bool self_muted () const;
- bool muted_by_others () const;
-
- bool path_muted_by_others() const { return _path_muted_by_others > 0; }
- void mod_path_muted_by_others (int delta);
-
void set_mute (bool yn, void* src);
- void mod_muted_by_others (int delta);
/* controls use set_solo() to modify this route's solo state
*/
boost::shared_ptr<MuteControllable> _mute_control;
boost::shared_ptr<MuteMaster> _mute_master;
MuteMaster::MutePoint _mute_points;
- volatile uint32_t _path_muted_by_others;
std::string _comment;
bool _have_internal_generator;
PreFaderListen
};
- enum SoloLevel {
- NotSoloed,
- DownstreamSoloed,
- UpstreamSoloed,
- SelfSoloed
- };
-
enum AutoConnectOption {
ManualConnect = 0x0,
AutoConnectPhysical = 0x1,
MuteMaster::MuteMaster (Session& s, const std::string&)
: SessionHandleRef (s)
, _mute_point (AllPoints)
- , _self_muted (false)
- , _muted_by_others (0)
+ , _muted (false)
+ , _soloed (false)
, _solo_ignore (false)
{
}
{
if ((_mute_point & mp) != mp) {
_mute_point = MutePoint (_mute_point | mp);
- cerr << "Mute point set, now " << _mute_point << endl;
MutePointChanged (); // EMIT SIGNAL
}
}
{
if ((_mute_point & mp) == mp) {
_mute_point = MutePoint (_mute_point & ~mp);
- cerr << "Mute point unset, now " << _mute_point << endl;
MutePointChanged (); // EMIT SIGNAL
}
}
void
-MuteMaster::clear_muted_by_others ()
+MuteMaster::set_soloed (bool yn)
{
- _muted_by_others = 0;
-}
-
-void
-MuteMaster::mod_muted_by_others (int32_t delta)
-{
- if (delta < 0) {
- if (_muted_by_others >= (uint32_t) abs (delta)) {
- _muted_by_others += delta;
- } else {
- _muted_by_others = 0;
- }
- } else {
- _muted_by_others += delta;
- }
-}
-
-void
-MuteMaster::set_solo_level (SoloLevel l)
-{
- _solo_level = l;
+ _soloed = yn;
}
gain_t
MuteMaster::mute_gain_at (MutePoint mp) const
{
gain_t gain;
- const SoloLevel l = _solo_level;
- // cerr << "solo level = " << _solo_level << " selfmuted " << self_muted_at (mp) << " omute " << muted_by_others_at (mp) << endl;
-
if (Config->get_solo_mute_override()) {
- if ((l == SelfSoloed) || (l == UpstreamSoloed)) {
+ if (_soloed) {
gain = 1.0;
- } else if (self_muted_at (mp)) { // self-muted
- gain = Config->get_solo_mute_gain ();
- } else if (l == DownstreamSoloed) {
- gain = 1.0;
- } else if (muted_by_others_at (mp)) { // muted by others
+ } else if (muted_at (mp)) { // self-muted
gain = Config->get_solo_mute_gain ();
} else {
if (!_solo_ignore && _session.soloing()) {
}
}
} else {
- if (self_muted_at (mp)) { // self-muted
- gain = Config->get_solo_mute_gain ();
- } else if ((l == SelfSoloed) || (l == UpstreamSoloed)) {
- gain = 1.0;
- } else if (muted_by_others_at (mp)) { // muted by others
+ if (muted_at (mp)) { // self-muted
gain = Config->get_solo_mute_gain ();
- } else if (l == DownstreamSoloed) { // soloed by others
+ } else if (_soloed) {
gain = 1.0;
} else {
if (!_solo_ignore && _session.soloing()) {
}
}
- // cerr << "\tgain = " << gain << endl;
-
return gain;
}
MutePoint old = _mute_point;
_mute_point = (MutePoint) string_2_enum (mute_point, _mute_point);
- cerr << "Mute point set from string, now " << _mute_point << endl;
if (old != _mute_point) {
MutePointChanged(); /* EMIT SIGNAL */
{
if (_mute_point != mp) {
_mute_point = mp;
- cerr << "Mute point set from mp, now " << _mute_point << endl;
MutePointChanged (); /* EMIT SIGNAL */
}
}
if ((prop = node.property ("mute-point")) != 0) {
_mute_point = (MutePoint) string_2_enum (prop->value(), _mute_point);
- cerr << "Mute point set from STATE string, now " << _mute_point << endl;
}
if ((prop = node.property ("muted")) != 0) {
- _self_muted = string_is_affirmative (prop->value());
+ _muted = string_is_affirmative (prop->value());
} else {
- _self_muted = (_mute_point != MutePoint (0));
- }
-
- if ((prop = node.property ("muted-by-others")) != 0) {
- if (sscanf (prop->value().c_str(), "%u", &_muted_by_others) != 1) {
- _muted_by_others = 0;
- }
- } else {
- _muted_by_others = 0;
+ _muted = (_mute_point != MutePoint (0));
}
return 0;
{
XMLNode* node = new XMLNode (X_("MuteMaster"));
node->add_property ("mute-point", enum_2_string (_mute_point));
- node->add_property ("muted", (_self_muted ? X_("yes") : X_("no")));
-
- char buf[32];
- snprintf (buf, sizeof (buf), "%u", _muted_by_others);
- node->add_property ("muted-by-others", buf);
-
+ node->add_property ("muted", (_muted ? X_("yes") : X_("no")));
return *node;
}
, _mute_control (new MuteControllable (X_("mute"), *this))
, _mute_master (new MuteMaster (sess, name))
, _mute_points (MuteMaster::AllPoints)
- , _path_muted_by_others (false)
, _have_internal_generator (false)
, _physically_connected (false)
, _graph_level (-1)
_soloed_by_others_upstream += delta;
}
+
/* push the inverse solo change to everything that feeds us.
+
+ This is important for solo-within-group. When we solo 1 track out of N that
+ feed a bus, that track will cause mod_solo_by_upstream (+1) to be called
+ on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all
+ tracks that feed it. This will silence them if they were audible because
+ of a bus solo, but the newly soloed track will still be audible (because
+ it is self-soloed).
+
+ but .. do this only when we are being told to solo-by-upstream (i.e delta = +1),
+ not in reverse.
*/
- for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
- boost::shared_ptr<Route> sr = i->r.lock();
- if (sr) {
- sr->mod_solo_by_others_downstream (-delta);
+ if (delta > 0) {
+ for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
+ boost::shared_ptr<Route> sr = i->r.lock();
+ if (sr) {
+ sr->mod_solo_by_others_downstream (-delta);
+ }
}
}
void
Route::set_mute_master_solo ()
{
- SoloLevel level;
-
- if (self_soloed()) {
- level = SelfSoloed;
- } else if (soloed_by_others_upstream()) {
- level = UpstreamSoloed;
- } else if (soloed_by_others_downstream()) {
- level = DownstreamSoloed;
- } else {
- level = NotSoloed;
- }
-
- _mute_master->set_solo_level (level);
+ _mute_master->set_soloed (self_soloed() || soloed_by_others_downstream() || soloed_by_others_upstream());
}
void
return;
}
- if (self_muted() != yn) {
- _mute_master->set_self_muted (yn);
+ if (muted() != yn) {
+ _mute_master->set_muted (yn);
mute_changed (src); /* EMIT SIGNAL */
}
}
bool
Route::muted () const
{
- return self_muted() || muted_by_others();
-}
-
-bool
-Route::self_muted() const
-{
- return _mute_master->self_muted ();
-}
-
-bool
-Route::muted_by_others() const
-{
- return _mute_master->muted_by_others ();
-}
-
-void
-Route::mod_muted_by_others (int delta)
-{
- if (_solo_isolated) {
- return;
- }
-
- bool old = muted ();
- _mute_master->mod_muted_by_others (delta);
- if (old != muted()) {
- mute_changed (this);
- }
-}
-
-void
-Route::mod_path_muted_by_others (int32_t delta)
-{
- if (delta < 0) {
- if (_path_muted_by_others >= (uint32_t) abs (delta)) {
- _path_muted_by_others += delta;
- } else {
- _path_muted_by_others = 0;
- }
- } else {
- _path_muted_by_others += delta;
- }
+ return _mute_master->muted();
}
#if 0
float
Route::MuteControllable::get_value (void) const
{
- return route.self_muted() ? 1.0f : 0.0f;
+ return route.muted() ? 1.0f : 0.0f;
}
void
error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
return;
}
-
+
shared_ptr<RouteList> r = routes.reader ();
int32_t delta;
} else {
delta = -1;
}
+
+ if (delta == 1 && !Config->get_solo_latched()) {
+ /* new solo: disable all other solos */
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
+ continue;
+ }
+ (*i)->set_solo (false, this);
+ }
+ }
solo_update_disabled = true;
-
- /*
-
- solo a route:
- for anything in the signal path for this route, increment its soloed-by-other count
- for anything not in the signal path for this route, increment its muted-by-other count
-
- unsolo a route:
- for anything in the signal path for this route, decrement its soloed-by-other count
- for anything not in the signal path for this route, decrement its muted-by-other count
-
- */
-
+
RouteList uninvolved;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
in_signal_flow = false;
- /* 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_downstream (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_upstream (delta);
in_signal_flow = true;