summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-03-12 22:58:00 -0500
committerPaul Davis <paul@linuxaudiosystems.com>2016-05-31 15:30:40 -0400
commit194b213456df43cb522651db6f27286a48eadec6 (patch)
tree5b415907ecd38ad92b79834b56105a821ce961e1 /libs/ardour
parent5531c834963726d5a35db078e17a7508f2b9d72d (diff)
add implicit mute state to MuteMaster and use when a master of a mute control is enabled/disabled. Add AutomationControl::master_changed() as a virtual method to handle ... master value changes
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/automation_control.h1
-rw-r--r--libs/ardour/ardour/mute_master.h14
-rw-r--r--libs/ardour/ardour/route.h54
-rw-r--r--libs/ardour/ardour/session_solo_notifications.h53
-rw-r--r--libs/ardour/ardour/vca.h13
-rw-r--r--libs/ardour/automation_control.cc20
-rw-r--r--libs/ardour/mute_master.cc8
-rw-r--r--libs/ardour/route.cc29
-rw-r--r--libs/ardour/route_controls.cc54
-rw-r--r--libs/ardour/session_rtevents.cc2
-rw-r--r--libs/ardour/vca.cc80
11 files changed, 150 insertions, 178 deletions
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
index 9462a79748..455e8891c1 100644
--- a/libs/ardour/ardour/automation_control.h
+++ b/libs/ardour/ardour/automation_control.h
@@ -156,6 +156,7 @@ public:
Masters _masters;
PBD::ScopedConnectionList masters_connections;
+ virtual void master_changed (bool from_self, GroupControlDisposition gcd);
void master_going_away (boost::weak_ptr<AutomationControl>);
virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
virtual double get_masters_value_locked () const;
diff --git a/libs/ardour/ardour/mute_master.h b/libs/ardour/ardour/mute_master.h
index d88cbdcd39..14597cb56b 100644
--- a/libs/ardour/ardour/mute_master.h
+++ b/libs/ardour/ardour/mute_master.h
@@ -66,17 +66,21 @@ class LIBARDOUR_API MuteMaster : public SessionHandleRef, public PBD::Stateful
void set_soloed_by_others (bool yn) { _soloed_by_others = yn; }
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; }
+
PBD::Signal0<void> MutePointChanged;
XMLNode& get_state();
int set_state(const XMLNode&, int version);
private:
- volatile MutePoint _mute_point;
- volatile bool _muted_by_self;
- volatile bool _soloed_by_self;
- volatile bool _soloed_by_others;
- volatile bool _solo_ignore;
+ MutePoint _mute_point;
+ bool _muted_by_self;
+ bool _soloed_by_self;
+ bool _soloed_by_others;
+ bool _solo_ignore;
+ int32_t _muted_by_others;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 0afafe82eb..9abe56afcb 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -160,7 +160,8 @@ public:
bool muted () const;
void set_mute (bool yn, PBD::Controllable::GroupControlDisposition);
- bool muted_by_others() const;
+ bool muted_by_others_soloing () const;
+ bool muted_by_others () const;
/* controls use set_solo() to modify this route's solo state
*/
@@ -508,17 +509,57 @@ public:
};
class SoloControllable : public BooleanRouteAutomationControl {
- public:
+ public:
SoloControllable (std::string name, boost::shared_ptr<Route>);
void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
void set_value_unchecked (double);
double get_value () const;
- private:
+
+ /* Export additional API so that objects that only get access
+ * to a Controllable/AutomationControl can do more fine-grained
+ * operations with respect to solo. Obviously, they would need
+ * to dynamic_cast<Route::SoloControllable> first.
+ *
+ * Solo state is not representable by a single scalar value,
+ * so this AutomationControl maps set_value() and get_value()
+ * to r->set_self_solo() and r->soloed() respectively. This
+ * means that the Controllable is technically asymmetric. It is
+ * possible to call ::set_value (0.0) to disable (self)solo,
+ * and then call ::get_value() and get a return of 1.0 because
+ * the Route owner is soloed by upstream/downstream.
+ */
+
+ void set_self_solo (bool yn) {
+ boost::shared_ptr<Route> r(_route.lock()); if (r) r->set_self_solo (yn);
+ }
+ void mod_solo_by_others_upstream (int32_t delta) {
+ boost::shared_ptr<Route> r(_route.lock()); if (r) r->mod_solo_by_others_upstream (delta);
+ }
+ void mod_solo_by_others_downstream (int32_t delta) {
+ boost::shared_ptr<Route> r(_route.lock()); if (r) r->mod_solo_by_others_downstream (delta);
+ }
+ bool soloed_by_others () const {
+ boost::shared_ptr<Route> r(_route.lock()); if (r) return r->soloed_by_others(); else return false;
+ }
+ bool soloed_by_others_upstream () const {
+ boost::shared_ptr<Route> r(_route.lock()); if (r) return r->soloed_by_others_upstream(); else return false;
+ }
+ bool soloed_by_others_downstream () const {
+ boost::shared_ptr<Route> r(_route.lock()); if (r) return r->soloed_by_others_downstream(); else return false;
+ }
+ bool self_soloed () const {
+ boost::shared_ptr<Route> r(_route.lock()); if (r) return r->self_soloed(); else return false;
+ }
+
+ protected:
+ void master_changed (bool, PBD::Controllable::GroupControlDisposition);
+
+ private:
void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
};
struct MuteControllable : public BooleanRouteAutomationControl {
- public:
+ public:
MuteControllable (std::string name, boost::shared_ptr<Route>);
void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
void set_value_unchecked (double);
@@ -526,7 +567,10 @@ public:
/* Pretend to change value, but do not affect actual route mute. */
void set_superficial_value(bool muted);
- private:
+ protected:
+ void master_changed (bool, PBD::Controllable::GroupControlDisposition);
+
+ private:
boost::weak_ptr<Route> _route;
void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
};
diff --git a/libs/ardour/ardour/session_solo_notifications.h b/libs/ardour/ardour/session_solo_notifications.h
deleted file mode 100644
index bfb2e7d333..0000000000
--- a/libs/ardour/ardour/session_solo_notifications.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- Copyright (C) 2016 Paul Davis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __libardour_session_solo_notifications_h__
-#define __libardour_session_solo_notifications_h__
-
-#include <boost/shared_ptr.hpp>
-#include "pbd/controllable.h"
-
-namespace ARDOUR {
-
-class Route;
-
-template<typename T>
-class SessionSoloNotifications
-{
- public:
- void solo_changed (bool self_solo_change, PBD::Controllable::GroupControlDisposition gcd, boost::shared_ptr<Route> route) {
- static_cast<T*>(this)->_route_solo_changed (self_solo_change, gcd, route);
- }
-
- void listen_changed (PBD::Controllable::GroupControlDisposition gcd, boost::shared_ptr<Route> route) {
- static_cast<T*>(this)->_route_listen_changed (gcd, route);
- }
-
- void mute_changed () {
- static_cast<T*>(this)->_route_mute_changed ();
- }
-
- void solo_isolated_changed (boost::shared_ptr<Route> route) {
- static_cast<T*>(this)->_route_solo_isolated_changed (route);
- }
-};
-
-} /* namespace */
-
-#endif /* __libardour_session_solo_notifications_h__ */
diff --git a/libs/ardour/ardour/vca.h b/libs/ardour/ardour/vca.h
index 82e0e7acd2..dc48ffa480 100644
--- a/libs/ardour/ardour/vca.h
+++ b/libs/ardour/ardour/vca.h
@@ -46,11 +46,6 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
XMLNode& get_state();
int set_state (XMLNode const&, int version);
- void add_solo_target (boost::shared_ptr<Route>);
- void remove_solo_target (boost::shared_ptr<Route>);
- void add_mute_target (boost::shared_ptr<Route>);
- void remove_mute_target (boost::shared_ptr<Route>);
-
bool soloed () const;
bool muted () const;
@@ -128,14 +123,6 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
uint32_t _number;
- RouteList solo_targets;
- PBD::ScopedConnectionList solo_connections;
- mutable Glib::Threads::RWLock solo_lock;
-
- RouteList mute_targets;
- PBD::ScopedConnectionList mute_connections;
- mutable Glib::Threads::RWLock mute_lock;
-
boost::shared_ptr<GainControl> _gain_control;
boost::shared_ptr<VCASoloControllable> _solo_control;
boost::shared_ptr<VCAMuteControllable> _mute_control;
diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc
index 2ac6574528..b00c615625 100644
--- a/libs/ardour/automation_control.cc
+++ b/libs/ardour/automation_control.cc
@@ -119,8 +119,6 @@ AutomationControl::set_value (double value, PBD::Controllable::GroupControlDispo
Control::set_double (value, _session.transport_frame(), to_list);
- cerr << "AC was set to " << value << endl;
-
Changed (true, gcd);
}
@@ -301,17 +299,23 @@ AutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
*/
- m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&PBD::Signal2<void,bool,Controllable::GroupControlDisposition>::operator(), &Changed, false, _2));
+ m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&AutomationControl::master_changed, this, _1, _2));
}
new_value = get_value_locked ();
}
if (res.second) {
+ /* this will notify everyone that we're now slaved to the master */
MasterStatusChange (); /* EMIT SIGNAL */
}
if (new_value != current_value) {
+ /* force a call to to ::master_changed() to carry the
+ * consequences that would occur if the master assumed
+ * its current value WHILE we were slaved.
+ */
+ master_changed (false, Controllable::NoGroup);
/* effective value changed by master */
Changed (false, Controllable::NoGroup);
}
@@ -319,6 +323,16 @@ AutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
}
void
+AutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd)
+{
+ /* our value has (likely) changed, but not because we were
+ * modified. Just the master.
+ */
+
+ Changed (false, gcd); /* EMIT SIGNAL */
+}
+
+void
AutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
{
boost::shared_ptr<AutomationControl> m = wm.lock();
diff --git a/libs/ardour/mute_master.cc b/libs/ardour/mute_master.cc
index 4b83d57a9b..dc40d1fd6b 100644
--- a/libs/ardour/mute_master.cc
+++ b/libs/ardour/mute_master.cc
@@ -41,6 +41,7 @@ MuteMaster::MuteMaster (Session& s, const std::string&)
, _soloed_by_self (false)
, _soloed_by_others (false)
, _solo_ignore (false)
+ , _muted_by_others (0)
{
if (Config->get_mute_affects_pre_fader ()) {
@@ -163,6 +164,11 @@ MuteMaster::get_state()
bool
MuteMaster::muted_by_others_at (MutePoint mp) const
{
- return (!_solo_ignore && _session.soloing() && (_mute_point & mp));
+ return (!_solo_ignore && (_muted_by_others || _session.soloing()) && (_mute_point & mp));
}
+void
+MuteMaster::mod_muted_by_others (int32_t delta)
+{
+ _muted_by_others = max (0, _muted_by_others + delta);
+}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index c9b9aff3ac..8207176729 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -924,14 +924,6 @@ Route::set_solo (bool yn, Controllable::GroupControlDisposition group_override)
}
assert (Config->get_solo_control_is_listen_control() || !_monitor_send || !_monitor_send->active());
-
- /* XXX TRACKS DEVELOPERS: THIS LOGIC SUGGESTS THAT YOU ARE NOT AWARE OF
- Config->get_solo_mute_overrride().
- */
-
- if (yn && Profile->get_trx()) {
- set_mute (false, Controllable::UseGroup);
- }
}
void
@@ -997,7 +989,8 @@ Route::mod_solo_by_others_upstream (int32_t delta)
}
set_mute_master_solo ();
- _solo_control->Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
+ cerr << name() << " SC->Changed (false, UseGroup)\n";
+ _solo_control->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
}
void
@@ -1151,6 +1144,21 @@ Route::muted () const
}
bool
+Route::muted_by_others_soloing () const
+{
+ // This method is only used by route_ui for display state.
+ // The real thing is MuteMaster::muted_by_others_at()
+
+ //master is never muted by others
+ if (is_master())
+ return false;
+
+ //now check to see if something is soloed (and I am not)
+ //see also MuteMaster::mute_gain_at()
+ return _session.soloing() && !soloed() && !solo_isolated();
+}
+
+bool
Route::muted_by_others () const
{
// This method is only used by route_ui for display state.
@@ -1162,7 +1170,7 @@ Route::muted_by_others () const
//now check to see if something is soloed (and I am not)
//see also MuteMaster::mute_gain_at()
- return (_session.soloing() && !soloed() && !solo_isolated());
+ return _mute_master->muted_by_others() || (_session.soloing() && !soloed() && !solo_isolated());
}
#if 0
@@ -5910,6 +5918,5 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
_gain_control->remove_master (vca->gain_control());
_solo_control->remove_master (vca->solo_control());
_mute_control->remove_master (vca->mute_control());
-
}
}
diff --git a/libs/ardour/route_controls.cc b/libs/ardour/route_controls.cc
index 5992014563..ad5408d06d 100644
--- a/libs/ardour/route_controls.cc
+++ b/libs/ardour/route_controls.cc
@@ -130,6 +130,31 @@ Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<R
}
void
+Route::SoloControllable::master_changed (bool from_self, PBD::Controllable::GroupControlDisposition gcd)
+{
+ boost::shared_ptr<Route> r = _route.lock ();
+
+ if (!r) {
+ return;
+ }
+
+ bool master_soloed;
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (master_lock);
+ master_soloed = (bool) get_masters_value_locked ();
+ }
+
+ /* Master is considered equivalent to an upstream solo control, not
+ * direct control over self-soloed.
+ */
+
+ r->mod_solo_by_others_upstream (master_soloed ? 1 : -1);
+
+ AutomationControl::master_changed (false, gcd);
+}
+
+void
Route::SoloControllable::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
{
if (writable()) {
@@ -158,13 +183,9 @@ Route::SoloControllable::set_value_unchecked (double val)
double
Route::SoloControllable::get_value () const
{
- std::cerr << "RSC get value\n";
-
if (slaved()) {
- std::cerr << "slaved solo control, get master value ... ";
Glib::Threads::RWLock::ReaderLock lm (master_lock);
- double v = get_masters_value_locked () ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
- std::cerr << v << std::endl;
+ return get_masters_value_locked () ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
}
if (_list && ((AutomationList*)_list.get())->automation_playback()) {
@@ -202,6 +223,7 @@ Route::MuteControllable::set_superficial_value(bool muted)
const bool to_list = _list && ((AutomationList*)_list.get ())->automation_write ();
const double where = _session.audible_frame ();
+
if (to_list) {
/* Note that we really need this:
* if (as == Touch && _list->in_new_write_pass ()) {
@@ -219,6 +241,24 @@ Route::MuteControllable::set_superficial_value(bool muted)
}
void
+Route::MuteControllable::master_changed (bool from_self, PBD::Controllable::GroupControlDisposition gcd)
+{
+ bool master_muted;
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (master_lock);
+ master_muted = (bool) get_masters_value_locked ();
+ }
+
+ boost::shared_ptr<Route> r (_route.lock());
+ if (r) {
+ r->mute_master()->mod_muted_by_others (master_muted ? 1 : -1);
+ }
+
+ AutomationControl::master_changed (false, gcd);
+}
+
+void
Route::MuteControllable::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
{
if (writable()) {
@@ -258,7 +298,7 @@ Route::MuteControllable::get_value () const
{
if (slaved()) {
Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return get_masters_value_locked () ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
+ return get_masters_value_locked () ? 1.0 : 0.0;
}
if (_list && ((AutomationList*)_list.get())->automation_playback()) {
@@ -268,7 +308,7 @@ Route::MuteControllable::get_value () const
// Not playing back automation, get the actual route mute value
boost::shared_ptr<Route> r = _route.lock ();
- return (r && r->muted()) ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
+ return (r && r->muted()) ? 1.0 : 0.0;
}
Route::PhaseControllable::PhaseControllable (std::string name, boost::shared_ptr<Route> r)
diff --git a/libs/ardour/session_rtevents.cc b/libs/ardour/session_rtevents.cc
index 68ba15550e..6b807fbf52 100644
--- a/libs/ardour/session_rtevents.cc
+++ b/libs/ardour/session_rtevents.cc
@@ -110,8 +110,10 @@ Session::rt_set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
if (!(*i)->is_auditioner()) {
if (upstream) {
+ std::cerr << "Changing " << (*i)->name() << " upstream by " << delta << std::endl;
(*i)->mod_solo_by_others_upstream (delta);
} else {
+ std::cerr << "Changing " << (*i)->name() << " downstream by " << delta << std::endl;
(*i)->mod_solo_by_others_downstream (delta);
}
}
diff --git a/libs/ardour/vca.cc b/libs/ardour/vca.cc
index 3fec2d9305..d92fa67c03 100644
--- a/libs/ardour/vca.cc
+++ b/libs/ardour/vca.cc
@@ -137,94 +137,14 @@ VCA::set_state (XMLNode const& node, int version)
}
void
-VCA::add_solo_target (boost::shared_ptr<Route> r)
-{
- Glib::Threads::RWLock::WriterLock lm (solo_lock);
- solo_targets.push_back (r);
- r->DropReferences.connect_same_thread (solo_connections, boost::bind (&VCA::solo_target_going_away, this, boost::weak_ptr<Route> (r)));
-}
-
-void
-VCA::remove_solo_target (boost::shared_ptr<Route> r)
-{
- Glib::Threads::RWLock::WriterLock lm (solo_lock);
- solo_targets.remove (r);
-}
-
-void
-VCA::solo_target_going_away (boost::weak_ptr<Route> wr)
-{
- boost::shared_ptr<Route> r (wr.lock());
- if (!r) {
- return;
- }
- remove_solo_target (r);
-}
-
-void
VCA::set_solo (bool yn)
{
- {
- Glib::Threads::RWLock::ReaderLock lm (solo_lock);
-
- if (yn == _solo_requested) {
- return;
- }
-
- if (solo_targets.empty()) {
- return;
- }
-
- boost::shared_ptr<RouteList> rl (new RouteList (solo_targets));
-
- if (Config->get_solo_control_is_listen_control()) {
- _session.set_listen (rl, yn, Session::rt_cleanup, Controllable::NoGroup);
- } else {
- _session.set_implicit_solo (rl, (yn ? 1 : -1), true, Session::rt_cleanup, Controllable::NoGroup);
- }
- }
-
_solo_requested = yn;
}
void
-VCA::add_mute_target (boost::shared_ptr<Route> r)
-{
- Glib::Threads::RWLock::WriterLock lm (mute_lock);
- mute_targets.push_back (r);
- r->DropReferences.connect_same_thread (mute_connections, boost::bind (&VCA::mute_target_going_away, this, boost::weak_ptr<Route> (r)));
-}
-
-void
-VCA::remove_mute_target (boost::shared_ptr<Route> r)
-{
- Glib::Threads::RWLock::WriterLock lm (mute_lock);
- mute_targets.remove (r);
-}
-
-void
-VCA::mute_target_going_away (boost::weak_ptr<Route> wr)
-{
- boost::shared_ptr<Route> r (wr.lock());
- if (!r) {
- return;
- }
- remove_mute_target (r);
-}
-
-void
VCA::set_mute (bool yn)
{
- {
- Glib::Threads::RWLock::ReaderLock lm (mute_lock);
- if (yn == _mute_requested) {
- return;
- }
-
- boost::shared_ptr<RouteList> rl (new RouteList (mute_targets));
- _session.set_mute (rl, yn, Session::rt_cleanup, Controllable::NoGroup);
- }
-
_mute_requested = yn;
}