summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/route_ui.cc20
-rw-r--r--gtk2_ardour/vca_master_strip.cc25
-rw-r--r--libs/ardour/ardour/automation_control.h4
-rw-r--r--libs/ardour/ardour/gain_control.h2
-rw-r--r--libs/ardour/ardour/mute_control.h2
-rw-r--r--libs/ardour/ardour/mute_master.h2
-rw-r--r--libs/ardour/ardour/route.h3
-rw-r--r--libs/ardour/gain_control.cc22
-rw-r--r--libs/ardour/mute_control.cc65
-rw-r--r--libs/ardour/mute_master.cc1
-rw-r--r--libs/ardour/route.cc18
-rw-r--r--libs/ardour/slavable_automation_control.cc79
-rw-r--r--libs/ardour/solo_control.cc3
13 files changed, 162 insertions, 84 deletions
diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc
index 91b14d9c78..3f00966c31 100644
--- a/gtk2_ardour/route_ui.cc
+++ b/gtk2_ardour/route_ui.cc
@@ -415,7 +415,7 @@ RouteUI::mute_press (GdkEventButton* ev)
}
DisplaySuspender ds;
- _session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
+ _session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
@@ -444,7 +444,7 @@ RouteUI::mute_press (GdkEventButton* ev)
}
DisplaySuspender ds;
- _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::InverseGroup);
+ _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
}
} else {
@@ -458,7 +458,7 @@ RouteUI::mute_press (GdkEventButton* ev)
_mute_release->routes = rl;
}
- _session->set_control (_route->mute_control(), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
+ _session->set_control (_route->mute_control(), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
}
}
@@ -1225,10 +1225,12 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
- if (r->muted ()) {
+ std::cerr << r->name() << " self " << r->mute_control()->muted_by_self() << " others " << r->muted_by_others() << " soloing " << r->muted_by_others_soloing() << std::endl;
+
+ if (r->mute_control()->muted_by_self ()) {
/* full mute */
return Gtkmm2ext::ExplicitActive;
- } else if (r->muted_by_others_soloing () || r->mute_control()->get_masters_value()) {
+ } else if (r->muted_by_others_soloing () || r->muted_by_others()) {
/* this will reflect both solo mutes AND master mutes */
return Gtkmm2ext::ImplicitActive;
} else {
@@ -1238,15 +1240,11 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
} else {
- if (r->muted()) {
+ if (r->mute_control()->muted_by_self()) {
/* full mute */
return Gtkmm2ext::ExplicitActive;
} else if (r->muted_by_others()) {
- /* note the direct use of MuteMaster API here. We are
- not interested in showing
- others-soloed-so-this-muted status in this
- conditional branch.
- */
+ /* this shows only master mutes, not mute-by-others-soloing */
return Gtkmm2ext::ImplicitActive;
} else {
/* no mute at all */
diff --git a/gtk2_ardour/vca_master_strip.cc b/gtk2_ardour/vca_master_strip.cc
index 1b1572cf74..6f43228424 100644
--- a/gtk2_ardour/vca_master_strip.cc
+++ b/gtk2_ardour/vca_master_strip.cc
@@ -131,6 +131,8 @@ VCAMasterStrip::VCAMasterStrip (Session* s, boost::shared_ptr<VCA> v)
_vca->solo_control()->Changed.connect (vca_connections, invalidator (*this), boost::bind (&VCAMasterStrip::solo_changed, this), gui_context());
_vca->mute_control()->Changed.connect (vca_connections, invalidator (*this), boost::bind (&VCAMasterStrip::mute_changed, this), gui_context());
+ /* only need to connect to one of these to update VCA status */
+
_vca->gain_control()->MasterStatusChange.connect (vca_connections,
invalidator (*this),
boost::bind (&VCAMasterStrip::update_vca_display, this),
@@ -198,14 +200,20 @@ VCAMasterStrip::set_selected (bool yn)
bool
VCAMasterStrip::solo_release (GdkEventButton*)
{
- _vca->solo_control()->set_value (_vca->solo_control()->get_value() ? 0.0 : 1.0, Controllable::NoGroup);
+ /* We use NoGroup because VCA controls are never part of a group. This
+ is redundant, but clear.
+ */
+ _vca->solo_control()->set_value (_vca->solo_control()->self_soloed() ? 0.0 : 1.0, Controllable::NoGroup);
return true;
}
bool
VCAMasterStrip::mute_release (GdkEventButton*)
{
- _vca->mute_control()->set_value (_vca->mute_control()->get_value() ? 0.0 : 1.0, Controllable::NoGroup);
+ /* We use NoGroup because VCA controls are never part of a group. This
+ is redundant, but clear.
+ */
+ _vca->mute_control()->set_value (_vca->mute_control()->muted_by_self() ? 0.0 : 1.0, Controllable::NoGroup);
return true;
}
@@ -229,8 +237,11 @@ VCAMasterStrip::set_solo_text ()
void
VCAMasterStrip::mute_changed ()
{
- if (_vca->mute_control()->muted()) {
+ std::cerr << "Mute changed for " << _vca->number() << std::endl;
+ if (_vca->mute_control()->muted_by_self()) {
mute_button.set_active_state (ExplicitActive);
+ } else if (_vca->mute_control()->muted_by_others()) {
+ mute_button.set_active_state (ImplicitActive);
} else {
mute_button.set_active_state (Gtkmm2ext::Off);
}
@@ -239,7 +250,7 @@ VCAMasterStrip::mute_changed ()
void
VCAMasterStrip::solo_changed ()
{
- if (_vca->solo_control()->soloed()) {
+ if (_vca->solo_control()->soloed() || _vca->solo_control()->get_masters_value()) {
solo_button.set_active_state (ExplicitActive);
} else {
solo_button.set_active_state (Gtkmm2ext::Off);
@@ -257,10 +268,14 @@ VCAMasterStrip::vca_menu_toggle (CheckMenuItem* menuitem, uint32_t n)
vca_unassign ();
} else {
_vca->gain_control()->remove_master (vca->gain_control());
+ _vca->solo_control()->remove_master (vca->solo_control());
+ _vca->mute_control()->remove_master (vca->mute_control());
}
} else {
if (vca) {
_vca->gain_control()->add_master (vca->gain_control());
+ _vca->mute_control()->add_master (vca->mute_control());
+ _vca->solo_control()->add_master (vca->solo_control());
}
}
}
@@ -269,6 +284,8 @@ void
VCAMasterStrip::vca_unassign ()
{
_vca->gain_control()->clear_masters ();
+ _vca->solo_control()->clear_masters ();
+ _vca->mute_control()->clear_masters ();
}
bool
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
index f576cb52c0..6195f90a68 100644
--- a/libs/ardour/ardour/automation_control.h
+++ b/libs/ardour/ardour/automation_control.h
@@ -152,8 +152,6 @@ class SlavableAutomationControl : public AutomationControl
boost::shared_ptr<ARDOUR::AutomationList> l=boost::shared_ptr<ARDOUR::AutomationList>(),
const std::string& name="");
- ~SlavableAutomationControl ();
-
double get_value () const;
void add_master (boost::shared_ptr<AutomationControl>);
@@ -200,7 +198,7 @@ class SlavableAutomationControl : public AutomationControl
virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
virtual double get_masters_value_locked () const;
double get_value_locked() const;
-
+ void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
};
diff --git a/libs/ardour/ardour/gain_control.h b/libs/ardour/ardour/gain_control.h
index f68ec00452..32d1ad1229 100644
--- a/libs/ardour/ardour/gain_control.h
+++ b/libs/ardour/ardour/gain_control.h
@@ -59,8 +59,6 @@ class LIBARDOUR_API GainControl : public SlavableAutomationControl {
void vcas_loaded();
void recompute_masters_ratios (double val);
-
- void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
};
} /* namespace */
diff --git a/libs/ardour/ardour/mute_control.h b/libs/ardour/ardour/mute_control.h
index 8e5e3fd27a..f7a7814f00 100644
--- a/libs/ardour/ardour/mute_control.h
+++ b/libs/ardour/ardour/mute_control.h
@@ -53,6 +53,7 @@ class LIBARDOUR_API MuteControl : public SlavableAutomationControl
*/
bool muted () const;
+ bool muted_by_self () const;
bool muted_by_others_soloing () const;
bool muted_by_others () const;
@@ -61,6 +62,7 @@ class LIBARDOUR_API MuteControl : public SlavableAutomationControl
MuteMaster::MutePoint mute_points () const;
protected:
+ void master_changed (bool, PBD::Controllable::GroupControlDisposition);
void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override);
private:
diff --git a/libs/ardour/ardour/mute_master.h b/libs/ardour/ardour/mute_master.h
index d147a58771..d8b2bf0021 100644
--- a/libs/ardour/ardour/mute_master.h
+++ b/libs/ardour/ardour/mute_master.h
@@ -70,7 +70,7 @@ class LIBARDOUR_API MuteMaster : public SessionHandleRef, public PBD::Stateful
void set_solo_ignore (bool yn) { _solo_ignore = yn; }
void mod_muted_by_others (int32_t delta);
- bool muted_by_others () const { return _muted_by_others; }
+ int32_t muted_by_others () const { return _muted_by_others; }
PBD::Signal0<void> MutePointChanged;
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 6c0380963d..9f66b95b6c 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -460,8 +460,9 @@ public:
bool can_be_muted_by_others () const { return !is_master(); }
bool muted () const { return _mute_control->muted(); }
+ bool muted_by_others () const { return _mute_control->muted_by_others(); }
+ bool muted_by_self () const { return _mute_control->muted_by_self(); }
bool muted_by_others_soloing () const;
- bool muted_by_others () const;
boost::shared_ptr<SoloIsolateControl> solo_isolate_control() const {
return _solo_isolate_control;
diff --git a/libs/ardour/gain_control.cc b/libs/ardour/gain_control.cc
index 508ddd12a6..3ffeb057da 100644
--- a/libs/ardour/gain_control.cc
+++ b/libs/ardour/gain_control.cc
@@ -43,28 +43,6 @@ GainControl::GainControl (Session& session, const Evoral::Parameter &param, boos
range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
}
-void
-GainControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
-{
- val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
-
- if (!_masters.empty()) {
- recompute_masters_ratios (val);
- }
- }
-
- /* this sets the Evoral::Control::_user_value for us, which will
- be retrieved by AutomationControl::get_value ()
- */
-
- AutomationControl::actually_set_value (val, group_override);
-
- _session.set_dirty ();
-}
-
double
GainControl::internal_to_interface (double v) const
{
diff --git a/libs/ardour/mute_control.cc b/libs/ardour/mute_control.cc
index a639cbda7a..8d35b02445 100644
--- a/libs/ardour/mute_control.cc
+++ b/libs/ardour/mute_control.cc
@@ -42,7 +42,7 @@ MuteControl::MuteControl (Session& session, std::string const & name, Muteable&
void
MuteControl::actually_set_value (double val, Controllable::GroupControlDisposition gcd)
{
- if (muted() != bool (val)) {
+ if (muted_by_self() != bool (val)) {
_muteable.mute_master()->set_muted_by_self (val);
/* allow the Muteable to respond to the mute change
@@ -54,12 +54,63 @@ MuteControl::actually_set_value (double val, Controllable::GroupControlDispositi
AutomationControl::actually_set_value (val, gcd);
}
+void
+MuteControl::master_changed (bool self_change, Controllable::GroupControlDisposition gcd)
+{
+ double m = get_masters_value ();
+ const int32_t old_muted_by_others = _muteable.mute_master()->muted_by_others ();
+ std::cerr << "master " << (self_change ? " self " : " not-self") << " changed to " << m << " old others = " << old_muted_by_others << std::endl;
+
+ _muteable.mute_master()->mod_muted_by_others (m ? 1 : -1);
+
+ if (m) {
+ /* master(s) are now muted. If we are self-muted, this
+ doesn't change our status. If we are not self-muted,
+ then it changes our status if either:
+
+ - the master had its own self-muted status changed OR
+ - the total number of masters that are muted used to be zero
+ */
+
+ if (!muted_by_self()) {
+ if (self_change || old_muted_by_others == 0) {
+ /* note false as the first argument - our own
+ value was not changed
+ */
+ Changed (false, gcd);
+ } else {
+ cerr << " no Change signal\n";
+ }
+ } else {
+ cerr << "muted by self, not relevant\n";
+ }
+ } else {
+ /* no master(s) are now muted. If we are self-muted, this
+ doesn't change our status. If we are not self-muted,
+ then it changes our status if either:
+
+ - the master had its own self-muted status changed OR
+ - the total number of masters that are muted used to be non-zero
+ */
+
+ if (!muted_by_self()) {
+ if (self_change || old_muted_by_others != 0) {
+ Changed (false, gcd);
+ } else {
+ cerr << " No change signal\n";
+ }
+ } else {
+ cerr << "muted by self, not relevant\n";
+ }
+ }
+}
+
double
MuteControl::get_value () const
{
- if (slaved()) {
+ if (slaved ()) {
Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return get_masters_value_locked () ? 1.0 : 0.0;
+ return get_masters_value_locked ();
}
if (_list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback()) {
@@ -90,11 +141,17 @@ MuteControl::mute_points () const
bool
MuteControl::muted () const
{
+ return _muteable.mute_master()->muted_by_self() || _muteable.mute_master()->muted_by_others();
+}
+
+bool
+MuteControl::muted_by_self () const
+{
return _muteable.mute_master()->muted_by_self();
}
bool
MuteControl::muted_by_others () const
{
- return _muteable.mute_master()->muted_by_others () || get_masters_value();
+ return _muteable.mute_master()->muted_by_others ();
}
diff --git a/libs/ardour/mute_master.cc b/libs/ardour/mute_master.cc
index 6817374dc7..c13131c11b 100644
--- a/libs/ardour/mute_master.cc
+++ b/libs/ardour/mute_master.cc
@@ -173,4 +173,5 @@ void
MuteMaster::mod_muted_by_others (int32_t delta)
{
_muted_by_others = max (0, _muted_by_others + delta);
+ std::cerr << this << " mod others by " << delta << " to get " << _muted_by_others << endl;
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index a45e30a91b..7da7e42abf 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -5481,27 +5481,13 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
bool
Route::muted_by_others_soloing () const
{
- // This method is only used by route_ui for display state.
- // The DSP version is MuteMaster::muted_by_others_at()
-
if (!can_be_muted_by_others ()) {
return false;
}
- return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
-}
-
-bool
-Route::muted_by_others () const
-{
- // This method is only used by route_ui for display state.
- // The DSP version is MuteMaster::muted_by_others_at()
-
- if (!can_be_muted_by_others()) {
- return false;
- }
+ /* XXX something needed here re: mute-overrides-solo */
- return _mute_master->muted_by_others();
+ return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
}
void
diff --git a/libs/ardour/slavable_automation_control.cc b/libs/ardour/slavable_automation_control.cc
index 07a2d5633a..624fa484ca 100644
--- a/libs/ardour/slavable_automation_control.cc
+++ b/libs/ardour/slavable_automation_control.cc
@@ -19,6 +19,8 @@
#ifndef __libardour_slavable_automation_control_h__
#define __libardour_slavable_automation_control_h__
+#include "pbd/enumwriter.h"
+
#include "ardour/automation_control.h"
#include "ardour/session.h"
@@ -35,29 +37,26 @@ SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
{
}
-SlavableAutomationControl::~SlavableAutomationControl ()
-{
-
-}
-
double
SlavableAutomationControl::get_masters_value_locked () const
{
- gain_t v = _desc.normal;
+ double v = _desc.normal;
- for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
- if (_desc.toggled) {
- /* if any master is enabled, the slaves are too */
+ if (_desc.toggled) {
+ for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
if (mr->second.master()->get_value()) {
return _desc.upper;
}
- } else {
- /* get current master value, scale by our current ratio with that master */
- v *= mr->second.master()->get_value () * mr->second.ratio();
}
+ return _desc.lower;
+ }
+
+ for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
+ /* get current master value, scale by our current ratio with that master */
+ v *= mr->second.master()->get_value () * mr->second.ratio();
}
- return min (_desc.upper, v);
+ return min ((double) _desc.upper, v);
}
double
@@ -69,6 +68,16 @@ SlavableAutomationControl::get_value_locked() const
return Control::get_double (false, _session.transport_frame());
}
+ if (_desc.toggled) {
+ /* for boolean/toggle controls, if this slave OR any master is
+ * enabled, this slave is enabled. So check our own value
+ * first, because if we are enabled, we can return immediately.
+ */
+ if (Control::get_double (false, _session.transport_frame())) {
+ return _desc.upper;
+ }
+ }
+
return get_masters_value_locked ();
}
@@ -87,6 +96,27 @@ SlavableAutomationControl::get_value() const
}
void
+SlavableAutomationControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
+{
+ val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
+
+ {
+ Glib::Threads::RWLock::WriterLock lm (master_lock);
+
+ if (!_masters.empty()) {
+ recompute_masters_ratios (val);
+ }
+ }
+
+ /* this sets the Evoral::Control::_user_value for us, which will
+ be retrieved by AutomationControl::get_value ()
+ */
+ AutomationControl::actually_set_value (val, group_override);
+
+ _session.set_dirty ();
+}
+
+void
SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
{
double current_value;
@@ -103,7 +133,9 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
if (res.second) {
- recompute_masters_ratios (current_value);
+ if (_desc.toggled) {
+ recompute_masters_ratios (current_value);
+ }
/* note that we bind @param m as a weak_ptr<AutomationControl>, thus
avoiding holding a reference to the control in the binding
@@ -145,13 +177,17 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
void
SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd)
{
- cerr << this << enum_2_string ((AutomationType)_parameter.type()) << " master changed, relay changed along\n";
-
/* our value has (likely) changed, but not because we were
* modified. Just the master.
*/
- Changed (false, gcd); /* EMIT SIGNAL */
+ /* propagate master state into our own control so that if we stop
+ * being slaved, our value doesn't change, and propagate to any
+ * group this control is part of.
+ */
+
+ cerr << this << ' ' << enum_2_string ((AutomationType) _parameter.type()) << " pass along " << get_masters_value() << " from master to group\n";
+ actually_set_value (get_masters_value(), Controllable::UseGroup);
}
void
@@ -168,6 +204,7 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
{
double current_value;
double new_value;
+ bool masters_left;
Masters::size_type erased = 0;
{
@@ -177,6 +214,7 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
if (erased) {
recompute_masters_ratios (current_value);
}
+ masters_left = _masters.size ();
new_value = get_value_locked ();
}
@@ -185,7 +223,12 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
}
if (new_value != current_value) {
- Changed (false, Controllable::NoGroup);
+ if (masters_left == 0) {
+ /* no masters left, make sure we keep the same value
+ that we had before.
+ */
+ actually_set_value (current_value, Controllable::UseGroup);
+ }
}
}
diff --git a/libs/ardour/solo_control.cc b/libs/ardour/solo_control.cc
index 936cc2263a..76e7ca536a 100644
--- a/libs/ardour/solo_control.cc
+++ b/libs/ardour/solo_control.cc
@@ -155,8 +155,7 @@ SoloControl::actually_set_value (double val, PBD::Controllable::GroupControlDisp
be retrieved by AutomationControl::get_value (), and emits Changed
*/
- AutomationControl::actually_set_value (val, group_override);
- _session.set_dirty ();
+ SlavableAutomationControl::actually_set_value (val, group_override);
}
double