summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-04-08 16:49:47 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2016-05-31 15:30:40 -0400
commit653ae4acd639fef149314fe6f8c7a0d862afae40 (patch)
treeba32ff0efd9b105c207ad7e3b2e89d73e76b4355 /libs
parentc107f1ab56270f4485ca2a787d575c2b5b53cfcf (diff)
universal change in the design of the way Route/Track controls are designed and used. The controls now own their own state, rather than proxy for state in their owners.
Massive changes all over the code to accomodate this. Many things are not finished. Consider this a backup safety commit
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/automation_control.h52
-rw-r--r--libs/ardour/ardour/gain_control.h9
-rw-r--r--libs/ardour/ardour/midi_track.h11
-rw-r--r--libs/ardour/ardour/mute_master.h8
-rw-r--r--libs/ardour/ardour/pan_controllable.h4
-rw-r--r--libs/ardour/ardour/plugin_insert.h8
-rw-r--r--libs/ardour/ardour/route.h279
-rw-r--r--libs/ardour/ardour/route_group.h13
-rw-r--r--libs/ardour/ardour/session.h35
-rw-r--r--libs/ardour/ardour/session_event.h12
-rw-r--r--libs/ardour/ardour/stripable.h22
-rw-r--r--libs/ardour/ardour/track.h61
-rw-r--r--libs/ardour/ardour/types.h3
-rw-r--r--libs/ardour/ardour/utils.h33
-rw-r--r--libs/ardour/ardour/vca.h61
-rw-r--r--libs/ardour/audio_track.cc10
-rw-r--r--libs/ardour/automation_control.cc210
-rw-r--r--libs/ardour/enums.cc15
-rw-r--r--libs/ardour/gain_control.cc42
-rw-r--r--libs/ardour/luabindings.cc8
-rw-r--r--libs/ardour/midi_track.cc80
-rw-r--r--libs/ardour/mute_master.cc4
-rw-r--r--libs/ardour/pan_controllable.cc20
-rw-r--r--libs/ardour/parameter_descriptor.cc1
-rw-r--r--libs/ardour/plugin_insert.cc32
-rw-r--r--libs/ardour/route.cc665
-rw-r--r--libs/ardour/route_controls.cc431
-rw-r--r--libs/ardour/route_graph.cc33
-rw-r--r--libs/ardour/route_group.cc115
-rw-r--r--libs/ardour/session.cc50
-rw-r--r--libs/ardour/session_midi.cc2
-rw-r--r--libs/ardour/session_rtevents.cc249
-rw-r--r--libs/ardour/session_transport.cc2
-rw-r--r--libs/ardour/track.cc246
-rw-r--r--libs/ardour/utils.cc1
-rw-r--r--libs/ardour/vca.cc100
-rw-r--r--libs/ardour/wscript13
-rw-r--r--libs/pbd/pbd/controllable.h1
-rw-r--r--libs/surfaces/control_protocol/control_protocol.cc12
-rw-r--r--libs/surfaces/faderport/faderport.cc8
-rw-r--r--libs/surfaces/faderport/operations.cc20
-rw-r--r--libs/surfaces/mackie/mcp_buttons.cc14
-rw-r--r--libs/surfaces/mackie/strip.cc8
-rw-r--r--libs/surfaces/osc/osc.cc13
44 files changed, 715 insertions, 2301 deletions
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
index 455e8891c1..d84f0a091f 100644
--- a/libs/ardour/ardour/automation_control.h
+++ b/libs/ardour/ardour/automation_control.h
@@ -41,7 +41,7 @@ namespace ARDOUR {
class Session;
class Automatable;
-
+class ControlGroup;
/** A PBD::Controllable with associated automation data (AutomationList)
*/
@@ -50,7 +50,7 @@ class LIBARDOUR_API AutomationControl
, public Evoral::Control
, public boost::enable_shared_from_this<AutomationControl>
{
-public:
+ public:
AutomationControl(ARDOUR::Session&,
const Evoral::Parameter& parameter,
const ParameterDescriptor& desc,
@@ -87,8 +87,6 @@ public:
void stop_touch(bool mark, double when);
/* inherited from PBD::Controllable.
- * Derived classes MUST call ::writable() to verify
- * that writing to the parameter is legal at that time.
*/
double get_value () const;
/* inherited from PBD::Controllable.
@@ -99,10 +97,11 @@ public:
/* automation related value setting */
virtual bool writable () const;
/* Call to ::set_value() with no test for writable() because
- * this is only used by automation playback. We would like
- * to make it pure virtual
+ * this is only used by automation playback.
*/
- virtual void set_value_unchecked (double val) {}
+ void set_value_unchecked (double val) {
+ actually_set_value (val, PBD::Controllable::NoGroup);
+ }
double lower() const { return _desc.lower; }
double upper() const { return _desc.upper; }
@@ -117,6 +116,37 @@ public:
const ARDOUR::Session& session() const { return _session; }
void commit_transaction (bool did_write);
+ void set_group (boost::shared_ptr<ControlGroup>);
+
+ protected:
+ ARDOUR::Session& _session;
+ boost::shared_ptr<ControlGroup> _group;
+
+ const ParameterDescriptor _desc;
+
+ bool check_rt (double val, Controllable::GroupControlDisposition gcd);
+
+ /* derived classes may reimplement this, but should either
+ call this explicitly inside their version OR make sure that the
+ Controllable::Changed signal is emitted when necessary.
+ */
+
+ virtual void actually_set_value (double value, PBD::Controllable::GroupControlDisposition);
+};
+
+class SlavableAutomationControl : public AutomationControl
+{
+ public:
+ SlavableAutomationControl(ARDOUR::Session&,
+ const Evoral::Parameter& parameter,
+ const ParameterDescriptor& desc,
+ 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>);
void remove_master (boost::shared_ptr<AutomationControl>);
void clear_masters ();
@@ -126,11 +156,7 @@ public:
PBD::Signal0<void> MasterStatusChange;
- protected:
- ARDOUR::Session& _session;
-
- const ParameterDescriptor _desc;
-
+ protected:
class MasterRecord {
public:
@@ -155,12 +181,12 @@ public:
typedef std::map<PBD::ID,MasterRecord> Masters;
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;
double get_value_locked() const;
+
};
diff --git a/libs/ardour/ardour/gain_control.h b/libs/ardour/ardour/gain_control.h
index 4ec538e698..f68ec00452 100644
--- a/libs/ardour/ardour/gain_control.h
+++ b/libs/ardour/ardour/gain_control.h
@@ -34,14 +34,11 @@ namespace ARDOUR {
class Session;
-class LIBARDOUR_API GainControl : public AutomationControl {
+class LIBARDOUR_API GainControl : public SlavableAutomationControl {
public:
GainControl (Session& session, const Evoral::Parameter &param,
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>());
- void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
- void set_value_unchecked (double);
-
double internal_to_interface (double) const;
double interface_to_internal (double) const;
double internal_to_user (double) const;
@@ -54,6 +51,8 @@ class LIBARDOUR_API GainControl : public AutomationControl {
int set_state (XMLNode const&, int);
XMLNode& get_state();
+ void inc_gain (gain_t);
+
private:
std::string masters_string;
PBD::ScopedConnection vca_loaded_connection;
@@ -61,7 +60,7 @@ class LIBARDOUR_API GainControl : public AutomationControl {
void vcas_loaded();
void recompute_masters_ratios (double val);
- void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
+ void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
};
} /* namespace */
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index ed13832360..69f4981047 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -50,8 +50,9 @@ public:
boost::shared_ptr<Diskstream> create_diskstream ();
void set_diskstream (boost::shared_ptr<Diskstream>);
- void set_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
- void set_record_safe (bool yn, PBD::Controllable::GroupControlDisposition);
+
+ bool can_be_record_enabled ();
+ bool can_be_record_safe ();
DataType data_type () const {
return DataType::MIDI;
@@ -89,14 +90,12 @@ public:
, _route (route)
{}
- void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
- void set_value_unchecked (double);
bool writable() const { return true; }
MidiTrack* _route;
private:
- void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
+ void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
};
virtual void set_parameter_automation_state (Evoral::Parameter param, AutoState);
@@ -133,7 +132,6 @@ public:
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
- void set_monitoring (MonitorChoice, PBD::Controllable::GroupControlDisposition);
MonitorState monitoring_state () const;
void set_input_active (bool);
@@ -144,6 +142,7 @@ protected:
XMLNode& state (bool full);
void act_on_mute ();
+ void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
private:
MidiRingBuffer<framepos_t> _immediate_events;
diff --git a/libs/ardour/ardour/mute_master.h b/libs/ardour/ardour/mute_master.h
index 14597cb56b..d147a58771 100644
--- a/libs/ardour/ardour/mute_master.h
+++ b/libs/ardour/ardour/mute_master.h
@@ -20,12 +20,15 @@
#ifndef __ardour_mute_master_h__
#define __ardour_mute_master_h__
-#include "evoral/Parameter.hpp"
+#include <string>
+
#include "pbd/signals.h"
#include "pbd/stateful.h"
-#include <string>
+
+#include "evoral/Parameter.hpp"
#include "ardour/session_handle.h"
+#include "ardour/types.h"
namespace ARDOUR {
@@ -73,6 +76,7 @@ class LIBARDOUR_API MuteMaster : public SessionHandleRef, public PBD::Stateful
XMLNode& get_state();
int set_state(const XMLNode&, int version);
+ static const std::string xml_node_name;
private:
MutePoint _mute_point;
diff --git a/libs/ardour/ardour/pan_controllable.h b/libs/ardour/ardour/pan_controllable.h
index 85a4efe2fc..26f0707ff7 100644
--- a/libs/ardour/ardour/pan_controllable.h
+++ b/libs/ardour/ardour/pan_controllable.h
@@ -47,12 +47,10 @@ class LIBARDOUR_API PanControllable : public AutomationControl
{}
double lower () const;
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- void set_value_unchecked (double);
private:
Pannable* owner;
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
+ void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override);
};
} // namespace
diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h
index 4b5f38964a..70bbd76a71 100644
--- a/libs/ardour/ardour/plugin_insert.h
+++ b/libs/ardour/ardour/plugin_insert.h
@@ -185,15 +185,13 @@ class LIBARDOUR_API PluginInsert : public Processor
const ParameterDescriptor& desc,
boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
- void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
- void set_value_unchecked (double);
double get_value (void) const;
void catch_up_with_external_value (double val);
XMLNode& get_state();
private:
PluginInsert* _plugin;
- void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
+ void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
};
/** A control that manipulates a plugin property (message). */
@@ -204,10 +202,10 @@ class LIBARDOUR_API PluginInsert : public Processor
const ParameterDescriptor& desc,
boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
- void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
- void set_value_unchecked (double);
double get_value (void) const;
XMLNode& get_state();
+ protected:
+ void actually_set_value (double value, PBD::Controllable::GroupControlDisposition);
private:
PluginInsert* _plugin;
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 9abe56afcb..6c0380963d 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -28,7 +28,6 @@
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
-#include <boost/dynamic_bitset.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <glibmm/threads.h>
@@ -46,12 +45,18 @@
#include "ardour/io_vector.h"
#include "ardour/libardour_visibility.h"
#include "ardour/types.h"
+#include "ardour/monitorable.h"
+#include "ardour/muteable.h"
#include "ardour/mute_master.h"
+#include "ardour/mute_control.h"
#include "ardour/route_group_member.h"
#include "ardour/stripable.h"
#include "ardour/graphnode.h"
#include "ardour/automatable.h"
#include "ardour/unknown_processor.h"
+#include "ardour/soloable.h"
+#include "ardour/solo_control.h"
+#include "ardour/solo_safe_control.h"
class RoutePinWindowProxy;
@@ -74,8 +79,18 @@ class Pannable;
class CapturingProcessor;
class InternalSend;
class VCA;
-
-class LIBARDOUR_API Route : public Stripable, public Automatable, public RouteGroupMember, public GraphNode, public boost::enable_shared_from_this<Route>
+class SoloIsolateControl;
+class PhaseControl;
+class MonitorControl;
+
+class LIBARDOUR_API Route : public Stripable,
+ public Soloable,
+ public Muteable,
+ public Monitorable,
+ public Automatable,
+ public RouteGroupMember,
+ public GraphNode,
+ public boost::enable_shared_from_this<Route>
{
public:
@@ -119,7 +134,7 @@ public:
bool is_master() const { return _flags & MasterOut; }
bool is_monitor() const { return _flags & MonitorOut; }
- virtual MonitorState monitoring_state () const;
+ MonitorState monitoring_state () const;
virtual MeterState metering_state () const;
/* these are the core of the API of a Route. see the protected sections as well */
@@ -135,10 +150,6 @@ public:
virtual bool can_record() { return false; }
- virtual void set_record_enabled (bool /*yn*/, PBD::Controllable::GroupControlDisposition) {}
- virtual bool record_enabled() const { return false; }
- virtual void set_record_safe (bool /*yn*/, PBD::Controllable::GroupControlDisposition) {}
- virtual bool record_safe () const {return false; }
virtual void nonrealtime_handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
virtual void realtime_handle_transport_stopped () {}
virtual void realtime_locate () {}
@@ -149,47 +160,31 @@ public:
void shift (framepos_t, framecnt_t);
- void set_gain (gain_t val, PBD::Controllable::GroupControlDisposition);
- void inc_gain (gain_t delta);
-
void set_trim (gain_t val, PBD::Controllable::GroupControlDisposition);
- void set_mute_points (MuteMaster::MutePoint);
- MuteMaster::MutePoint mute_points () const;
-
- bool muted () const;
- void set_mute (bool yn, PBD::Controllable::GroupControlDisposition);
-
- bool muted_by_others_soloing () const;
- bool muted_by_others () const;
-
/* controls use set_solo() to modify this route's solo state
*/
- void set_solo (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- bool soloed () const { return self_soloed () || soloed_by_others (); }
void clear_all_solo_state ();
- bool soloed_by_others () const { return _soloed_by_others_upstream||_soloed_by_others_downstream; }
- bool soloed_by_others_upstream () const { return _soloed_by_others_upstream; }
- bool soloed_by_others_downstream () const { return _soloed_by_others_downstream; }
- bool self_soloed () const { return _self_solo; }
-
- void set_solo_isolated (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- bool solo_isolated() const;
+ bool soloed_by_others () const { return _solo_control->soloed_by_others(); }
+ bool soloed_by_others_upstream () const { return _solo_control->soloed_by_others_upstream(); }
+ bool soloed_by_others_downstream () const { return _solo_control->soloed_by_others_downstream(); }
+ bool self_soloed () const { return _solo_control->self_soloed(); }
+ bool soloed () const { return self_soloed () || soloed_by_others (); }
- void set_solo_safe (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- bool solo_safe() const;
+ void push_solo_upstream (int32_t delta);
+ void push_solo_isolate_upstream (int32_t delta);
+ bool can_solo () const {
+ return !(is_master() || is_monitor() || is_auditioner());
+ }
+ bool is_safe () const {
+ return _solo_safe_control->get_value();
+ }
- void set_listen (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
bool listening_via_monitor () const;
void enable_monitor_send ();
- void set_phase_invert (uint32_t, bool yn);
- void set_phase_invert (boost::dynamic_bitset<>);
- bool phase_invert (uint32_t) const;
- boost::dynamic_bitset<> phase_invert () const;
-
void set_denormal_protection (bool yn);
bool denormal_protection() const;
@@ -353,7 +348,6 @@ public:
PBD::Signal0<void> active_changed;
PBD::Signal0<void> denormal_protection_changed;
PBD::Signal0<void> comment_changed;
- PBD::Signal0<void> mute_points_changed;
/** track numbers - assigned by session
* nubers > 0 indicate tracks (audio+midi)
@@ -456,185 +450,32 @@ public:
boost::shared_ptr<AutomationControl> get_control (const Evoral::Parameter& param);
- class RouteAutomationControl : public AutomationControl {
- public:
- RouteAutomationControl (const std::string& name,
- AutomationType atype,
- boost::shared_ptr<AutomationList> alist,
- boost::shared_ptr<Route> route);
- protected:
- friend class Route;
-
- void route_set_value (double val) {
- AutomationControl::set_value (val, Controllable::NoGroup);
- }
-
- boost::weak_ptr<Route> _route;
- };
-
- class BooleanRouteAutomationControl : public RouteAutomationControl {
- public:
- BooleanRouteAutomationControl (const std::string& name,
- AutomationType atype,
- boost::shared_ptr<AutomationList> alist,
- boost::shared_ptr<Route> route)
- : RouteAutomationControl (name, atype, alist, route) {}
- protected:
- double get_masters_value_locked() const;
-
- };
-
- class GainControllable : public GainControl {
- public:
- GainControllable (Session& session,
- AutomationType type,
- boost::shared_ptr<Route> route);
-
- void set_value (double val, PBD::Controllable::GroupControlDisposition group_override) {
- boost::shared_ptr<Route> r = _route.lock();
- if (r) {
- /* Route must mediate group control */
- r->set_control ((AutomationType) parameter().type(), val, group_override);
- }
- }
-
- protected:
- friend class Route;
-
- void route_set_value (double val) {
- GainControl::set_value (val, Controllable::NoGroup);
- }
-
- boost::weak_ptr<Route> _route;
- };
-
- class SoloControllable : public BooleanRouteAutomationControl {
- 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;
-
- /* 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:
- MuteControllable (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;
-
- /* Pretend to change value, but do not affect actual route mute. */
- void set_superficial_value(bool muted);
- protected:
- void master_changed (bool, PBD::Controllable::GroupControlDisposition);
-
- private:
- boost::weak_ptr<Route> _route;
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- };
-
- class LIBARDOUR_API PhaseControllable : public BooleanRouteAutomationControl {
- public:
- PhaseControllable (std::string name, boost::shared_ptr<Route>);
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- /* currently no automation, so no need for set_value_unchecked() */
- void set_channel (uint32_t);
- double get_value () const;
- uint32_t channel() const;
- private:
- uint32_t _current_phase;
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- };
-
- class LIBARDOUR_API SoloIsolateControllable : public BooleanRouteAutomationControl {
- public:
- SoloIsolateControllable (std::string name, boost::shared_ptr<Route>);
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- /* currently no automation, so no need for set_value_unchecked() */
- double get_value () const;
- private:
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- };
-
- class LIBARDOUR_API SoloSafeControllable : public BooleanRouteAutomationControl {
- public:
- SoloSafeControllable (std::string name, boost::shared_ptr<Route>);
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- /* currently no automation, so no need for set_value_unchecked() */
- double get_value () const;
- private:
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- };
-
- void set_control (AutomationType, double val, PBD::Controllable::GroupControlDisposition group_override);
-
- boost::shared_ptr<AutomationControl> solo_control() const {
+ boost::shared_ptr<SoloControl> solo_control() const {
return _solo_control;
}
- boost::shared_ptr<AutomationControl> mute_control() const {
+ boost::shared_ptr<MuteControl> mute_control() const {
return _mute_control;
}
- boost::shared_ptr<MuteMaster> mute_master() const {
- return _mute_master;
- }
+ bool can_be_muted_by_others () const { return !is_master(); }
+ bool muted () const { return _mute_control->muted(); }
+ bool muted_by_others_soloing () const;
+ bool muted_by_others () const;
- boost::shared_ptr<AutomationControl> solo_isolate_control() const {
+ boost::shared_ptr<SoloIsolateControl> solo_isolate_control() const {
return _solo_isolate_control;
}
- boost::shared_ptr<AutomationControl> solo_safe_control() const {
+ boost::shared_ptr<SoloSafeControl> solo_safe_control() const {
return _solo_safe_control;
}
- boost::shared_ptr<AutomationControl> monitoring_control() const {
+ boost::shared_ptr<MonitorControl> monitoring_control() const {
/* tracks override this to provide actual monitoring control;
busses have no possible choices except input monitoring.
*/
- return boost::shared_ptr<AutomationControl> ();
+ return boost::shared_ptr<MonitorControl> ();
}
/* Route doesn't own these items, but sub-objects that it does own have them
@@ -647,8 +488,8 @@ public:
boost::shared_ptr<Pannable> pannable() const;
boost::shared_ptr<GainControl> gain_control() const;
- boost::shared_ptr<AutomationControl> trim_control() const;
- boost::shared_ptr<AutomationControl> phase_control() const;
+ boost::shared_ptr<GainControl> trim_control() const;
+ boost::shared_ptr<PhaseControl> phase_control() const;
/**
Return the first processor that accepts has at least one MIDI input
@@ -766,8 +607,8 @@ public:
friend class Session;
void catch_up_on_solo_mute_override ();
- void mod_solo_by_others_upstream (int32_t);
- void mod_solo_by_others_downstream (int32_t);
+ void set_listen (bool);
+
void curve_reallocate ();
virtual void set_block_size (pframes_t nframes);
@@ -829,14 +670,6 @@ protected:
MeterPoint _meter_point;
MeterPoint _pending_meter_point;
MeterType _meter_type;
- boost::dynamic_bitset<> _phase_invert;
- bool _self_solo;
- uint32_t _soloed_by_others_upstream;
- uint32_t _soloed_by_others_downstream;
- bool _solo_isolated;
- uint32_t _solo_isolated_by_upstream;
-
- void mod_solo_isolated_by_upstream (bool);
bool _denormal_protection;
@@ -844,18 +677,14 @@ protected:
bool _silent : 1;
bool _declickable : 1;
- boost::shared_ptr<SoloControllable> _solo_control;
- boost::shared_ptr<MuteControllable> _mute_control;
- boost::shared_ptr<MuteMaster> _mute_master;
- boost::shared_ptr<PhaseControllable> _phase_control;
- boost::shared_ptr<SoloIsolateControllable> _solo_isolate_control;
- boost::shared_ptr<SoloSafeControllable> _solo_safe_control;
-
- virtual void act_on_mute () {}
+ boost::shared_ptr<SoloControl> _solo_control;
+ boost::shared_ptr<MuteControl> _mute_control;
+ boost::shared_ptr<PhaseControl> _phase_control;
+ boost::shared_ptr<SoloIsolateControl> _solo_isolate_control;
+ boost::shared_ptr<SoloSafeControl> _solo_safe_control;
std::string _comment;
bool _have_internal_generator;
- bool _solo_safe;
DataType _default_type;
FedBy _fed_by;
@@ -882,9 +711,9 @@ protected:
virtual void maybe_declick (BufferSet&, framecnt_t, int);
- boost::shared_ptr<GainControllable> _gain_control;
+ boost::shared_ptr<GainControl> _gain_control;
boost::shared_ptr<Amp> _amp;
- boost::shared_ptr<GainControllable> _trim_control;
+ boost::shared_ptr<GainControl> _trim_control;
boost::shared_ptr<Amp> _trim;
boost::shared_ptr<PeakMeter> _meter;
boost::shared_ptr<DelayLine> _delayline;
@@ -928,7 +757,6 @@ private:
void placement_range (Placement p, ProcessorList::iterator& start, ProcessorList::iterator& end);
void set_self_solo (bool yn);
- void set_mute_master_solo ();
void set_processor_positions ();
framecnt_t update_port_latencies (PortSet& ports, PortSet& feeders, bool playback, framecnt_t) const;
@@ -985,6 +813,7 @@ private:
void reset_instrument_info ();
void set_remote_control_id_internal (uint32_t id, bool notify_class_listeners = true);
+ void solo_control_changed (bool self, PBD::Controllable::GroupControlDisposition);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h
index 95affaeaf5..feeac6a467 100644
--- a/libs/ardour/ardour/route_group.h
+++ b/libs/ardour/ardour/route_group.h
@@ -29,10 +29,12 @@
#include "pbd/signals.h"
#include "pbd/stateful.h"
-#include "ardour/libardour_visibility.h"
+#include "ardour/control_group.h"
#include "ardour/types.h"
#include "ardour/session_object.h"
+#include "ardour/libardour_visibility.h"
+
namespace ARDOUR {
namespace Properties {
@@ -157,8 +159,17 @@ class LIBARDOUR_API RouteGroup : public SessionObject
PBD::Property<bool> _color;
PBD::Property<bool> _monitoring;
+ boost::shared_ptr<ControlGroup> _solo_group;
+ boost::shared_ptr<ControlGroup> _mute_group;
+ boost::shared_ptr<ControlGroup> _rec_enable_group;
+ boost::shared_ptr<ControlGroup> _gain_group;
+ boost::shared_ptr<ControlGroup> _monitoring_group;
+
void remove_when_going_away (boost::weak_ptr<Route>);
int set_state_2X (const XMLNode&, int);
+
+ void post_set (PBD::PropertyChange const &);
+ void push_to_groups ();
};
} /* namespace */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 18507ee5d9..786751dea5 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -791,16 +791,13 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
static const SessionEvent::RTeventCallback rt_cleanup;
- void set_solo (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- void set_implicit_solo (boost::shared_ptr<RouteList>, int delta, bool up_or_downstream, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
void clear_all_solo_state (boost::shared_ptr<RouteList>);
- void set_just_one_solo (boost::shared_ptr<Route>, bool, SessionEvent::RTeventCallback after = rt_cleanup);
- void set_mute (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- void set_listen (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- void set_record_enabled (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- void set_record_safe (boost::shared_ptr<RouteList>, bool yn, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- void set_solo_isolated (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
- void set_monitoring (boost::shared_ptr<RouteList>, MonitorChoice, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
+
+ /* Control-based methods */
+
+ void set_controls (boost::shared_ptr<ControlList>, double val, PBD::Controllable::GroupControlDisposition);
+ void set_control (boost::shared_ptr<AutomationControl>, double val, PBD::Controllable::GroupControlDisposition);
+
void set_exclusive_input_active (boost::shared_ptr<RouteList> rt, bool onoff, bool flip_others = false);
PBD::Signal1<void,bool> SoloActive;
@@ -1936,16 +1933,18 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
return ev;
}
- void rt_set_solo (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
- void rt_set_implicit_solo (boost::shared_ptr<RouteList>, int delta, bool up_or_downstream, PBD::Controllable::GroupControlDisposition);
+ /* specialized version realtime "apply to set of controls" operations */
+ SessionEvent* get_rt_event (boost::shared_ptr<ControlList> cl, double arg, PBD::Controllable::GroupControlDisposition group_override) {
+ SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+ ev->rt_slot = boost::bind (&Session::rt_set_controls, this, cl, arg, group_override);
+ ev->rt_return = Session::rt_cleanup;
+ ev->event_loop = PBD::EventLoop::get_event_loop_for_thread ();
+
+ return ev;
+ }
+
+ void rt_set_controls (boost::shared_ptr<ControlList>, double val, PBD::Controllable::GroupControlDisposition group_override);
void rt_clear_all_solo_state (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
- void rt_set_just_one_solo (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition /* ignored*/ );
- void rt_set_mute (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
- void rt_set_listen (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
- void rt_set_solo_isolated (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
- void rt_set_record_enabled (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
- void rt_set_record_safe (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
- void rt_set_monitoring (boost::shared_ptr<RouteList>, MonitorChoice, PBD::Controllable::GroupControlDisposition group_override);
/** temporary list of Diskstreams used only during load of 2.X sessions */
std::list<boost::shared_ptr<Diskstream> > _diskstreams_2X;
diff --git a/libs/ardour/ardour/session_event.h b/libs/ardour/ardour/session_event.h
index cca7f1274e..8bb160b90e 100644
--- a/libs/ardour/ardour/session_event.h
+++ b/libs/ardour/ardour/session_event.h
@@ -84,26 +84,28 @@ public:
union {
void* ptr;
bool yes_or_no;
- framepos_t target2_frame;
+ framepos_t target2_frame;
Slave* slave;
Route* route;
};
union {
bool second_yes_or_no;
+ double control_value;
};
union {
bool third_yes_or_no;
};
- /* 4 members to handle a multi-group event handled in RT context */
+ /* 5 members to handle a multi-group event handled in RT context */
typedef boost::function<void (SessionEvent*)> RTeventCallback;
- boost::shared_ptr<RouteList> routes; /* apply to */
- boost::function<void (void)> rt_slot; /* what to call in RT context */
- RTeventCallback rt_return; /* called after rt_slot, with this event as an argument */
+ boost::shared_ptr<ControlList> controls; /* apply to */
+ boost::shared_ptr<RouteList> routes; /* apply to */
+ boost::function<void (void)> rt_slot; /* what to call in RT context */
+ RTeventCallback rt_return; /* called after rt_slot, with this event as an argument */
PBD::EventLoop* event_loop;
std::list<AudioRange> audio_range;
diff --git a/libs/ardour/ardour/stripable.h b/libs/ardour/ardour/stripable.h
index e97fe79103..f68cb07b91 100644
--- a/libs/ardour/ardour/stripable.h
+++ b/libs/ardour/ardour/stripable.h
@@ -26,13 +26,19 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "ardour/gain_control.h"
#include "ardour/session_object.h"
namespace ARDOUR {
class AutomationControl;
+class GainControl;
class PeakMeter;
+class SoloControl;
+class MuteControl;
+class PhaseControl;
+class SoloIsolateControl;
+class SoloSafeControl;
+class MonitorControl;
/* This is a virtual base class for any object that needs to be potentially
* represented by a control-centric user interface using the general model of a
@@ -58,12 +64,13 @@ class Stripable : public SessionObject {
virtual boost::shared_ptr<GainControl> gain_control() const = 0;
- virtual boost::shared_ptr<AutomationControl> solo_control() const = 0;
- virtual boost::shared_ptr<AutomationControl> mute_control() const = 0;
- virtual boost::shared_ptr<AutomationControl> phase_control() const = 0;
- virtual boost::shared_ptr<AutomationControl> trim_control() const = 0;
+ virtual boost::shared_ptr<SoloControl> solo_control() const = 0;
+ virtual boost::shared_ptr<MuteControl> mute_control() const = 0;
- virtual boost::shared_ptr<AutomationControl> monitoring_control() const = 0;
+ virtual boost::shared_ptr<PhaseControl> phase_control() const = 0;
+ virtual boost::shared_ptr<GainControl> trim_control() const = 0;
+
+ virtual boost::shared_ptr<MonitorControl> monitoring_control() const = 0;
virtual boost::shared_ptr<AutomationControl> recenable_control() const { return boost::shared_ptr<AutomationControl>(); }
/* "well-known" controls for panning. Any or all of these may return
@@ -131,6 +138,9 @@ class Stripable : public SessionObject {
* the route.
*/
virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const = 0;
+
+ virtual bool muted_by_others_soloing () const = 0;
+ virtual bool muted_by_others () const = 0;
};
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index b378021bce..bb955265c8 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -22,6 +22,7 @@
#include <boost/shared_ptr.hpp>
#include "ardour/interthread_info.h"
+#include "ardour/recordable.h"
#include "ardour/route.h"
#include "ardour/public_diskstream.h"
@@ -34,13 +35,14 @@ class Source;
class Region;
class Diskstream;
class IO;
+class MonitorControl;
/** A track is an route (bus) with a recordable diskstream and
* related objects relevant to tracking, playback and editing.
*
* Specifically a track has regions and playlist objects.
*/
-class LIBARDOUR_API Track : public Route, public PublicDiskstream
+class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskstream
{
public:
Track (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal, DataType default_type = DataType::AUDIO);
@@ -56,23 +58,9 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
virtual bool can_use_mode (TrackMode /*m*/, bool& /*bounce_required*/) { return false; }
PBD::Signal0<void> TrackModeChanged;
- class LIBARDOUR_API MonitoringControllable : public RouteAutomationControl {
- public:
- MonitoringControllable (std::string name, boost::shared_ptr<Track>);
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- /* currently no automation, so no need for set_value_unchecked() */
- double get_value () const;
- private:
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- };
-
- void set_monitoring (MonitorChoice, PBD::Controllable::GroupControlDisposition group_override);
- MonitorChoice monitoring_choice() const { return _monitoring; }
- MonitorState monitoring_state () const;
- PBD::Signal0<void> MonitoringChanged;
-
- boost::shared_ptr<AutomationControl> monitoring_control() const { return _monitoring_control; }
+ boost::shared_ptr<MonitorControl> monitoring_control() const { return _monitoring_control; }
+ MonitorState monitoring_state () const;
MeterState metering_state () const;
virtual int no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
@@ -142,13 +130,12 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
virtual int set_state (const XMLNode&, int version);
static void zero_diskstream_id_in_xml (XMLNode&);
- boost::shared_ptr<AutomationControl> rec_enable_control() { return _rec_enable_control; }
+ boost::shared_ptr<AutomationControl> rec_enable_control() const { return _record_enable_control; }
+ boost::shared_ptr<AutomationControl> rec_safe_control() const { return _record_safe_control; }
- bool record_enabled() const;
- bool record_safe () const;
- void set_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
- void set_record_safe (bool yn, PBD::Controllable::GroupControlDisposition);
- void prep_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
+ int prep_record_enabled (bool);
+ bool can_be_record_enabled ();
+ bool can_be_record_safe ();
bool using_diskstream_id (PBD::ID) const;
@@ -204,8 +191,6 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
PBD::Signal0<void> FreezeChange;
/* Emitted when our diskstream is set to use a different playlist */
PBD::Signal0<void> PlaylistChanged;
- PBD::Signal0<void> RecordEnableChanged;
- PBD::Signal0<void> RecordSafeChanged;
PBD::Signal0<void> SpeedChanged;
PBD::Signal0<void> AlignmentStyleChanged;
@@ -216,8 +201,7 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
MeterPoint _saved_meter_point;
TrackMode _mode;
bool _needs_butler;
- MonitorChoice _monitoring;
- boost::shared_ptr<MonitoringControllable> _monitoring_control;
+ boost::shared_ptr<MonitorControl> _monitoring_control;
//private: (FIXME)
struct FreezeRecordProcessorInfo {
@@ -242,20 +226,6 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
FreezeState state;
};
- class RecEnableControl : public AutomationControl {
- public:
- RecEnableControl (boost::shared_ptr<Track> t);
-
- void set_value (double, PBD::Controllable::GroupControlDisposition);
- void set_value_unchecked (double);
- double get_value (void) const;
-
- boost::weak_ptr<Track> track;
-
- private:
- void _set_value (double, PBD::Controllable::GroupControlDisposition);
- };
-
virtual void set_state_part_two () = 0;
FreezeRecord _freeze_record;
@@ -264,17 +234,20 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
void maybe_declick (BufferSet&, framecnt_t, int);
- boost::shared_ptr<RecEnableControl> _rec_enable_control;
+ boost::shared_ptr<AutomationControl> _record_enable_control;
+ boost::shared_ptr<AutomationControl> _record_safe_control;
+
+ virtual void record_enable_changed (bool, PBD::Controllable::GroupControlDisposition);
+ virtual void record_safe_changed (bool, PBD::Controllable::GroupControlDisposition);
framecnt_t check_initial_delay (framecnt_t nframes, framepos_t&);
+ virtual void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
private:
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &) = 0;
void diskstream_playlist_changed ();
- void diskstream_record_enable_changed ();
- void diskstream_record_safe_changed ();
void diskstream_speed_changed ();
void diskstream_alignment_style_changed ();
void parameter_changed (std::string const & p);
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 626109557f..bd866141d5 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -53,6 +53,7 @@ namespace ARDOUR {
class Route;
class Region;
class VCA;
+ class AutomationControl;
typedef float Sample;
typedef float pan_t;
@@ -149,6 +150,7 @@ namespace ARDOUR {
FadeOutAutomation,
EnvelopeAutomation,
RecEnableAutomation,
+ RecSafeAutomation,
TrimAutomation,
PhaseAutomation,
MonitoringAutomation,
@@ -565,6 +567,7 @@ namespace ARDOUR {
typedef std::list<boost::shared_ptr<Route> > RouteList;
typedef std::list<boost::weak_ptr <Route> > WeakRouteList;
+ typedef std::list<boost::shared_ptr<AutomationControl> > ControlList;
typedef std::list<boost::shared_ptr<VCA> > VCAList;
diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h
index f3767d471a..1dc7c2baf4 100644
--- a/libs/ardour/ardour/utils.h
+++ b/libs/ardour/ardour/utils.h
@@ -28,19 +28,26 @@
#include <string>
#include <cmath>
+#include "boost/shared_ptr.hpp"
+
#if __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif /* __APPLE__ */
-#include "ardour/libardour_visibility.h"
#include "ardour/ardour.h"
#include "ardour/data_type.h"
#include "ardour/dB.h"
+#include "ardour/types.h"
+
+#include "ardour/libardour_visibility.h"
class XMLNode;
namespace ARDOUR {
+class Route;
+class Track;
+
LIBARDOUR_API std::string legalize_for_path (const std::string& str);
LIBARDOUR_API std::string legalize_for_universal_path (const std::string& str);
LIBARDOUR_API std::string legalize_for_uri (const std::string& str);
@@ -169,6 +176,29 @@ LIBARDOUR_API bool matching_unsuffixed_filename_exists_in (const std::string& di
LIBARDOUR_API uint32_t how_many_dsp_threads ();
+template<typename T> boost::shared_ptr<ControlList> route_list_to_control_list (boost::shared_ptr<RouteList> rl, boost::shared_ptr<T> (Route::*get_control)() const) {
+ boost::shared_ptr<ControlList> cl (new ControlList);
+ for (RouteList::const_iterator r = rl->begin(); r != rl->end(); ++r) {
+ boost::shared_ptr<AutomationControl> ac = ((*r).get()->*get_control)();
+ if (ac) {
+ cl->push_back (ac);
+ }
+ }
+ return cl;
+}
+
+template<typename T> boost::shared_ptr<ControlList> route_list_to_control_list (boost::shared_ptr<RouteList> rl, boost::shared_ptr<T> (Track::*get_control)() const) {
+ boost::shared_ptr<ControlList> cl (new ControlList);
+ for (RouteList::const_iterator r = rl->begin(); r != rl->end(); ++r) {
+ boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
+ boost::shared_ptr<AutomationControl> ac = (t.get()->*get_control)();
+ if (ac) {
+ cl->push_back (ac);
+ }
+ }
+ return cl;
+}
+
#if __APPLE__
LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef);
#endif // __APPLE__
@@ -176,4 +206,3 @@ LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef);
} //namespave
#endif /* __ardour_utils_h__ */
-
diff --git a/libs/ardour/ardour/vca.h b/libs/ardour/ardour/vca.h
index dc48ffa480..1c247c0e92 100644
--- a/libs/ardour/ardour/vca.h
+++ b/libs/ardour/ardour/vca.h
@@ -27,14 +27,19 @@
#include "pbd/statefuldestructible.h"
#include "ardour/automatable.h"
+#include "ardour/muteable.h"
+#include "ardour/soloable.h"
#include "ardour/stripable.h"
namespace ARDOUR {
-class GainControl;
class Route;
+class GainControl;
+class SoloControl;
+class MuteControl;
+class MonitorControl;
-class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::enable_shared_from_this<VCA> {
+class LIBARDOUR_API VCA : public Stripable, public Soloable, public Muteable, public Automatable, public boost::enable_shared_from_this<VCA> {
public:
VCA (Session& session, uint32_t num, const std::string& name);
~VCA();
@@ -47,7 +52,15 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
int set_state (XMLNode const&, int version);
bool soloed () const;
+ void push_solo_upstream (int32_t) {}
+ void push_solo_isolate_upstream (int32_t) {}
+ bool can_solo() const { return true; }
+ bool is_safe () const { return false; }
+
bool muted () const;
+ bool can_be_muted_by_others () const { return true; }
+ bool muted_by_others_soloing() const { return false; }
+ bool muted_by_others() const { return false; }
static std::string default_name_template ();
static int next_vca_number ();
@@ -58,16 +71,16 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
static void set_next_vca_number (uint32_t);
virtual boost::shared_ptr<GainControl> gain_control() const { return _gain_control; }
- virtual boost::shared_ptr<AutomationControl> solo_control() const { return _solo_control; }
- virtual boost::shared_ptr<AutomationControl> mute_control() const { return _mute_control; }
+ virtual boost::shared_ptr<SoloControl> solo_control() const { return _solo_control; }
+ virtual boost::shared_ptr<MuteControl> mute_control() const { return _mute_control; }
/* null Stripable API, because VCAs don't have any of this */
- virtual boost::shared_ptr<PeakMeter> peak_meter() { return boost::shared_ptr<PeakMeter>(); }
- virtual boost::shared_ptr<const PeakMeter> peak_meter() const { return boost::shared_ptr<PeakMeter>(); }
- virtual boost::shared_ptr<AutomationControl> phase_control() const { return boost::shared_ptr<AutomationControl>(); }
- virtual boost::shared_ptr<AutomationControl> trim_control() const { return boost::shared_ptr<AutomationControl>(); }
- virtual boost::shared_ptr<AutomationControl> monitoring_control() const { return boost::shared_ptr<AutomationControl>(); }
+ virtual boost::shared_ptr<PeakMeter> peak_meter() { return boost::shared_ptr<PeakMeter>(); }
+ virtual boost::shared_ptr<const PeakMeter> peak_meter() const { return boost::shared_ptr<PeakMeter>(); }
+ virtual boost::shared_ptr<PhaseControl> phase_control() const { return boost::shared_ptr<PhaseControl>(); }
+ virtual boost::shared_ptr<GainControl> trim_control() const { return boost::shared_ptr<GainControl>(); }
+ virtual boost::shared_ptr<MonitorControl> monitoring_control() const { return boost::shared_ptr<MonitorControl>(); }
virtual boost::shared_ptr<AutomationControl> recenable_control() const { return boost::shared_ptr<AutomationControl>(); }
virtual boost::shared_ptr<AutomationControl> pan_azimuth_control() const { return boost::shared_ptr<AutomationControl>(); }
virtual boost::shared_ptr<AutomationControl> pan_elevation_control() const { return boost::shared_ptr<AutomationControl>(); }
@@ -96,36 +109,12 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const { return boost::shared_ptr<AutomationControl>(); }
private:
- class VCASoloControllable : public AutomationControl {
- public:
- VCASoloControllable (std::string const & name, boost::shared_ptr<VCA> vca);
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- void set_value_unchecked (double);
- double get_value () const;
- private:
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- boost::weak_ptr<VCA> _vca;
- };
-
- class VCAMuteControllable : public AutomationControl {
- public:
- VCAMuteControllable (std::string const & name, boost::shared_ptr<VCA> vca);
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- void set_value_unchecked (double);
- double get_value () const;
- private:
- void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- boost::weak_ptr<VCA> _vca;
- };
-
- friend class VCASoloControllable;
- friend class VCAMuteControllable;
-
uint32_t _number;
boost::shared_ptr<GainControl> _gain_control;
- boost::shared_ptr<VCASoloControllable> _solo_control;
- boost::shared_ptr<VCAMuteControllable> _mute_control;
+ boost::shared_ptr<SoloControl> _solo_control;
+ boost::shared_ptr<MuteControl> _mute_control;
+
bool _solo_requested;
bool _mute_requested;
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 579b0064bc..2ed200d6f6 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -33,6 +33,7 @@
#include "ardour/buffer_set.h"
#include "ardour/delivery.h"
#include "ardour/meter.h"
+#include "ardour/monitor_control.h"
#include "ardour/playlist_factory.h"
#include "ardour/processor.h"
#include "ardour/profile.h"
@@ -349,7 +350,7 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
if (!_active) {
silence (nframes);
- if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+ if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
_meter->reset();
}
return 0;
@@ -391,7 +392,7 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
fill_buffers_with_input (bufs, _input, nframes);
- if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+ if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
_meter->run (bufs, start_frame, end_frame, nframes, true);
}
@@ -629,8 +630,9 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
/* reset stuff that has already been accounted for in the freeze process */
- set_gain (GAIN_COEFF_UNITY, Controllable::NoGroup);
- _amp->gain_control()->set_automation_state (Off);
+ gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
+ gain_control()->set_automation_state (Off);
+
/* XXX need to use _main_outs _panner->set_automation_state (Off); */
_freeze_record.state = Frozen;
diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc
index b00c615625..7efaa07f23 100644
--- a/libs/ardour/automation_control.cc
+++ b/libs/ardour/automation_control.cc
@@ -20,14 +20,17 @@
#include <math.h>
#include <iostream>
+
+#include "pbd/memento_command.h"
+#include "pbd/stacktrace.h"
+
+#include "ardour/audioengine.h"
#include "ardour/automation_control.h"
#include "ardour/automation_watch.h"
+#include "ardour/control_group.h"
#include "ardour/event_type_map.h"
#include "ardour/session.h"
-#include "pbd/memento_command.h"
-#include "pbd/stacktrace.h"
-
#include "i18n.h"
#ifdef COMPILER_MSVC
@@ -69,42 +72,38 @@ AutomationControl::writable() const
return true;
}
+/** Get the current effective `user' value based on automation state */
double
-AutomationControl::get_masters_value_locked () const
+AutomationControl::get_value() const
{
- gain_t v = 1.0;
-
- 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);
+ bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
+ return Control::get_double (from_list, _session.transport_frame());
}
-double
-AutomationControl::get_value_locked() const
+void
+AutomationControl::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
{
- /* read or write masters lock must be held */
-
- if (_masters.empty()) {
- return Control::get_double (false, _session.transport_frame());
+ if (!writable()) {
+ return;
}
- return get_masters_value_locked ();
-}
+ /* enforce strict double/boolean value mapping */
-/** Get the current effective `user' value based on automation state */
-double
-AutomationControl::get_value() const
-{
- bool from_list = _list && ((AutomationList*)_list.get())->automation_playback();
+ if (_desc.toggled) {
+ if (val != 0.0) {
+ val = 1.0;
+ }
+ }
+
+ if (check_rt (val, gcd)) {
+ /* change has been queued to take place in an RT context */
+ return;
+ }
- if (!from_list) {
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return get_value_locked ();
+ if (_group && _group->use_me (gcd)) {
+ _group->set_group_value (shared_from_this(), val);
} else {
- return Control::get_double (from_list, _session.transport_frame());
+ actually_set_value (val, gcd);
}
}
@@ -113,12 +112,15 @@ AutomationControl::get_value() const
* @param value `user' value
*/
void
-AutomationControl::set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
+AutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
{
- bool to_list = _list && ((AutomationList*)_list.get())->automation_write();
+ bool to_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_write();
Control::set_double (value, _session.transport_frame(), to_list);
+ AutomationType at = (AutomationType) _parameter.type();
+
+ std::cerr << "++++ Changed (" << enum_2_string (at) << ", " << enum_2_string (gcd) << ") = " << value << " @ " << this << std::endl;
Changed (true, gcd);
}
@@ -263,147 +265,25 @@ AutomationControl::interface_to_internal (double val) const
return val;
}
-
-void
-AutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
-{
- double current_value;
- double new_value;
- std::pair<Masters::iterator,bool> res;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- current_value = get_value_locked ();
-
- /* ratio will be recomputed below */
-
- res = _masters.insert (make_pair<PBD::ID,MasterRecord> (m->id(), MasterRecord (m, 1.0)));
-
- if (res.second) {
-
- 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
- itself.
- */
-
- m->DropReferences.connect_same_thread (masters_connections, boost::bind (&AutomationControl::master_going_away, this, m));
-
- /* Store the connection inside the MasterRecord, so that when we destroy it, the connection is destroyed
- and we no longer hear about changes to the AutomationControl.
-
- Note that we fix the "from_self" argument that will
- be given to our own Changed signal to "false",
- because the change came from the master.
- */
-
-
- 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);
- }
-
-}
-
-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();
- if (m) {
- remove_master (m);
- }
-}
-
-void
-AutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
-{
- double current_value;
- double new_value;
- Masters::size_type erased = 0;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- current_value = get_value_locked ();
- erased = _masters.erase (m->id());
- if (erased) {
- recompute_masters_ratios (current_value);
- }
- new_value = get_value_locked ();
- }
-
- if (erased) {
- MasterStatusChange (); /* EMIT SIGNAL */
- }
-
- if (new_value != current_value) {
- Changed (false, Controllable::NoGroup);
- }
-}
-
void
-AutomationControl::clear_masters ()
+AutomationControl::set_group (boost::shared_ptr<ControlGroup> cg)
{
- double current_value;
- double new_value;
- bool had_masters = false;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- current_value = get_value_locked ();
- if (!_masters.empty()) {
- had_masters = true;
- }
- _masters.clear ();
- new_value = get_value_locked ();
- }
-
- if (had_masters) {
- MasterStatusChange (); /* EMIT SIGNAL */
- }
-
- if (new_value != current_value) {
- Changed (false, Controllable::NoGroup);
+ if (_group) {
+ _group->remove_control (shared_from_this());
}
+ _group = cg;
}
bool
-AutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
+AutomationControl::check_rt (double val, Controllable::GroupControlDisposition gcd)
{
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return _masters.find (m->id()) != _masters.end();
-}
+ if ((flags() & Controllable::RealTime) && !AudioEngine::instance()->in_process_thread()) {
+ /* queue change in RT context */
+ std::cerr << "::set_value (" << val << ", " << enum_2_string (gcd) << ") called for " << enum_2_string ((AutomationType) _parameter.type()) << ", queueing in RT context\n";
+ _session.set_control (shared_from_this(), val, gcd);
+ return true;
+ }
-bool
-AutomationControl::slaved () const
-{
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return !_masters.empty();
+ return false;
}
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index b7e77952cb..85634640b9 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -140,21 +140,30 @@ setup_enum_writer ()
#define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
#define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
+ REGISTER_ENUM (NullAutomation);
REGISTER_ENUM (GainAutomation);
- REGISTER_ENUM (TrimAutomation);
REGISTER_ENUM (PanAzimuthAutomation);
REGISTER_ENUM (PanElevationAutomation);
REGISTER_ENUM (PanWidthAutomation);
+ REGISTER_ENUM (PanFrontBackAutomation);
+ REGISTER_ENUM (PanLFEAutomation);
REGISTER_ENUM (PluginAutomation);
REGISTER_ENUM (PluginPropertyAutomation);
REGISTER_ENUM (SoloAutomation);
+ REGISTER_ENUM (SoloIsolateAutomation);
+ REGISTER_ENUM (SoloSafeAutomation);
REGISTER_ENUM (MuteAutomation);
REGISTER_ENUM (MidiCCAutomation);
+ REGISTER_ENUM (MidiPgmChangeAutomation);
+ REGISTER_ENUM (MidiPitchBenderAutomation);
+ REGISTER_ENUM (MidiChannelPressureAutomation);
+ REGISTER_ENUM (MidiSystemExclusiveAutomation);
REGISTER_ENUM (FadeInAutomation);
REGISTER_ENUM (FadeOutAutomation);
REGISTER_ENUM (EnvelopeAutomation);
- REGISTER_ENUM (SoloIsolateAutomation);
- REGISTER_ENUM (SoloSafeAutomation);
+ REGISTER_ENUM (RecEnableAutomation);
+ REGISTER_ENUM (RecSafeAutomation);
+ REGISTER_ENUM (TrimAutomation);
REGISTER_ENUM (PhaseAutomation);
REGISTER_ENUM (MonitoringAutomation);
REGISTER_ENUM (EQGain);
diff --git a/libs/ardour/gain_control.cc b/libs/ardour/gain_control.cc
index 456fd9b248..3cb8230198 100644
--- a/libs/ardour/gain_control.cc
+++ b/libs/ardour/gain_control.cc
@@ -33,9 +33,9 @@ using namespace ARDOUR;
using namespace std;
GainControl::GainControl (Session& session, const Evoral::Parameter &param, boost::shared_ptr<AutomationList> al)
- : AutomationControl (session, param, ParameterDescriptor(param),
- al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
- param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
+ : SlavableAutomationControl (session, param, ParameterDescriptor(param),
+ al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
+ param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
alist()->reset_default (1.0);
@@ -44,22 +44,7 @@ GainControl::GainControl (Session& session, const Evoral::Parameter &param, boos
}
void
-GainControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
- if (writable()) {
- _set_value (val, group_override);
- }
-}
-
-void
-GainControl::set_value_unchecked (double val)
-{
- /* used only automation playback */
- _set_value (val, Controllable::NoGroup);
-}
-
-void
-GainControl::_set_value (double val, Controllable::GroupControlDisposition group_override)
+GainControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
{
val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
@@ -75,7 +60,7 @@ GainControl::_set_value (double val, Controllable::GroupControlDisposition group
be retrieved by AutomationControl::get_value ()
*/
- AutomationControl::set_value (val, group_override);
+ AutomationControl::actually_set_value (val, group_override);
_session.set_dirty ();
}
@@ -120,6 +105,23 @@ GainControl::get_user_string () const
}
void
+GainControl::inc_gain (gain_t factor)
+{
+ /* To be used ONLY when doing group-relative gain adjustment, from
+ * ControlGroup::set_group_values().
+ */
+
+ const float desired_gain = user_double();
+
+ if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
+ // really?! what's the idea here?
+ actually_set_value (0.000001f + (0.000001f * factor), Controllable::ForGroup);
+ } else {
+ actually_set_value (desired_gain + (desired_gain * factor), Controllable::ForGroup);
+ }
+}
+
+void
GainControl::recompute_masters_ratios (double val)
{
/* Master WRITE lock must be held */
diff --git a/libs/ardour/luabindings.cc b/libs/ardour/luabindings.cc
index 23dc0d26f0..28214b7e62 100644
--- a/libs/ardour/luabindings.cc
+++ b/libs/ardour/luabindings.cc
@@ -583,10 +583,10 @@ LuaBindings::common (lua_State* L)
.addCast<MidiTrack> ("to_midi_track")
.addFunction ("set_name", &Track::set_name)
.addFunction ("can_record", &Track::can_record)
- .addFunction ("record_enabled", &Track::record_enabled)
- .addFunction ("record_safe", &Track::record_safe)
- .addFunction ("set_record_enabled", &Track::set_record_enabled)
- .addFunction ("set_record_safe", &Track::set_record_safe)
+ //.addFunction ("record_enabled", &Track::record_enabled)
+ //.addFunction ("record_safe", &Track::record_safe)
+ //.addFunction ("set_record_enabled", &Track::set_record_enabled)
+ //.addFunction ("set_record_safe", &Track::set_record_safe)
.addFunction ("bounceable", &Track::bounceable)
.addFunction ("bounce", &Track::bounce)
.addFunction ("bounce_range", &Track::bounce_range)
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 9a38f9f05a..7c1b3a9399 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -44,6 +44,7 @@
#include "ardour/midi_port.h"
#include "ardour/midi_region.h"
#include "ardour/midi_track.h"
+#include "ardour/monitor_control.h"
#include "ardour/parameter_types.h"
#include "ardour/port.h"
#include "ardour/processor.h"
@@ -103,24 +104,24 @@ MidiTrack::create_diskstream ()
}
-void
-MidiTrack::set_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
+bool
+MidiTrack::can_be_record_safe ()
{
if (_step_editing) {
- return;
+ return false;
}
- Track::set_record_enabled (yn, group_override);
+ return Track::can_be_record_safe ();
}
-void
-MidiTrack::set_record_safe (bool yn, Controllable::GroupControlDisposition group_override)
+bool
+MidiTrack::can_be_record_enabled ()
{
- if (_step_editing) { /* REQUIRES REVIEW */
- return;
+ if (_step_editing) {
+ return false;
}
- Track::set_record_safe (yn, group_override);
+ return Track::can_be_record_enabled ();
}
void
@@ -372,7 +373,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
if (!_active) {
silence (nframes);
- if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+ if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
_meter->reset();
}
return 0;
@@ -412,7 +413,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
/* filter captured data before meter sees it */
_capture_filter.filter (bufs);
- if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+ if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
_meter->run (bufs, start_frame, end_frame, nframes, true);
}
@@ -726,22 +727,7 @@ MidiTrack::set_parameter_automation_state (Evoral::Parameter param, AutoState st
}
void
-MidiTrack::MidiControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
- if (writable()) {
- _set_value (val, group_override);
- }
-}
-
-void
-MidiTrack::MidiControl::set_value_unchecked (double val)
-{
- /* used only by automation playback */
- _set_value (val, Controllable::NoGroup);
-}
-
-void
-MidiTrack::MidiControl::_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
+MidiTrack::MidiControl::actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
{
const Evoral::Parameter &parameter = _list ? _list->parameter() : Control::parameter();
const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
@@ -798,7 +784,7 @@ MidiTrack::MidiControl::_set_value (double val, PBD::Controllable::GroupControlD
_route->write_immediate_event(size, ev);
}
- AutomationControl::set_value(val, group_override);
+ AutomationControl::actually_set_value(val, group_override);
}
void
@@ -958,35 +944,27 @@ MidiTrack::act_on_mute ()
}
void
-MidiTrack::set_monitoring (MonitorChoice mc, Controllable::GroupControlDisposition gcd)
+MidiTrack::monitoring_changed (bool self, Controllable::GroupControlDisposition gcd)
{
- if (use_group (gcd, &RouteGroup::is_monitoring)) {
- _route_group->apply (&Track::set_monitoring, mc, Controllable::NoGroup);
- return;
- }
-
- if (mc != _monitoring) {
+ Track::monitoring_changed (self, gcd);
+
+ /* monitoring state changed, so flush out any on notes at the
+ * port level.
+ */
- Track::set_monitoring (mc, gcd);
+ PortSet& ports (_output->ports());
- /* monitoring state changed, so flush out any on notes at the
- * port level.
- */
-
- PortSet& ports (_output->ports());
-
- for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p) {
- boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
- if (mp) {
- mp->require_resolve ();
- }
+ for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p) {
+ boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
+ if (mp) {
+ mp->require_resolve ();
}
+ }
- boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
+ boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
- if (md) {
- md->reset_tracker ();
- }
+ if (md) {
+ md->reset_tracker ();
}
}
diff --git a/libs/ardour/mute_master.cc b/libs/ardour/mute_master.cc
index dc40d1fd6b..6817374dc7 100644
--- a/libs/ardour/mute_master.cc
+++ b/libs/ardour/mute_master.cc
@@ -31,6 +31,8 @@
using namespace ARDOUR;
using namespace std;
+const string MuteMaster::xml_node_name (X_("MuteMaster"));
+
const MuteMaster::MutePoint MuteMaster::AllPoints = MuteMaster::MutePoint(
PreFader|PostFader|Listen|Main);
@@ -155,7 +157,7 @@ MuteMaster::set_state (const XMLNode& node, int /*version*/)
XMLNode&
MuteMaster::get_state()
{
- XMLNode* node = new XMLNode (X_("MuteMaster"));
+ XMLNode* node = new XMLNode (xml_node_name);
node->add_property ("mute-point", enum_2_string (_mute_point));
node->add_property ("muted", (_muted_by_self ? X_("yes") : X_("no")));
return *node;
diff --git a/libs/ardour/pan_controllable.cc b/libs/ardour/pan_controllable.cc
index a6a96787a2..624f397b77 100644
--- a/libs/ardour/pan_controllable.cc
+++ b/libs/ardour/pan_controllable.cc
@@ -35,27 +35,13 @@ PanControllable::lower () const
}
void
-PanControllable::set_value (double v, PBD::Controllable::GroupControlDisposition group_override)
-{
- if (writable()) {
- _set_value (v, group_override);
- }
-}
-void
-PanControllable::set_value_unchecked (double v)
-{
- /* used only automation playback */
- _set_value (v, Controllable::NoGroup);
-}
-
-void
-PanControllable::_set_value (double v, Controllable::GroupControlDisposition group_override)
+PanControllable::actually_set_value (double v, Controllable::GroupControlDisposition group_override)
{
boost::shared_ptr<Panner> p = owner->panner();
if (!p) {
/* no panner: just do it */
- AutomationControl::set_value (v, group_override);
+ AutomationControl::actually_set_value (v, group_override);
return;
}
@@ -76,7 +62,7 @@ PanControllable::_set_value (double v, Controllable::GroupControlDisposition gro
}
if (can_set) {
- AutomationControl::set_value (v, group_override);
+ AutomationControl::actually_set_value (v, group_override);
}
}
diff --git a/libs/ardour/parameter_descriptor.cc b/libs/ardour/parameter_descriptor.cc
index 9fb6b89a0c..e28dbecd35 100644
--- a/libs/ardour/parameter_descriptor.cc
+++ b/libs/ardour/parameter_descriptor.cc
@@ -75,6 +75,7 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
normal = 0.0f;
break;
case RecEnableAutomation:
+ case RecSafeAutomation:
lower = 0.0;
upper = 1.0;
toggled = true;
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index 451f801f1d..b0d4d2f9ac 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -2614,22 +2614,9 @@ PluginInsert::PluginControl::PluginControl (PluginInsert* p,
}
/** @param val `user' value */
-void
-PluginInsert::PluginControl::set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
-{
- if (writable()) {
- _set_value (user_val, group_override);
- }
-}
-void
-PluginInsert::PluginControl::set_value_unchecked (double user_val)
-{
- /* used only by automation playback */
- _set_value (user_val, Controllable::NoGroup);
-}
void
-PluginInsert::PluginControl::_set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
+PluginInsert::PluginControl::actually_set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
{
/* FIXME: probably should be taking out some lock here.. */
@@ -2642,13 +2629,13 @@ PluginInsert::PluginControl::_set_value (double user_val, PBD::Controllable::Gro
iasp->set_parameter (_list->parameter().id(), user_val);
}
- AutomationControl::set_value (user_val, group_override);
+ AutomationControl::actually_set_value (user_val, group_override);
}
void
PluginInsert::PluginControl::catch_up_with_external_value (double user_val)
{
- AutomationControl::set_value (user_val, Controllable::NoGroup);
+ AutomationControl::actually_set_value (user_val, Controllable::NoGroup);
}
XMLNode&
@@ -2700,15 +2687,7 @@ PluginInsert::PluginPropertyControl::PluginPropertyControl (PluginInsert*
}
void
-PluginInsert::PluginPropertyControl::set_value (double user_val, PBD::Controllable::GroupControlDisposition /* group_override*/)
-{
- if (writable()) {
- set_value_unchecked (user_val);
- }
-}
-
-void
-PluginInsert::PluginPropertyControl::set_value_unchecked (double user_val)
+PluginInsert::PluginPropertyControl::actually_set_value (double user_val, Controllable::GroupControlDisposition gcd)
{
/* Old numeric set_value(), coerce to appropriate datatype if possible.
This is lossy, but better than nothing until Ardour's automation system
@@ -2724,7 +2703,8 @@ PluginInsert::PluginPropertyControl::set_value_unchecked (double user_val)
}
_value = value;
- AutomationControl::set_value (user_val, Controllable::NoGroup);
+
+ AutomationControl::actually_set_value (user_val, gcd);
}
XMLNode&
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 8207176729..7a3d37d2a7 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -58,6 +58,7 @@
#include "ardour/panner.h"
#include "ardour/panner_shell.h"
#include "ardour/parameter_descriptor.h"
+#include "ardour/phase_control.h"
#include "ardour/plugin_insert.h"
#include "ardour/port.h"
#include "ardour/port_insert.h"
@@ -67,6 +68,8 @@
#include "ardour/route_group.h"
#include "ardour/send.h"
#include "ardour/session.h"
+#include "ardour/solo_control.h"
+#include "ardour/solo_isolate_control.h"
#include "ardour/unknown_processor.h"
#include "ardour/utils.h"
#include "ardour/vca.h"
@@ -84,6 +87,7 @@ PBD::Signal3<int,boost::shared_ptr<Route>, boost::shared_ptr<PluginInsert>, Rout
/** Base class for all routable/mixable objects (tracks and busses) */
Route::Route (Session& sess, string name, Flag flg, DataType default_type)
: Stripable (sess, name)
+ , Muteable (sess, name)
, Automatable (sess)
, GraphNode (sess._process_graph)
, _active (true)
@@ -99,18 +103,11 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
, _meter_point (MeterPostFader)
, _pending_meter_point (MeterPostFader)
, _meter_type (MeterPeak)
- , _self_solo (false)
- , _soloed_by_others_upstream (0)
- , _soloed_by_others_downstream (0)
- , _solo_isolated (false)
- , _solo_isolated_by_upstream (0)
, _denormal_protection (false)
, _recordable (true)
, _silent (false)
, _declickable (false)
- , _mute_master (new MuteMaster (sess, name))
, _have_internal_generator (false)
- , _solo_safe (false)
, _default_type (default_type)
, _order_key (0)
, _has_order_key (false)
@@ -141,21 +138,30 @@ Route::init ()
/* add standard controls */
- _solo_control.reset (new SoloControllable (X_("solo"), shared_from_this ()));
- _mute_control.reset (new MuteControllable (X_("mute"), shared_from_this ()));
- _phase_control.reset (new PhaseControllable (X_("phase"), shared_from_this ()));
+ _gain_control.reset (new GainControl (_session, GainAutomation));
+ add_control (_gain_control);
- _solo_isolate_control.reset (new SoloIsolateControllable (X_("solo-iso"), shared_from_this ()));
- _solo_safe_control.reset (new SoloSafeControllable (X_("solo-safe"), shared_from_this ()));
+ _trim_control.reset (new GainControl (_session, TrimAutomation));
+ add_control (_trim_control);
+ _solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
_solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
- _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
- _phase_control->set_flags (Controllable::Flag (_phase_control->flags() | Controllable::Toggle));
-
add_control (_solo_control);
+ _solo_control->Changed.connect_same_thread (*this, boost::bind (&Route::solo_control_changed, this, _1, _2));
+
+ _mute_control.reset (new MuteControl (_session, X_("mute"), *this));
+ _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
add_control (_mute_control);
+
+ _phase_control.reset (new PhaseControl (_session, X_("phase")));
add_control (_phase_control);
+ _solo_isolate_control.reset (new SoloIsolateControl (_session, X_("solo-iso"), *this, *this));
+ add_control (_solo_isolate_control);
+
+ _solo_safe_control.reset (new SoloSafeControl (_session, X_("solo-safe")));
+ add_control (_solo_safe_control);
+
/* panning */
if (!(_flags & Route::MonitorOut)) {
@@ -177,9 +183,6 @@ Route::init ()
* it should be the first processor to be added on every route.
*/
- _gain_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, GainAutomation, shared_from_this ()));
- add_control (_gain_control);
-
_amp.reset (new Amp (_session, X_("Fader"), _gain_control, true));
add_processor (_amp, PostFader);
@@ -196,9 +199,6 @@ Route::init ()
/* and input trim */
- _trim_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, TrimAutomation, shared_from_this ()));
- add_control (_trim_control);
-
_trim.reset (new Amp (_session, X_("Trim"), _trim_control, false));
_trim->set_display_to_user (false);
@@ -399,82 +399,10 @@ Route::ensure_track_or_route_name(string name, Session &session)
}
void
-Route::inc_gain (gain_t factor)
-{
- /* To be used ONLY when doing group-relative gain adjustment, from
- * ::set_gain()
- */
-
- float desired_gain = _gain_control->user_double();
-
- if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
- // really?! what's the idea here?
- _gain_control->route_set_value (0.000001f + (0.000001f * factor));
- } else {
- _gain_control->route_set_value (desired_gain + (desired_gain * factor));
- }
-}
-
-void
-Route::set_gain (gain_t val, Controllable::GroupControlDisposition gcd)
-{
- if (use_group (gcd, &RouteGroup::is_gain)) {
-
- if (_route_group->is_relative()) {
-
- gain_t usable_gain = _gain_control->get_value();
- if (usable_gain < 0.000001f) {
- usable_gain = 0.000001f;
- }
-
- gain_t delta = val;
- if (delta < 0.000001f) {
- delta = 0.000001f;
- }
-
- delta -= usable_gain;
-
- if (delta == 0.0f)
- return;
-
- gain_t factor = delta / usable_gain;
-
- if (factor > 0.0f) {
- factor = _route_group->get_max_factor(factor);
- if (factor == 0.0f) {
- _amp->gain_control()->Changed (true, gcd); /* EMIT SIGNAL */
- return;
- }
- } else {
- factor = _route_group->get_min_factor(factor);
- if (factor == 0.0f) {
- _amp->gain_control()->Changed (true, gcd); /* EMIT SIGNAL */
- return;
- }
- }
-
- _route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor));
-
- } else {
-
- _route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, Controllable::NoGroup));
- }
-
- return;
- }
-
- if (val == _gain_control->get_value()) {
- return;
- }
-
- _gain_control->route_set_value (val);
-}
-
-void
Route::set_trim (gain_t val, Controllable::GroupControlDisposition /* group override */)
{
// TODO route group, see set_gain()
- _trim_control->route_set_value (val);
+ // _trim_control->route_set_value (val);
}
void
@@ -551,7 +479,7 @@ Route::process_output_buffers (BufferSet& bufs,
DENORMAL CONTROL/PHASE INVERT
----------------------------------------------------------------------------------------- */
- if (_phase_invert.any ()) {
+ if (!_phase_control->none()) {
int chn = 0;
@@ -560,7 +488,7 @@ Route::process_output_buffers (BufferSet& bufs,
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
Sample* const sp = i->data();
- if (_phase_invert[chn]) {
+ if (_phase_control->inverted (chn)) {
for (pframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] = -sp[nx];
sp[nx] += 1.0e-27f;
@@ -577,7 +505,7 @@ Route::process_output_buffers (BufferSet& bufs,
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
Sample* const sp = i->data();
- if (_phase_invert[chn]) {
+ if (_phase_control->inverted (chn)) {
for (pframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] = -sp[nx];
}
@@ -808,283 +736,46 @@ Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t
}
void
-Route::set_listen (bool yn, Controllable::GroupControlDisposition group_override)
-{
- if (_solo_safe) {
- return;
- }
-
- if (use_group (group_override, &RouteGroup::is_solo)) {
- _route_group->foreach_route (boost::bind (&Route::set_listen, _1, yn, Controllable::ForGroup));
- return;
- }
-
- if (_monitor_send) {
- if (yn != _monitor_send->active()) {
- if (yn) {
- _monitor_send->activate ();
- _mute_master->set_soloed_by_self (true);
- } else {
- _monitor_send->deactivate ();
- _mute_master->set_soloed_by_self (false);
- }
- _mute_master->set_soloed_by_others (false);
-
- /* first argument won't matter because solo <=> listen right now */
- _solo_control->Changed (false, group_override); /* EMIT SIGNAL */
- }
- }
-}
-
-bool
-Route::listening_via_monitor () const
+Route::set_listen (bool yn)
{
- if (_monitor_send) {
- return _monitor_send->active ();
+ if (yn) {
+ _monitor_send->activate ();
} else {
- return false;
+ _monitor_send->deactivate ();
}
}
void
-Route::set_solo_safe (bool yn, Controllable::GroupControlDisposition gcd)
+Route::solo_control_changed (bool, Controllable::GroupControlDisposition)
{
- if (_solo_safe != yn) {
- _solo_safe = yn;
- _solo_safe_control->Changed (true, gcd); /* EMIT SIGNAL */
- }
-}
-
-bool
-Route::solo_safe() const
-{
- return _solo_safe;
-}
-
-void
-Route::clear_all_solo_state ()
-{
- // ideally this function will never do anything, it only exists to forestall Murphy
- bool emit_changed = false;
-
-#ifndef NDEBUG
- // these are really debug messages, but of possible interest.
- if (_self_solo) {
- PBD::info << string_compose (_("Cleared Explicit solo: %1\n"), name());
- }
- if (_soloed_by_others_upstream || _soloed_by_others_downstream) {
- PBD::info << string_compose (_("Cleared Implicit solo: %1 up:%2 down:%3\n"),
- name(), _soloed_by_others_upstream, _soloed_by_others_downstream);
- }
-#endif
-
- if (!_self_solo && (_soloed_by_others_upstream || _soloed_by_others_downstream)) {
- // if self-soled, set_solo() will do signal emission
- emit_changed = true;
- }
-
- _soloed_by_others_upstream = 0;
- _soloed_by_others_downstream = 0;
-
- {
- PBD::Unwinder<bool> uw (_solo_safe, false);
- set_solo (false, Controllable::NoGroup);
- }
-
- if (emit_changed) {
- set_mute_master_solo ();
- _solo_control->Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
- }
-}
-
-void
-Route::set_solo (bool yn, Controllable::GroupControlDisposition group_override)
-{
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, grp ? %3 currently self-soloed ? %4\n",
- name(), yn, enum_2_string(group_override), self_soloed()));
-
- if (_solo_safe) {
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name()));
- return;
- }
-
- if (is_master() || is_monitor() || is_auditioner()) {
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change (master, monitor or auditioner)\n", name()));
- return;
- }
-
- if (use_group (group_override, &RouteGroup::is_solo)) {
- _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, Controllable::ForGroup));
- return;
- }
-
- if (self_soloed() != yn) {
- set_self_solo (yn);
- _solo_control->Changed (true, group_override); /* EMIT SIGNAL */
- }
-
- assert (Config->get_solo_control_is_listen_control() || !_monitor_send || !_monitor_send->active());
-}
-
-void
-Route::set_self_solo (bool yn)
-{
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn));
- _self_solo = yn;
- set_mute_master_solo ();
-}
-
-void
-Route::mod_solo_by_others_upstream (int32_t delta)
-{
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-upstream by %2, current up = %3 down = %4\n",
- name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
-
- uint32_t old_sbu = _soloed_by_others_upstream;
-
- if (delta < 0) {
- if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) {
- _soloed_by_others_upstream += delta;
- } else {
- _soloed_by_others_upstream = 0;
- }
- } else {
- _soloed_by_others_upstream += delta;
- }
-
- DEBUG_TRACE (DEBUG::Solo, string_compose (
- "%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n",
- name(), delta, _soloed_by_others_upstream, old_sbu,
- _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo()));
-
- /* 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.
+ /* nothing to do if we're not using AFL/PFL. But if we are, we need
+ to alter the active state of the monitor send.
*/
- if ((_self_solo || _soloed_by_others_downstream) &&
- ((old_sbu == 0 && _soloed_by_others_upstream > 0) ||
- (old_sbu > 0 && _soloed_by_others_upstream == 0))) {
-
- if (delta > 0 || !Config->get_exclusive_solo()) {
- DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
- for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
- if (i->sends_only) {
- continue;
- }
- boost::shared_ptr<Route> sr = i->r.lock();
- if (sr) {
- sr->mod_solo_by_others_downstream (-delta);
- }
- }
- }
- }
-
- set_mute_master_solo ();
- cerr << name() << " SC->Changed (false, UseGroup)\n";
- _solo_control->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
-}
-
-void
-Route::mod_solo_by_others_downstream (int32_t delta)
-{
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-downstream by %2, current up = %3 down = %4\n",
- name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
-
- if (delta < 0) {
- if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
- _soloed_by_others_downstream += delta;
- } else {
- _soloed_by_others_downstream = 0;
- }
- } else {
- _soloed_by_others_downstream += delta;
+ if (Config->get_solo_control_is_listen_control ()) {
+ set_listen (_solo_control->self_soloed());
}
-
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream));
-
- set_mute_master_solo ();
- _solo_control->Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
-}
-
-void
-Route::set_mute_master_solo ()
-{
- _mute_master->set_soloed_by_self (self_soloed());
- _mute_master->set_soloed_by_others (soloed_by_others_downstream() || soloed_by_others_upstream());
}
-void
-Route::mod_solo_isolated_by_upstream (bool yn)
+bool
+Route::listening_via_monitor () const
{
- bool old = solo_isolated ();
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod_solo_isolated_by_upstream cur: %2 d: %3\n",
- name(), _solo_isolated_by_upstream, yn ? "+1" : "-1"));
-
- if (!yn) {
- if (_solo_isolated_by_upstream >= 1) {
- _solo_isolated_by_upstream--;
- } else {
- _solo_isolated_by_upstream = 0;
- }
+ if (_monitor_send) {
+ return _monitor_send->active ();
} else {
- _solo_isolated_by_upstream++;
- }
-
- if (solo_isolated() != old) {
- /* solo isolated status changed */
- _mute_master->set_solo_ignore (solo_isolated());
- _solo_isolate_control->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
+ return false;
}
}
void
-Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_override)
+Route::push_solo_isolate_upstream (int32_t delta)
{
- if (is_master() || is_monitor() || is_auditioner()) {
- return;
- }
-
- if (use_group (group_override, &RouteGroup::is_solo)) {
- _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, Controllable::ForGroup));
- return;
- }
-
- bool changed = false;
-
- if (yn) {
- if (_solo_isolated == false) {
- _mute_master->set_solo_ignore (true);
- changed = true;
- }
- _solo_isolated = true;
- } else {
- if (_solo_isolated == true) {
- _solo_isolated = false;
- _mute_master->set_solo_ignore (false);
- changed = true;
- }
- }
-
-
- if (!changed) {
- return;
- }
-
/* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
boost::shared_ptr<RouteList> routes = _session.get_routes ();
for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+ if ((*i).get() == this || !(*i)->can_solo()) {
continue;
}
@@ -1092,87 +783,26 @@ Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_o
bool does_feed = feeds (*i, &sends_only);
if (does_feed && !sends_only) {
- (*i)->mod_solo_isolated_by_upstream (yn);
+ (*i)->solo_isolate_control()->mod_solo_isolated_by_upstream (delta);
}
}
-
- /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
-
- _solo_isolate_control->Changed (true, group_override); /* EMIT SIGNAL */
-}
-
-bool
-Route::solo_isolated () const
-{
- return (_solo_isolated == true) || (_solo_isolated_by_upstream > 0);
-}
-
-void
-Route::set_mute_points (MuteMaster::MutePoint mp)
-{
- _mute_master->set_mute_points (mp);
- mute_points_changed (); /* EMIT SIGNAL */
-
- if (_mute_master->muted_by_self()) {
- _mute_control->Changed (true, Controllable::UseGroup); /* EMIT SIGNAL */
- }
}
void
-Route::set_mute (bool yn, Controllable::GroupControlDisposition group_override)
+Route::push_solo_upstream (int delta)
{
- if (use_group (group_override, &RouteGroup::is_mute)) {
- _route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, Controllable::ForGroup));
- return;
- }
-
- if (muted() != yn) {
- _mute_master->set_muted_by_self (yn);
- /* allow any derived classes to respond to the mute change
- before anybody else knows about it.
- */
- act_on_mute ();
- /* tell everyone else */
- _mute_control->Changed (true, Controllable::NoGroup); /* EMIT SIGNAL */
+ DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
+ for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
+ if (i->sends_only) {
+ continue;
+ }
+ boost::shared_ptr<Route> sr (i->r.lock());
+ if (sr) {
+ sr->solo_control()->mod_solo_by_others_downstream (-delta);
+ }
}
}
-bool
-Route::muted () const
-{
- return _mute_master->muted_by_self();
-}
-
-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.
- // 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 _mute_master->muted_by_others() || (_session.soloing() && !soloed() && !solo_isolated());
-}
-
#if 0
static void
dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
@@ -2743,8 +2373,6 @@ Route::state(bool full_state)
node->add_property("active", _active?"yes":"no");
string p;
- boost::to_string (_phase_invert, p);
- node->add_property("phase-invert", p);
node->add_property("denormal-protection", _denormal_protection?"yes":"no");
node->add_property("meter-point", enum_2_string (_meter_point));
@@ -2756,18 +2384,9 @@ Route::state(bool full_state)
snprintf (buf, sizeof (buf), "%d", _order_key);
node->add_property ("order-key", buf);
- node->add_property ("self-solo", (_self_solo ? "yes" : "no"));
- snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream);
- node->add_property ("soloed-by-upstream", buf);
- snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream);
- node->add_property ("soloed-by-downstream", buf);
- node->add_property ("solo-isolated", solo_isolated() ? "yes" : "no");
- node->add_property ("solo-safe", _solo_safe ? "yes" : "no");
node->add_child_nocopy (_input->state (full_state));
node->add_child_nocopy (_output->state (full_state));
- node->add_child_nocopy (_solo_control->get_state ());
- node->add_child_nocopy (_mute_control->get_state ());
node->add_child_nocopy (_mute_master->get_state ());
if (full_state) {
@@ -2866,7 +2485,7 @@ Route::set_state (const XMLNode& node, int version)
_strict_io = string_is_affirmative (prop->value());
}
- if (is_master() || is_monitor() || is_auditioner()) {
+ if (!can_solo()) {
_mute_master->set_solo_ignore (true);
}
@@ -2933,31 +2552,10 @@ Route::set_state (const XMLNode& node, int version)
// this looks up the internal instrument in processors
reset_instrument_info();
- if ((prop = node.property ("self-solo")) != 0) {
- set_self_solo (string_is_affirmative (prop->value()));
- }
-
- if ((prop = node.property ("soloed-by-upstream")) != 0) {
- _soloed_by_others_upstream = 0; // needed for mod_.... () to work
- mod_solo_by_others_upstream (atoi (prop->value()));
- }
-
- if ((prop = node.property ("soloed-by-downstream")) != 0) {
- _soloed_by_others_downstream = 0; // needed for mod_.... () to work
- mod_solo_by_others_downstream (atoi (prop->value()));
- }
-
- if ((prop = node.property ("solo-isolated")) != 0) {
- set_solo_isolated (string_is_affirmative (prop->value()), Controllable::NoGroup);
- }
-
- if ((prop = node.property ("solo-safe")) != 0) {
- set_solo_safe (string_is_affirmative (prop->value()), Controllable::NoGroup);
- }
-
- if ((prop = node.property (X_("phase-invert"))) != 0) {
- set_phase_invert (boost::dynamic_bitset<> (prop->value ()));
- }
+ _solo_control->set_state (node, version);
+ _solo_safe_control->set_state (node, version);
+ _solo_isolate_control->set_state (node, version);
+ _mute_control->set_state (node, version);
if ((prop = node.property (X_("denormal-protection"))) != 0) {
set_denormal_protection (string_is_affirmative (prop->value()));
@@ -3046,7 +2644,7 @@ Route::set_state (const XMLNode& node, int version)
set_remote_control_id_internal (x);
}
- } else if (child->name() == X_("MuteMaster")) {
+ } else if (child->name() == MuteMaster::xml_node_name) {
_mute_master->set_state (*child, version);
} else if (child->name() == Automatable::xml_node_name) {
@@ -3089,26 +2687,10 @@ Route::set_state_2X (const XMLNode& node, int version)
_mute_master->set_solo_ignore (true);
}
- if ((prop = node.property (X_("phase-invert"))) != 0) {
- boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
- if (string_is_affirmative (prop->value ())) {
- p.set ();
- }
- set_phase_invert (p);
- }
-
if ((prop = node.property (X_("denormal-protection"))) != 0) {
set_denormal_protection (string_is_affirmative (prop->value()));
}
- if ((prop = node.property (X_("soloed"))) != 0) {
- bool yn = string_is_affirmative (prop->value());
-
- /* XXX force reset of solo status */
-
- set_solo (yn);
- }
-
if ((prop = node.property (X_("muted"))) != 0) {
bool first = true;
@@ -3870,11 +3452,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
contains ConfigurationChanged
*/
configure_processors (0);
- _phase_invert.resize (_input->n_ports().n_audio ());
+ _phase_control->resize (_input->n_ports().n_audio ());
io_changed (); /* EMIT SIGNAL */
}
- if (_soloed_by_others_upstream || _solo_isolated_by_upstream) {
+ if (_solo_control->soloed_by_others_upstream() || _solo_isolate_control->solo_isolated_by_upstream()) {
int sbou = 0;
int ibou = 0;
boost::shared_ptr<RouteList> routes = _session.get_routes ();
@@ -3889,38 +3471,36 @@ Route::input_change_handler (IOChange change, void * /*src*/)
if ((*i)->soloed()) {
++sbou;
}
- if ((*i)->solo_isolated()) {
+ if ((*i)->solo_isolate_control()->solo_isolated()) {
++ibou;
}
}
}
}
- int delta = sbou - _soloed_by_others_upstream;
- int idelta = ibou - _solo_isolated_by_upstream;
+ int delta = sbou - _solo_control->soloed_by_others_upstream();
+ int idelta = ibou - _solo_isolate_control->solo_isolated_by_upstream();
if (idelta < -1) {
PBD::warning << string_compose (
_("Invalid Solo-Isolate propagation: from:%1 new:%2 - old:%3 = delta:%4"),
- _name, ibou, _solo_isolated_by_upstream, idelta)
+ _name, ibou, _solo_isolate_control->solo_isolated_by_upstream(), idelta)
<< endmsg;
}
- if (_soloed_by_others_upstream) {
+ if (_solo_control->soloed_by_others_upstream()) {
// ignore new connections (they're not propagated)
if (delta <= 0) {
- mod_solo_by_others_upstream (delta);
+ _solo_control->mod_solo_by_others_upstream (delta);
}
}
- if (_solo_isolated_by_upstream) {
+ if (_solo_isolate_control->solo_isolated_by_upstream()) {
// solo-isolate currently only propagates downstream
if (idelta < 0) {
- mod_solo_isolated_by_upstream (false);
+ _solo_isolate_control->mod_solo_isolated_by_upstream (1);
}
- // TODO think: mod_solo_isolated_by_upstream() does not take delta arg,
- // but idelta can't be smaller than -1, can it?
//_solo_isolated_by_upstream = ibou;
}
@@ -3933,11 +3513,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
bool sends_only;
bool does_feed = feeds (*i, &sends_only);
if (delta <= 0 && does_feed && !sends_only) {
- (*i)->mod_solo_by_others_upstream (delta);
+ (*i)->solo_control()->mod_solo_by_others_upstream (delta);
}
if (idelta < 0 && does_feed && !sends_only) {
- (*i)->mod_solo_isolated_by_upstream (false);
+ (*i)->solo_isolate_control()->mod_solo_isolated_by_upstream (-1);
}
}
}
@@ -3963,7 +3543,7 @@ Route::output_change_handler (IOChange change, void * /*src*/)
io_changed (); /* EMIT SIGNAL */
}
- if (_soloed_by_others_downstream) {
+ if (_solo_control->soloed_by_others_downstream()) {
int sbod = 0;
/* checking all all downstream routes for
* explicit of implict solo is a rather drastic measure,
@@ -3986,20 +3566,20 @@ Route::output_change_handler (IOChange change, void * /*src*/)
}
}
}
- int delta = sbod - _soloed_by_others_downstream;
+ int delta = sbod - _solo_control->soloed_by_others_downstream();
if (delta <= 0) {
// do not allow new connections to change implicit solo (no propagation)
- mod_solo_by_others_downstream (delta);
+ _solo_control->mod_solo_by_others_downstream (delta);
// Session::route_solo_changed() does not propagate indirect solo-changes
// propagate upstream to tracks
for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+ if ((*i).get() == this || !can_solo()) {
continue;
}
bool sends_only;
bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
if (delta != 0 && does_feed && !sends_only) {
- (*i)->mod_solo_by_others_downstream (delta);
+ (*i)->solo_control()->mod_solo_by_others_downstream (delta);
}
}
@@ -4639,41 +4219,6 @@ Route::internal_send_for (boost::shared_ptr<const Route> target) const
return boost::shared_ptr<Send>();
}
-/** @param c Audio channel index.
- * @param yn true to invert phase, otherwise false.
- */
-void
-Route::set_phase_invert (uint32_t c, bool yn)
-{
- if (_phase_invert[c] != yn) {
- _phase_invert[c] = yn;
- _phase_control->Changed (true, Controllable::NoGroup); /* EMIT SIGNAL */
- _session.set_dirty ();
- }
-}
-
-void
-Route::set_phase_invert (boost::dynamic_bitset<> p)
-{
- if (_phase_invert != p) {
- _phase_invert = p;
- _phase_control->Changed (true, Controllable::NoGroup); /* EMIT SIGNAL */
- _session.set_dirty ();
- }
-}
-
-bool
-Route::phase_invert (uint32_t c) const
-{
- return _phase_invert[c];
-}
-
-boost::dynamic_bitset<>
-Route::phase_invert () const
-{
- return _phase_invert;
-}
-
void
Route::set_denormal_protection (bool yn)
{
@@ -4735,20 +4280,16 @@ Route::gain_control() const
return _gain_control;
}
-boost::shared_ptr<AutomationControl>
+boost::shared_ptr<GainControl>
Route::trim_control() const
{
return _trim_control;
}
-boost::shared_ptr<AutomationControl>
+boost::shared_ptr<PhaseControl>
Route::phase_control() const
{
- if (phase_invert().size()) {
- return _phase_control;
- } else {
- return boost::shared_ptr<PhaseControllable>();
- }
+ return _phase_control;
}
boost::shared_ptr<AutomationControl>
@@ -4841,12 +4382,6 @@ Route::has_io_processor_named (const string& name)
return false;
}
-MuteMaster::MutePoint
-Route::mute_points () const
-{
- return _mute_master->mute_points ();
-}
-
void
Route::set_processor_positions ()
{
@@ -5903,7 +5438,7 @@ Route::vca_assign (boost::shared_ptr<VCA> vca)
{
_gain_control->add_master (vca->gain_control());
_solo_control->add_master (vca->solo_control());
- _mute_control->add_master (vca->mute_control());
+ // _mute_control->add_master (vca->mute_control());
}
void
@@ -5913,10 +5448,48 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
/* unassign from all */
_gain_control->clear_masters ();
_solo_control->clear_masters ();
- _mute_control->clear_masters ();
+ //_mute_control->clear_masters ();
} else {
_gain_control->remove_master (vca->gain_control());
_solo_control->remove_master (vca->solo_control());
- _mute_control->remove_master (vca->mute_control());
+ //_mute_control->remove_master (vca->mute_control());
+ }
+}
+
+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;
+ }
+
+ return _mute_master->muted_by_others();
+}
+
+void
+Route::clear_all_solo_state ()
+{
+ double v = _solo_safe_control->get_value ();
+
+ _solo_control->clear_all_solo_state ();
+
+ if (v != 0.0) {
+ _solo_safe_control->set_value (v, Controllable::NoGroup);
}
}
diff --git a/libs/ardour/route_controls.cc b/libs/ardour/route_controls.cc
deleted file mode 100644
index ad5408d06d..0000000000
--- a/libs/ardour/route_controls.cc
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- Copyright (C) 2000 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.
-
-*/
-
-#ifdef WAF_BUILD
-#include "libardour-config.h"
-#endif
-
-#include "ardour/automation_control.h"
-#include "ardour/parameter_descriptor.h"
-#include "ardour/route.h"
-#include "ardour/session.h"
-
-#include "i18n.h"
-
-using namespace std;
-using namespace ARDOUR;
-using namespace PBD;
-
-void
-Route::set_control (AutomationType type, double val, PBD::Controllable::GroupControlDisposition group_override)
-{
- boost::shared_ptr<RouteList> rl;
-
- switch (type) {
- case GainAutomation:
- /* route must mediate group control */
- set_gain (val, group_override);
- break;
-
- case TrimAutomation:
- /* route must mediate group control */
- set_trim (val, group_override);
- break;
-
- case RecEnableAutomation:
- /* session must mediate group control */
- rl.reset (new RouteList);
- rl->push_back (shared_from_this());
- _session.set_record_enabled (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
- break;
-
- case SoloAutomation:
- /* session must mediate group control */
- rl.reset (new RouteList);
- rl->push_back (shared_from_this());
- if (Config->get_solo_control_is_listen_control()) {
- _session.set_listen (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
- } else {
- _session.set_solo (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
- }
- break;
-
- case MuteAutomation:
- /* session must mediate group control */
- rl.reset (new RouteList);
- rl->push_back (shared_from_this());
- _session.set_mute (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
- return;
- break;
-
- default:
- /* Not a route automation control */
- fatal << string_compose (_("programming error: %1%2\n"), X_("illegal type of route automation control passed to Route::set_control(): "), enum_2_string(type)) << endmsg;
- /*NOTREACHED*/
- return;
- }
-}
-
-
-Route::RouteAutomationControl::RouteAutomationControl (const std::string& name,
- AutomationType atype,
- boost::shared_ptr<AutomationList> alist,
- boost::shared_ptr<Route> r)
- : AutomationControl (r->session(), Evoral::Parameter (atype),
- ParameterDescriptor (Evoral::Parameter (atype)),
- alist, name)
- , _route (r)
-{
-}
-
-double
-Route::BooleanRouteAutomationControl::get_masters_value_locked () const
-{
- /* masters (read/write) lock must be held */
-
- /* if any master is enabled (val > 0.0) then we consider the master
- value to be 1.0
- */
-
- for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
- if (mr->second.master()->get_value()) {
- return 1.0;
- }
- }
-
- return 0.0;
-}
-
-
-
-Route::GainControllable::GainControllable (Session& s, AutomationType atype, boost::shared_ptr<Route> r)
- : GainControl (s, Evoral::Parameter(atype))
- , _route (r)
-{
-
-}
-
-Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
- : BooleanRouteAutomationControl (name, SoloAutomation, boost::shared_ptr<AutomationList>(), r)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-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()) {
- _set_value (val, group_override);
- }
-}
-
-void
-Route::SoloControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return;
- }
- r->set_control (SoloAutomation, val, group_override);
-}
-
-void
-Route::SoloControllable::set_value_unchecked (double val)
-{
- /* Used only by automation playback */
-
- _set_value (val, Controllable::NoGroup);
-}
-
-double
-Route::SoloControllable::get_value () const
-{
- if (slaved()) {
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return get_masters_value_locked () ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
- }
-
- if (_list && ((AutomationList*)_list.get())->automation_playback()) {
- // Playing back automation, get the value from the list
- return AutomationControl::get_value();
- }
-
- boost::shared_ptr<Route> r = _route.lock ();
-
- if (!r) {
- return 0;
- }
-
- if (Config->get_solo_control_is_listen_control()) {
- return r->listening_via_monitor() ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
- } else {
- return r->self_soloed() ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
- }
-}
-
-Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr<Route> r)
- : BooleanRouteAutomationControl (name, MuteAutomation, boost::shared_ptr<AutomationList>(), r)
- , _route (r)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Route::MuteControllable::set_superficial_value(bool muted)
-{
- /* Note we can not use AutomationControl::set_value here since it will emit
- Changed(), but the value will not be correct to the observer. */
-
- 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 ()) {
- * alist->start_write_pass (_session.audible_frame ());
- * }
- * here in the case of the user calling from a GUI or whatever.
- * Without the ability to distinguish between user and
- * automation-initiated changes, we lose the "touch mute"
- * behaviour we have in AutomationController::toggled ().
- */
- _list->set_in_write_pass (true, false, where);
- }
-
- Control::set_double (muted, where, to_list);
-}
-
-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()) {
- _set_value (val, group_override);
- }
-}
-
-void
-Route::MuteControllable::set_value_unchecked (double val)
-{
- /* used only automation playback */
- _set_value (val, Controllable::NoGroup);
-}
-
-void
-Route::MuteControllable::_set_value (double val, Controllable::GroupControlDisposition group_override)
-{
- boost::shared_ptr<Route> r = _route.lock ();
-
- if (!r) {
- return;
- }
-
- if (_list && ((AutomationList*)_list.get())->automation_playback()) {
- // Set superficial/automation value to drive controller (and possibly record)
- const bool bval = ((val >= 0.5) ? true : false);
- set_superficial_value (bval);
- // Playing back automation, set route mute directly
- r->set_mute (bval, Controllable::NoGroup);
- } else {
- r->set_control (MuteAutomation, val, group_override);
- }
-}
-
-double
-Route::MuteControllable::get_value () const
-{
- if (slaved()) {
- Glib::Threads::RWLock::ReaderLock lm (master_lock);
- return get_masters_value_locked () ? 1.0 : 0.0;
- }
-
- if (_list && ((AutomationList*)_list.get())->automation_playback()) {
- // Playing back automation, get the value from the list
- return AutomationControl::get_value();
- }
-
- // Not playing back automation, get the actual route mute value
- boost::shared_ptr<Route> r = _route.lock ();
- return (r && r->muted()) ? 1.0 : 0.0;
-}
-
-Route::PhaseControllable::PhaseControllable (std::string name, boost::shared_ptr<Route> r)
- : BooleanRouteAutomationControl (name, PhaseAutomation, boost::shared_ptr<AutomationList>(), r)
- , _current_phase (0)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(PhaseAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Route::PhaseControllable::set_value (double v, PBD::Controllable::GroupControlDisposition /* group_override */)
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (r->phase_invert().size()) {
- if (v == 0 || (v < 1 && v > 0.9) ) {
- r->set_phase_invert (_current_phase, false);
- } else {
- r->set_phase_invert (_current_phase, true);
- }
- }
-}
-
-double
-Route::PhaseControllable::get_value () const
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return 0.0;
- }
- return (double) r->phase_invert (_current_phase);
-}
-
-void
-Route::PhaseControllable::set_channel (uint32_t c)
-{
- _current_phase = c;
-}
-
-uint32_t
-Route::PhaseControllable::channel () const
-{
- return _current_phase;
-}
-
-Route::SoloIsolateControllable::SoloIsolateControllable (std::string name, boost::shared_ptr<Route> r)
- : BooleanRouteAutomationControl (name, SoloIsolateAutomation, boost::shared_ptr<AutomationList>(), r)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloIsolateAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-
-double
-Route::SoloIsolateControllable::get_value () const
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return 0.0; /* "false" */
- }
-
- return r->solo_isolated() ? 1.0 : 0.0;
-}
-
-void
-Route::SoloIsolateControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
- _set_value (val, gcd);
-}
-
-void
-Route::SoloIsolateControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition)
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return;
- }
-
- /* no group semantics yet */
- r->set_solo_isolated (val >= 0.5 ? true : false);
-}
-
-Route::SoloSafeControllable::SoloSafeControllable (std::string name, boost::shared_ptr<Route> r)
- : BooleanRouteAutomationControl (name, SoloSafeAutomation, boost::shared_ptr<AutomationList>(), r)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloSafeAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Route::SoloSafeControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
- _set_value (val, gcd);
-}
-
-void
-Route::SoloSafeControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition)
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return;
- }
-
- /* no group semantics yet */
- r->set_solo_safe (val >= 0.5 ? true : false);
-}
-
-double
-Route::SoloSafeControllable::get_value () const
-{
- boost::shared_ptr<Route> r = _route.lock ();
- if (!r) {
- return 0.0; /* "false" */
- }
-
- return r->solo_safe() ? 1.0 : 0.0;
-}
diff --git a/libs/ardour/route_graph.cc b/libs/ardour/route_graph.cc
index 910141a440..70b9b48d6f 100644
--- a/libs/ardour/route_graph.cc
+++ b/libs/ardour/route_graph.cc
@@ -20,6 +20,7 @@
#include "ardour/route.h"
#include "ardour/route_graph.h"
+#include "ardour/track.h"
#include "i18n.h"
@@ -195,21 +196,39 @@ struct RouteRecEnabledComparator
{
bool operator () (GraphVertex r1, GraphVertex r2) const
{
- if (r1->record_enabled()) {
- if (r2->record_enabled()) {
- /* both rec-enabled, just use signal order */
+ boost::shared_ptr<Track> t1 (boost::dynamic_pointer_cast<Track>(r1));
+ boost::shared_ptr<Track> t2 (boost::dynamic_pointer_cast<Track>(r2));
+
+ if (!t1) {
+ if (!t2) {
+ /* makes no difference which is first, use signal order */
return r1->order_key () < r2->order_key ();
} else {
- /* r1 rec-enabled, r2 not rec-enabled, run r2 early */
+ /* r1 is not a track, r2 is, run it early */
+ return false;
+ }
+ }
+
+ if (!t2) {
+ /* we already tested !t1, so just use signal order */
+ return r1->order_key () < r2->order_key ();
+ }
+
+ if (t1->rec_enable_control()->get_value()) {
+ if (t2->rec_enable_control()->get_value()) {
+ /* both rec-enabled, just use signal order */
+ return t1->order_key () < t2->order_key ();
+ } else {
+ /* t1 rec-enabled, t2 not rec-enabled, run t2 early */
return false;
}
} else {
- if (r2->record_enabled()) {
- /* r2 rec-enabled, r1 not rec-enabled, run r1 early */
+ if (t2->rec_enable_control()->get_value()) {
+ /* t2 rec-enabled, t1 not rec-enabled, run t1 early */
return true;
} else {
/* neither rec-enabled, use signal order */
- return r1->order_key () < r2->order_key ();
+ return t1->order_key () < t2->order_key ();
}
}
}
diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc
index b482bb85d3..137e2c4734 100644
--- a/libs/ardour/route_group.cc
+++ b/libs/ardour/route_group.cc
@@ -28,6 +28,7 @@
#include "ardour/amp.h"
#include "ardour/audio_track.h"
+#include "ardour/monitor_control.h"
#include "ardour/route.h"
#include "ardour/route_group.h"
#include "ardour/session.h"
@@ -57,21 +58,21 @@ void
RouteGroup::make_property_quarks ()
{
Properties::relative.property_id = g_quark_from_static_string (X_("relative"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for relative = %1\n", Properties::relative.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for relative = %1\n", Properties::relative.property_id));
Properties::active.property_id = g_quark_from_static_string (X_("active"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for active = %1\n", Properties::active.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for active = %1\n", Properties::active.property_id));
Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
Properties::gain.property_id = g_quark_from_static_string (X_("gain"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for gain = %1\n", Properties::gain.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for gain = %1\n", Properties::gain.property_id));
Properties::mute.property_id = g_quark_from_static_string (X_("mute"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for mute = %1\n", Properties::mute.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for mute = %1\n", Properties::mute.property_id));
Properties::solo.property_id = g_quark_from_static_string (X_("solo"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for solo = %1\n", Properties::solo.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for solo = %1\n", Properties::solo.property_id));
Properties::recenable.property_id = g_quark_from_static_string (X_("recenable"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for recenable = %1\n", Properties::recenable.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for recenable = %1\n", Properties::recenable.property_id));
Properties::select.property_id = g_quark_from_static_string (X_("select"));
- DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for select = %1\n", Properties::select.property_id));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for select = %1\n", Properties::select.property_id));
Properties::route_active.property_id = g_quark_from_static_string (X_("route-active"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for route-active = %1\n", Properties::route_active.property_id));
Properties::color.property_id = g_quark_from_static_string (X_("color"));
@@ -96,6 +97,11 @@ RouteGroup::RouteGroup (Session& s, const string &n)
: SessionObject (s, n)
, routes (new RouteList)
, ROUTE_GROUP_DEFAULT_PROPERTIES
+ , _solo_group (new ControlGroup (SoloAutomation))
+ , _mute_group (new ControlGroup (MuteAutomation))
+ , _rec_enable_group (new ControlGroup (RecEnableAutomation))
+ , _gain_group (new ControlGroup (GainAutomation))
+ , _monitoring_group (new ControlGroup (MonitoringAutomation))
{
_xml_node_name = X_("RouteGroup");
@@ -114,6 +120,12 @@ RouteGroup::RouteGroup (Session& s, const string &n)
RouteGroup::~RouteGroup ()
{
+ _solo_group->clear ();
+ _mute_group->clear ();
+ _gain_group->clear ();
+ _rec_enable_group->clear ();
+ _monitoring_group->clear ();
+
for (RouteList::iterator i = routes->begin(); i != routes->end();) {
RouteList::iterator tmp = i;
++tmp;
@@ -140,6 +152,15 @@ RouteGroup::add (boost::shared_ptr<Route> r)
routes->push_back (r);
+ _solo_group->add_control (r->solo_control());
+ _mute_group->add_control (r->mute_control());
+ _gain_group->add_control (r->gain_control());
+ boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
+ if (trk) {
+ _rec_enable_group->add_control (trk->rec_enable_control());
+ _monitoring_group->add_control (trk->monitoring_control());
+ }
+
r->set_route_group (this);
r->DropReferences.connect_same_thread (*this, boost::bind (&RouteGroup::remove_when_going_away, this, boost::weak_ptr<Route> (r)));
@@ -165,6 +186,14 @@ RouteGroup::remove (boost::shared_ptr<Route> r)
if ((i = find (routes->begin(), routes->end(), r)) != routes->end()) {
r->set_route_group (0);
+ _solo_group->remove_control (r->solo_control());
+ _mute_group->remove_control (r->mute_control());
+ _gain_group->remove_control (r->gain_control());
+ boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
+ if (trk) {
+ _rec_enable_group->remove_control (trk->rec_enable_control());
+ _monitoring_group->remove_control (trk->monitoring_control());
+ }
routes->erase (i);
_session.set_dirty ();
RouteRemoved (this, boost::weak_ptr<Route> (r)); /* EMIT SIGNAL */
@@ -175,49 +204,6 @@ RouteGroup::remove (boost::shared_ptr<Route> r)
}
-gain_t
-RouteGroup::get_min_factor (gain_t factor)
-{
- for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- gain_t const g = (*i)->gain_control()->get_value();
-
- if ((g + g * factor) >= 0.0f) {
- continue;
- }
-
- if (g <= 0.0000003f) {
- return 0.0f;
- }
-
- factor = 0.0000003f / g - 1.0f;
- }
-
- return factor;
-}
-
-gain_t
-RouteGroup::get_max_factor (gain_t factor)
-{
- for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
- gain_t const g = (*i)->gain_control()->get_value();
-
- // if the current factor woulnd't raise this route above maximum
- if ((g + g * factor) <= 1.99526231f) {
- continue;
- }
-
- // if route gain is already at peak, return 0.0f factor
- if (g >= 1.99526231f) {
- return 0.0f;
- }
-
- // factor is calculated so that it would raise current route to max
- factor = 1.99526231f / g - 1.0f;
- }
-
- return factor;
-}
-
XMLNode&
RouteGroup::get_state ()
{
@@ -269,6 +255,8 @@ RouteGroup::set_state (const XMLNode& node, int version)
}
}
+ push_to_groups ();
+
return 0;
}
@@ -293,6 +281,8 @@ RouteGroup::set_state_2X (const XMLNode& node, int /*version*/)
_color = false;
}
+ push_to_groups ();
+
return 0;
}
@@ -303,6 +293,8 @@ RouteGroup::set_gain (bool yn)
return;
}
_gain = yn;
+ _gain_group->set_active (yn);
+
send_change (PropertyChange (Properties::gain));
}
@@ -313,6 +305,7 @@ RouteGroup::set_mute (bool yn)
return;
}
_mute = yn;
+ _mute_group->set_active (yn);
send_change (PropertyChange (Properties::mute));
}
@@ -323,6 +316,7 @@ RouteGroup::set_solo (bool yn)
return;
}
_solo = yn;
+ _solo_group->set_active (yn);
send_change (PropertyChange (Properties::solo));
}
@@ -333,6 +327,7 @@ RouteGroup::set_recenable (bool yn)
return;
}
_recenable = yn;
+ _rec_enable_group->set_active (yn);
send_change (PropertyChange (Properties::recenable));
}
@@ -384,6 +379,8 @@ RouteGroup::set_monitoring (bool yn)
}
_monitoring = yn;
+ _monitoring_group->set_active (yn);
+
send_change (PropertyChange (Properties::monitoring));
_session.set_dirty ();
@@ -531,3 +528,19 @@ RouteGroup::enabled_property (PBD::PropertyID prop)
return dynamic_cast<const PropertyTemplate<bool>* > (i->second)->val ();
}
+
+void
+RouteGroup::post_set (PBD::PropertyChange const &)
+{
+ push_to_groups ();
+}
+
+void
+RouteGroup::push_to_groups ()
+{
+ _gain_group->set_active (_gain);
+ _solo_group->set_active (_solo);
+ _mute_group->set_active (_mute);
+ _rec_enable_group->set_active (_recenable);
+ _monitoring_group->set_active (_monitoring);
+}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index ee70d2a40f..7658ff270d 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -98,6 +98,7 @@
#include "ardour/session_directory.h"
#include "ardour/session_playlists.h"
#include "ardour/smf_source.h"
+#include "ardour/solo_isolate_control.h"
#include "ardour/source_factory.h"
#include "ardour/speakers.h"
#include "ardour/tempo.h"
@@ -1506,7 +1507,7 @@ Session::set_track_monitor_input_status (bool yn)
boost::shared_ptr<RouteList> rl = routes.reader ();
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<AudioTrack> tr = boost::dynamic_pointer_cast<AudioTrack> (*i);
- if (tr && tr->record_enabled ()) {
+ if (tr && tr->rec_enable_control()->get_value()) {
//cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
tr->request_input_monitoring (yn);
}
@@ -1941,15 +1942,9 @@ void
Session::set_all_tracks_record_enabled (bool enable )
{
boost::shared_ptr<RouteList> rl = routes.reader();
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
- if (tr) {
- tr->set_record_enabled (enable, Controllable::NoGroup);
- }
- }
+ set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), enable, Controllable::NoGroup);
}
-
void
Session::disable_record (bool rt_context, bool force)
{
@@ -2981,7 +2976,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
// 0 for Stereo Out mode
// 0 Multi Out mode
if (Config->get_output_auto_connect() & AutoConnectMaster) {
- track->set_gain (dB_to_coefficient (0), Controllable::NoGroup);
+ track->gain_control()->set_value (dB_to_coefficient (0), Controllable::NoGroup);
}
}
@@ -3430,7 +3425,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
if (tr) {
tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
track_playlist_changed (boost::weak_ptr<Track> (tr));
- tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
+ tr->rec_enable_control()->Changed.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
if (mt) {
@@ -3580,7 +3575,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
continue;
}
- (*iter)->set_solo (false, Controllable::NoGroup);
+ (*iter)->solo_control()->set_value (0.0, Controllable::NoGroup);
rs->remove (*iter);
@@ -3721,7 +3716,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
continue;
}
- if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+ if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
/* route does not get solo propagated to it */
continue;
}
@@ -3734,7 +3729,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
*/
continue;
}
- (*i)->set_listen (false, Controllable::NoGroup);
+ (*i)->solo_control()->set_value (0.0, Controllable::NoGroup);
}
}
@@ -3759,7 +3754,7 @@ Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
bool send_changed = false;
- if (route->solo_isolated()) {
+ if (route->solo_isolate_control()->solo_isolated()) {
if (_solo_isolated_cnt == 0) {
send_changed = true;
}
@@ -3838,7 +3833,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
continue;
}
- if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+ if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
/* route does not get solo propagated to it */
continue;
}
@@ -3852,7 +3847,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
continue;
}
- (*i)->set_solo (false, group_override);
+ (*i)->solo_control()->set_value (0.0, group_override);
}
}
@@ -3871,7 +3866,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
continue;
}
- if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+ if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
/* route does not get solo propagated to it */
continue;
}
@@ -3893,7 +3888,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
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);
+ (*i)->solo_control()->mod_solo_by_others_downstream (delta);
} else {
DEBUG_TRACE (DEBUG::Solo, "\talready soloed by others upstream\n");
}
@@ -3922,7 +3917,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
if (!via_sends_only) {
//NB. Triggers Invert Push, which handles soloed by downstream
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
- (*i)->mod_solo_by_others_upstream (delta);
+ (*i)->solo_control()->mod_solo_by_others_upstream (delta);
} else {
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tfeed to %1 ignored, sends-only\n", (*i)->name()));
}
@@ -3969,7 +3964,7 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
}
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner() && (*i)->self_soloed()) {
+ if ((*i)->can_solo() && (*i)->self_soloed()) {
something_soloed = true;
}
@@ -3978,11 +3973,11 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
listeners++;
something_listening = true;
} else {
- (*i)->set_listen (false, Controllable::NoGroup);
+ (*i)->set_listen (false);
}
}
- if ((*i)->solo_isolated()) {
+ if ((*i)->solo_isolate_control()->solo_isolated()) {
isolated++;
}
}
@@ -6078,7 +6073,7 @@ Session::update_route_record_state ()
while (i != rl->end ()) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
- if (tr && tr->record_enabled ()) {
+ if (tr && tr->rec_enable_control()->get_value()) {
break;
}
@@ -6095,7 +6090,7 @@ Session::update_route_record_state ()
for (i = rl->begin(); i != rl->end (); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
- if (tr && !tr->record_enabled ()) {
+ if (tr && !tr->rec_enable_control()->get_value()) {
break;
}
}
@@ -6124,12 +6119,7 @@ void
Session::solo_control_mode_changed ()
{
/* cancel all solo or all listen when solo control mode changes */
-
- if (soloing()) {
- set_solo (get_routes(), false);
- } else if (listening()) {
- set_listen (get_routes(), false);
- }
+ clear_all_solo_state (get_routes());
}
/** Called when a property of one of our route groups changes */
diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc
index c2010fd592..390f1de32f 100644
--- a/libs/ardour/session_midi.cc
+++ b/libs/ardour/session_midi.cc
@@ -350,7 +350,7 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled)
if ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) {
if (trk == at->remote_control_id()) {
- at->set_record_enabled (enabled, Controllable::UseGroup);
+ at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
break;
}
}
diff --git a/libs/ardour/session_rtevents.cc b/libs/ardour/session_rtevents.cc
index 6b807fbf52..67249d48b9 100644
--- a/libs/ardour/session_rtevents.cc
+++ b/libs/ardour/session_rtevents.cc
@@ -21,8 +21,9 @@
#include "pbd/error.h"
#include "pbd/compose.h"
-#include "ardour/session.h"
+#include "ardour/monitor_control.h"
#include "ardour/route.h"
+#include "ardour/session.h"
#include "ardour/track.h"
#include "i18n.h"
@@ -33,26 +34,26 @@ using namespace ARDOUR;
using namespace Glib;
void
-Session::set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc,
- SessionEvent::RTeventCallback after,
- Controllable::GroupControlDisposition group_override)
+Session::set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
{
- queue_event (get_rt_event (rl, mc, after, group_override, &Session::rt_set_monitoring));
+ std::cerr << "Session::set_controls called on " << cl->size() << " controls, group = " << enum_2_string (gcd) << std::endl;
+ queue_event (get_rt_event (cl, val, gcd));
}
void
-Session::rt_set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc, Controllable::GroupControlDisposition group_override)
+Session::set_control (boost::shared_ptr<AutomationControl> ac, double val, Controllable::GroupControlDisposition gcd)
{
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- if (!(*i)->is_auditioner()) {
- boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*i);
- if (t) {
- t->set_monitoring (mc, group_override);
- }
- }
- }
+ boost::shared_ptr<ControlList> cl (new ControlList);
+ cl->push_back (ac);
+ set_controls (cl, val, gcd);
+}
- set_dirty();
+void
+Session::rt_set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
+{
+ for (ControlList::iterator c = cl->begin(); c != cl->end(); ++c) {
+ (*c)->set_value (val, gcd);
+ }
}
void
@@ -74,224 +75,6 @@ Session::rt_clear_all_solo_state (boost::shared_ptr<RouteList> rl, bool /* yn */
}
void
-Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after,
- Controllable::GroupControlDisposition group_override)
-{
- queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo));
-}
-
-void
-Session::rt_set_solo (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- if (!(*i)->is_auditioner()) {
- (*i)->set_solo (yn, group_override);
- }
- }
-
- set_dirty();
-
- /* XXX boost::shared_ptr<RouteList> goes out of scope here and is likley free()ed in RT context
- * because boost's shared_ptr does reference counting and free/delete in the dtor.
- * (this also applies to other rt_ methods here)
- */
-}
-
-void
-Session::set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, SessionEvent::RTeventCallback after,
- Controllable::GroupControlDisposition group_override)
-{
- queue_event (get_rt_event (rl, delta, upstream, after, group_override, &Session::rt_set_implicit_solo));
-}
-
-void
-Session::rt_set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, PBD::Controllable::GroupControlDisposition)
-{
- 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);
- }
- }
- }
-
- set_dirty();
-
- /* XXX boost::shared_ptr<RouteList> goes out of scope here and is likley free()ed in RT context
- * because boost's shared_ptr does reference counting and free/delete in the dtor.
- * (this also applies to other rt_ methods here)
- */
-}
-
-void
-Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, SessionEvent::RTeventCallback after)
-{
- /* its a bit silly to have to do this, but it keeps the API for this public method sane (we're
- only going to solo one route) and keeps our ability to use get_rt_event() for the internal
- private method.
- */
-
- boost::shared_ptr<RouteList> rl (new RouteList);
- rl->push_back (r);
-
- queue_event (get_rt_event (rl, yn, after, Controllable::NoGroup, &Session::rt_set_just_one_solo));
-}
-
-void
-Session::rt_set_just_one_solo (boost::shared_ptr<RouteList> just_one, bool yn, Controllable::GroupControlDisposition /*ignored*/)
-{
- boost::shared_ptr<RouteList> rl = routes.reader ();
- boost::shared_ptr<Route> r = just_one->front();
-
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- if (!(*i)->is_auditioner() && r != *i) {
- (*i)->set_solo (!yn, Controllable::NoGroup);
- }
- }
-
- r->set_solo (yn, Controllable::NoGroup);
-
- set_dirty();
-}
-
-void
-Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
- queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_listen));
-}
-
-void
-Session::rt_set_listen (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- if (!(*i)->is_auditioner()) {
- (*i)->set_listen (yn, group_override);
- }
- }
-
- set_dirty();
-}
-
-void
-Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
- /* Set superficial value of mute controls for automation. */
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- boost::shared_ptr<Route::MuteControllable> mc = boost::dynamic_pointer_cast<Route::MuteControllable> ((*i)->mute_control());
- mc->set_superficial_value(yn);
- }
-
- queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_mute));
-}
-
-void
-Session::rt_set_mute (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- if (!(*i)->is_monitor() && !(*i)->is_auditioner()) {
- (*i)->set_mute (yn, group_override);
- }
- }
-
- set_dirty();
-}
-
-void
-Session::set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
- queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo_isolated));
-}
-
-void
-Session::rt_set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition 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 (yn, group_override);
- }
- }
-
- set_dirty();
-}
-
-void
-Session::set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
- if (!writable()) {
- return;
- }
-
- /* do the non-RT part of rec-enabling first - the RT part will be done
- * on the next process cycle. This does mean that theoretically we are
- * doing things provisionally on the assumption that the rec-enable
- * change will work, but this had better be a solid assumption for
- * other reasons.
- */
-
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- if ((*i)->is_auditioner() || (*i)->record_safe ()) {
- continue;
- }
-
- boost::shared_ptr<Track> t;
-
- if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
- t->prep_record_enabled (yn, group_override);
- }
- }
-
- queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_enabled));
-}
-
-void
-Session::rt_set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
- if ((*i)->is_auditioner() || (*i)->record_safe ()) {
- continue;
- }
-
- boost::shared_ptr<Track> t;
-
- if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
- t->set_record_enabled (yn, group_override);
- }
- }
-
- set_dirty ();
-}
-
-
-void
-Session::set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
- set_record_enabled (rl, false, after, group_override);
- queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_safe));
-}
-
-void
-Session::rt_set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
- for (RouteList::iterator i = rl->begin (); i != rl->end (); ++i) {
- if ((*i)->is_auditioner ()) { // REQUIRES REVIEW Can audiotioner be in Record Safe mode?
- continue;
- }
-
- boost::shared_ptr<Track> t;
-
- if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
- t->set_record_safe (yn, group_override);
- }
- }
-
- set_dirty ();
-}
-
-void
Session::process_rtop (SessionEvent* ev)
{
ev->rt_slot ();
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 4e59da7137..47c7885b85 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -1265,7 +1265,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
- if (tr && tr->record_enabled ()) {
+ if (tr && tr->rec_enable_control()->get_value()) {
// tell it we've looped, so it can deal with the record state
tr->transport_looped (_transport_frame);
}
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index 8aebf09259..84a6d71349 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -23,9 +23,11 @@
#include "ardour/diskstream.h"
#include "ardour/io_processor.h"
#include "ardour/meter.h"
+#include "ardour/monitor_control.h"
#include "ardour/playlist.h"
#include "ardour/port.h"
#include "ardour/processor.h"
+#include "ardour/record_enable_control.h"
#include "ardour/route_group_specialized.h"
#include "ardour/session.h"
#include "ardour/session_playlists.h"
@@ -42,7 +44,6 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data
: Route (sess, name, flag, default_type)
, _saved_meter_point (_meter_point)
, _mode (mode)
- , _monitoring (MonitorAuto)
{
_freeze_record.state = NoFreeze;
_declickable = true;
@@ -62,17 +63,24 @@ Track::init ()
boost::shared_ptr<Route> rp (shared_from_this());
boost::shared_ptr<Track> rt = boost::dynamic_pointer_cast<Track> (rp);
- _rec_enable_control = boost::shared_ptr<RecEnableControl> (new RecEnableControl(rt));
- _rec_enable_control->set_flags (Controllable::Toggle);
- _monitoring_control.reset (new MonitoringControllable (X_("monitoring"), rt));
- /* don't add rec_enable_control to controls because we don't want it to
- * appear as an automatable parameter
- */
+ _record_enable_control.reset (new RecordEnableControl (_session, X_("recenable"), *this));
+ _record_enable_control->set_flags (Controllable::Toggle);
+
+ _monitoring_control.reset (new MonitorControl (_session, X_("monitoring"), *this));
+
+ _record_safe_control.reset (new AutomationControl (_session, RecSafeAutomation, ParameterDescriptor (RecSafeAutomation),
+ boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (RecSafeAutomation))),
+ X_("recsafe")));
+
track_number_changed.connect_same_thread (*this, boost::bind (&Track::resync_track_name, this));
_session.config.ParameterChanged.connect_same_thread (*this, boost::bind (&Track::parameter_changed, this, _1));
- return 0;
+ _monitoring_control->Changed.connect_same_thread (*this, boost::bind (&Track::monitoring_changed, this, _1, _2));
+ _record_safe_control->Changed.connect_same_thread (*this, boost::bind (&Track::record_safe_changed, this, _1, _2));
+ _record_enable_control->Changed.connect_same_thread (*this, boost::bind (&Track::record_enable_changed, this, _1, _2));
+
+ return 0;
}
void
@@ -97,9 +105,7 @@ XMLNode&
Track::state (bool full)
{
XMLNode& root (Route::state (full));
- root.add_property (X_("monitoring"), enum_2_string (_monitoring));
root.add_property (X_("saved-meter-point"), enum_2_string (_saved_meter_point));
- root.add_child_nocopy (_rec_enable_control->get_state());
root.add_child_nocopy (_diskstream->get_state ());
return root;
@@ -137,19 +143,13 @@ Track::set_state (const XMLNode& node, int version)
XMLProperty const * prop;
if (child->name() == Controllable::xml_node_name && (prop = child->property ("name")) != 0) {
if (prop->value() == X_("recenable")) {
- _rec_enable_control->set_state (*child, version);
+ _record_enable_control->set_state (*child, version);
}
}
}
XMLProperty const * prop;
- if ((prop = node.property (X_("monitoring"))) != 0) {
- _monitoring = MonitorChoice (string_2_enum (prop->value(), _monitoring));
- } else {
- _monitoring = MonitorAuto;
- }
-
if ((prop = node.property (X_("saved-meter-point"))) != 0) {
_saved_meter_point = MeterPoint (string_2_enum (prop->value(), _saved_meter_point));
} else {
@@ -178,62 +178,6 @@ Track::freeze_state() const
return _freeze_record.state;
}
-Track::RecEnableControl::RecEnableControl (boost::shared_ptr<Track> t)
- : AutomationControl (t->session(),
- RecEnableAutomation,
- ParameterDescriptor(Evoral::Parameter(RecEnableAutomation)),
- boost::shared_ptr<AutomationList>(),
- X_("recenable"))
- , track (t)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(RecEnableAutomation)));
- set_list (gl);
-}
-
-void
-Track::RecEnableControl::set_value (double val, Controllable::GroupControlDisposition group_override)
-{
- if (writable()) {
- _set_value (val, group_override);
- }
-}
-
-void
-Track::RecEnableControl::set_value_unchecked (double val)
-{
- if (writable()) {
- _set_value (val, Controllable::NoGroup);
- }
-}
-
-void
-Track::RecEnableControl::_set_value (double val, Controllable::GroupControlDisposition group_override)
-{
- boost::shared_ptr<Track> t = track.lock ();
- if (!t) {
- return;
- }
-
- t->set_record_enabled (val >= 0.5 ? true : false, group_override);
-}
-
-double
-Track::RecEnableControl::get_value () const
-{
- boost::shared_ptr<Track> t = track.lock ();
- if (!t) {
- return 0;
- }
-
- return (t->record_enabled() ? 1.0 : 0.0);
-}
-
-bool
-Track::record_enabled () const
-{
- return _diskstream && _diskstream->record_enabled ();
-}
-
bool
Track::can_record()
{
@@ -246,24 +190,15 @@ Track::can_record()
return will_record;
}
-void
-Track::prep_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
+int
+Track::prep_record_enabled (bool yn)
{
- if (yn && record_safe ()) {
- return;
- }
-
- if (!_session.writable()) {
- return;
- }
-
- if (_freeze_record.state == Frozen) {
- return;
+ if (yn && _record_safe_control->get_value()) {
+ return -1;
}
- if (use_group (group_override, &RouteGroup::is_recenable)) {
- _route_group->apply (&Track::prep_record_enabled, yn, Controllable::NoGroup);
- return;
+ if (!can_be_record_enabled()) {
+ return -1;
}
/* keep track of the meter point as it was before we rec-enabled */
@@ -288,31 +223,20 @@ Track::prep_record_enabled (bool yn, Controllable::GroupControlDisposition group
set_meter_point (_saved_meter_point);
}
}
+
+ return 0;
}
void
-Track::set_record_enabled (bool yn, Controllable::GroupControlDisposition gcd)
+Track::record_enable_changed (bool, Controllable::GroupControlDisposition)
{
- if (_diskstream->record_safe ()) {
- return;
- }
-
- if (!_session.writable()) {
- return;
- }
-
- if (_freeze_record.state == Frozen) {
- return;
- }
-
- if (use_group (gcd, &RouteGroup::is_recenable)) {
- _route_group->apply (&Track::set_record_enabled, yn, Controllable::NoGroup);
- return;
- }
-
- _diskstream->set_record_enabled (yn);
+ _diskstream->set_record_enabled (_record_enable_control->get_value());
+}
- _rec_enable_control->Changed (true, gcd);
+void
+Track::record_safe_changed (bool, Controllable::GroupControlDisposition)
+{
+ _diskstream->set_record_safe (_record_safe_control->get_value());
}
bool
@@ -336,12 +260,7 @@ Track::set_record_safe (bool yn, Controllable::GroupControlDisposition group_ove
return;
}
- if (use_group (group_override, &RouteGroup::is_recenable)) {
- _route_group->apply (&Track::set_record_safe, yn, Controllable::NoGroup);
- return;
- }
-
- _diskstream->set_record_safe (yn);
+ _rec_safe_control->set_value (yn, group_override);
}
void
@@ -371,7 +290,7 @@ Track::set_name (const string& str)
{
bool ret;
- if (record_enabled() && _session.actively_recording()) {
+ if (_record_enable_control->get_value() && _session.actively_recording()) {
/* this messes things up if done while recording */
return false;
}
@@ -452,7 +371,7 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
if (!_active) {
silence (nframes);
- if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+ if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
_meter->reset();
}
return 0;
@@ -611,8 +530,6 @@ Track::set_diskstream (boost::shared_ptr<Diskstream> ds)
ds->PlaylistChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_playlist_changed, this));
diskstream_playlist_changed ();
- ds->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_enable_changed, this));
- ds->RecordSafeChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_safe_changed, this));
ds->SpeedChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_speed_changed, this));
ds->AlignmentStyleChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_alignment_style_changed, this));
}
@@ -624,18 +541,6 @@ Track::diskstream_playlist_changed ()
}
void
-Track::diskstream_record_enable_changed ()
-{
- RecordEnableChanged (); /* EMIT SIGNAL */
-}
-
-void
-Track::diskstream_record_safe_changed ()
-{
- RecordSafeChanged (); /* EMIT SIGNAL */
-}
-
-void
Track::diskstream_speed_changed ()
{
SpeedChanged (); /* EMIT SIGNAL */
@@ -1014,12 +919,13 @@ MonitorState
Track::monitoring_state () const
{
/* Explicit requests */
+ MonitorChoice m (_monitoring_control->monitoring_choice());
- if (_monitoring & MonitorInput) {
+ if (m & MonitorInput) {
return MonitoringInput;
}
- if (_monitoring & MonitorDisk) {
+ if (m & MonitorDisk) {
return MonitoringDisk;
}
@@ -1086,7 +992,7 @@ Track::maybe_declick (BufferSet& bufs, framecnt_t nframes, int declick)
ditto if we are monitoring inputs.
*/
- if (_have_internal_generator || monitoring_choice() == MonitorInput) {
+ if (_have_internal_generator || (_monitoring_control->monitoring_choice() == MonitorInput)) {
return;
}
@@ -1136,22 +1042,10 @@ Track::check_initial_delay (framecnt_t nframes, framepos_t& transport_frame)
}
void
-Track::set_monitoring (MonitorChoice mc, Controllable::GroupControlDisposition gcd)
+Track::monitoring_changed (bool, Controllable::GroupControlDisposition)
{
- if (use_group (gcd, &RouteGroup::is_monitoring)) {
- _route_group->apply (&Track::set_monitoring, mc, Controllable::NoGroup);
- return;
- }
-
- if (mc != _monitoring) {
- _monitoring = mc;
-
- for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- (*i)->monitoring_changed ();
- }
-
- MonitoringChanged (); /* EMIT SIGNAL */
- _monitoring_control->Changed (true, gcd);
+ for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ (*i)->monitoring_changed ();
}
}
@@ -1161,64 +1055,10 @@ Track::metering_state () const
bool rv;
if (_session.transport_rolling ()) {
// audio_track.cc || midi_track.cc roll() runs meter IFF:
- rv = _meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled());
+ rv = _meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled());
} else {
// track no_roll() always metering if
rv = _meter_point == MeterInput;
}
return rv ? MeteringInput : MeteringRoute;
}
-
-Track::MonitoringControllable::MonitoringControllable (std::string name, boost::shared_ptr<Track> r)
- : RouteAutomationControl (name, MonitoringAutomation, boost::shared_ptr<AutomationList>(), r)
-{
- boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MonitoringAutomation)));
- gl->set_interpolation(Evoral::ControlList::Discrete);
- set_list (gl);
-}
-
-void
-Track::MonitoringControllable::set_value (double val, Controllable::GroupControlDisposition gcd)
-{
- _set_value (val, gcd);
-}
-
-void
-Track::MonitoringControllable::_set_value (double val, Controllable::GroupControlDisposition gcd)
-{
- boost::shared_ptr<Route> r = _route.lock();
- if (!r) {
- return;
- }
-
- boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (r);
- if (!t) {
- return;
- }
-
- int mc = (int) val;
-
- if (mc < MonitorAuto || mc > MonitorDisk) {
- return;
- }
-
- /* no group effect at present */
-
- t->set_monitoring ((MonitorChoice) mc, gcd);
-}
-
-double
-Track::MonitoringControllable::get_value () const
-{
- boost::shared_ptr<Route> r = _route.lock();
- if (!r) {
- return 0.0;
- }
-
- boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (r);
- if (!t) {
- return 0.0;
- }
-
- return t->monitoring_choice();
-}
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 08bb61065b..0ae1c569c8 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -754,3 +754,4 @@ ARDOUR::slider_position_to_gain_with_max (double g, double max_gain)
extern "C" {
void c_stacktrace() { stacktrace (cerr); }
}
+
diff --git a/libs/ardour/vca.cc b/libs/ardour/vca.cc
index d92fa67c03..39303fc8ca 100644
--- a/libs/ardour/vca.cc
+++ b/libs/ardour/vca.cc
@@ -63,6 +63,7 @@ VCA::get_next_vca_number ()
VCA::VCA (Session& s, uint32_t num, const string& name)
: Stripable (s, name)
+ , Muteable (s, name)
, Automatable (s)
, _number (num)
, _gain_control (new GainControl (s, Evoral::Parameter (GainAutomation), boost::shared_ptr<AutomationList> ()))
@@ -74,8 +75,8 @@ VCA::VCA (Session& s, uint32_t num, const string& name)
int
VCA::init ()
{
- _solo_control.reset (new VCASoloControllable (X_("solo"), shared_from_this()));
- _mute_control.reset (new VCAMuteControllable (X_("mute"), shared_from_this()));
+ _solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
+ _mute_control.reset (new MuteControl (_session, X_("mute"), *this));
add_control (_gain_control);
add_control (_solo_control);
@@ -159,98 +160,3 @@ VCA::muted () const
{
return _mute_requested;
}
-
-VCA::VCASoloControllable::VCASoloControllable (string const & name, boost::shared_ptr<VCA> vca)
- : AutomationControl (vca->session(), Evoral::Parameter (SoloAutomation), ParameterDescriptor (Evoral::Parameter (SoloAutomation)),
- boost::shared_ptr<AutomationList>(), name)
- , _vca (vca)
-{
-}
-
-void
-VCA::VCASoloControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
- if (writable()) {
- _set_value (val, gcd);
- }
-}
-
-void
-VCA::VCASoloControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
- boost::shared_ptr<VCA> vca = _vca.lock();
- if (!vca) {
- return;
- }
-
- vca->set_solo (val >= 0.5);
-
- AutomationControl::set_value (val, gcd);
-}
-
-void
-VCA::VCASoloControllable::set_value_unchecked (double val)
-{
- /* used only by automation playback */
- _set_value (val, Controllable::NoGroup);
-}
-
-double
-VCA::VCASoloControllable::get_value() const
-{
- boost::shared_ptr<VCA> vca = _vca.lock();
- if (!vca) {
- return 0.0;
- }
-
- return vca->soloed() ? 1.0 : 0.0;
-}
-
-/*----*/
-
-VCA::VCAMuteControllable::VCAMuteControllable (string const & name, boost::shared_ptr<VCA> vca)
- : AutomationControl (vca->session(), Evoral::Parameter (MuteAutomation), ParameterDescriptor (Evoral::Parameter (MuteAutomation)),
- boost::shared_ptr<AutomationList>(), name)
- , _vca (vca)
-{
-}
-
-void
-VCA::VCAMuteControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
- if (writable()) {
- _set_value (val, gcd);
- }
-}
-
-void
-VCA::VCAMuteControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
- boost::shared_ptr<VCA> vca = _vca.lock();
-
- if (!vca) {
- return;
- }
-
- vca->set_mute (val >= 0.5);
-
- AutomationControl::set_value (val, gcd);
-}
-
-void
-VCA::VCAMuteControllable::set_value_unchecked (double val)
-{
- /* used only by automation playback */
- _set_value (val, Controllable::NoGroup);
-}
-
-double
-VCA::VCAMuteControllable::get_value() const
-{
- boost::shared_ptr<VCA> vca = _vca.lock();
- if (!vca) {
- return 0.0;
- }
-
- return vca->muted() ? 1.0 : 0.0;
-}
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 625bac8742..17876f889b 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -57,6 +57,7 @@ libardour_sources = [
'chan_count.cc',
'chan_mapping.cc',
'config_text.cc',
+ 'control_group.cc',
'control_protocol_manager.cc',
'cycle_timer.cc',
'data_type.cc',
@@ -137,12 +138,15 @@ libardour_sources = [
'midi_stretch.cc',
'midi_track.cc',
'midi_ui.cc',
+ 'mididm.cc',
'midiport_manager.cc',
'mix.cc',
+ 'monitor_control.cc',
'monitor_processor.cc',
'mtc_slave.cc',
- 'mididm.cc',
'mtdm.cc',
+ 'muteable.cc',
+ 'mute_control.cc',
'mute_master.cc',
'note_fixer.cc',
'onset_detector.cc',
@@ -154,6 +158,7 @@ libardour_sources = [
'panner_shell.cc',
'parameter_descriptor.cc',
'pcm_utils.cc',
+ 'phase_control.cc',
'playlist.cc',
'playlist_factory.cc',
'playlist_source.cc',
@@ -170,13 +175,13 @@ libardour_sources = [
'quantize.cc',
'rc_configuration.cc',
'recent_sessions.cc',
+ 'record_enable_control.cc',
'region_factory.cc',
'resampled_source.cc',
'region.cc',
'return.cc',
'reverse.cc',
'route.cc',
- 'route_controls.cc',
'route_graph.cc',
'route_group.cc',
'route_group_member.cc',
@@ -206,10 +211,14 @@ libardour_sources = [
'session_transport.cc',
'sidechain.cc',
'slave.cc',
+ 'slavable_automation_control.cc',
'smf_source.cc',
'sndfile_helpers.cc',
'sndfileimportable.cc',
'sndfilesource.cc',
+ 'solo_control.cc',
+ 'solo_isolate_control.cc',
+ 'solo_safe_control.cc',
'soundcloud_upload.cc',
'source.cc',
'source_factory.cc',
diff --git a/libs/pbd/pbd/controllable.h b/libs/pbd/pbd/controllable.h
index 078671c91b..11ba979198 100644
--- a/libs/pbd/pbd/controllable.h
+++ b/libs/pbd/pbd/controllable.h
@@ -54,6 +54,7 @@ class LIBPBD_API Controllable : public PBD::StatefulDestructible {
enum Flag {
Toggle = 0x1,
GainLike = 0x2,
+ RealTime = 0x4
};
Controllable (const std::string& name, Flag f = Flag (0));
diff --git a/libs/surfaces/control_protocol/control_protocol.cc b/libs/surfaces/control_protocol/control_protocol.cc
index 5470232ad7..f413ad82d6 100644
--- a/libs/surfaces/control_protocol/control_protocol.cc
+++ b/libs/surfaces/control_protocol/control_protocol.cc
@@ -199,7 +199,7 @@ ControlProtocol::route_set_rec_enable (uint32_t table_index, bool yn)
boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
if (at) {
- at->set_record_enabled (yn, Controllable::NoGroup);
+ at->rec_enable_control()->set_value (1.0, Controllable::UseGroup);
}
}
@@ -215,7 +215,7 @@ ControlProtocol::route_get_rec_enable (uint32_t table_index)
boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
if (at) {
- return at->record_enabled ();
+ return at->rec_enable_control()->get_value();
}
return false;
@@ -248,7 +248,7 @@ ControlProtocol::route_set_gain (uint32_t table_index, float gain)
boost::shared_ptr<Route> r = route_table[table_index];
if (r != 0) {
- r->set_gain (gain, Controllable::UseGroup);
+ r->gain_control()->set_value (gain, Controllable::UseGroup);
}
}
@@ -298,7 +298,7 @@ ControlProtocol::route_get_muted (uint32_t table_index)
return false;
}
- return r->muted ();
+ return r->mute_control()->muted ();
}
void
@@ -311,7 +311,7 @@ ControlProtocol::route_set_muted (uint32_t table_index, bool yn)
boost::shared_ptr<Route> r = route_table[table_index];
if (r != 0) {
- r->set_mute (yn, Controllable::UseGroup);
+ r->mute_control()->set_value (yn ? 1.0 : 0.0, Controllable::UseGroup);
}
}
@@ -342,7 +342,7 @@ ControlProtocol::route_set_soloed (uint32_t table_index, bool yn)
boost::shared_ptr<Route> r = route_table[table_index];
if (r != 0) {
- r->set_solo (yn, Controllable::UseGroup);
+ r->solo_control()->set_value (yn ? 1.0 : 0.0, Controllable::UseGroup);
}
}
diff --git a/libs/surfaces/faderport/faderport.cc b/libs/surfaces/faderport/faderport.cc
index d08264a42d..1df2fc4865 100644
--- a/libs/surfaces/faderport/faderport.cc
+++ b/libs/surfaces/faderport/faderport.cc
@@ -507,7 +507,7 @@ FaderPort::fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
single route at a time, allow the fader to
modify the group, if appropriate.
*/
- _current_route->set_gain (val, Controllable::UseGroup);
+ _current_route->gain_control()->set_value (val, Controllable::UseGroup);
}
}
}
@@ -1147,7 +1147,7 @@ FaderPort::set_current_route (boost::shared_ptr<Route> r)
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
if (t) {
- t->RecordEnableChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_recenable, this), this);
+ t->rec_enable_control()->Changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_recenable, this), this);
}
boost::shared_ptr<AutomationControl> control = _current_route->gain_control ();
@@ -1227,7 +1227,7 @@ FaderPort::map_mute ()
if (_current_route->muted()) {
stop_blinking (Mute);
get_button (Mute).set_led_state (_output_port, true);
- } else if (_current_route->muted_by_others()) {
+ } else if (_current_route->mute_control()->muted_by_others()) {
start_blinking (Mute);
} else {
stop_blinking (Mute);
@@ -1252,7 +1252,7 @@ FaderPort::map_recenable ()
{
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
if (t) {
- get_button (Rec).set_led_state (_output_port, t->record_enabled());
+ get_button (Rec).set_led_state (_output_port, t->rec_enable_control()->get_value());
} else {
get_button (Rec).set_led_state (_output_port, false);
}
diff --git a/libs/surfaces/faderport/operations.cc b/libs/surfaces/faderport/operations.cc
index bb72794504..592b26da23 100644
--- a/libs/surfaces/faderport/operations.cc
+++ b/libs/surfaces/faderport/operations.cc
@@ -129,9 +129,9 @@ FaderPort::mute ()
return;
}
- boost::shared_ptr<RouteList> rl (new RouteList);
- rl->push_back (_current_route);
- session->set_mute (rl, !_current_route->muted());
+ boost::shared_ptr<ControlList> cl (new ControlList);
+ cl->push_back (_current_route->mute_control());
+ session->set_controls (cl, !_current_route->muted(), PBD::Controllable::UseGroup);
}
void
@@ -141,14 +141,15 @@ FaderPort::solo ()
return;
}
- boost::shared_ptr<RouteList> rl (new RouteList);
- rl->push_back (_current_route);
+ bool yn;
if (Config->get_solo_control_is_listen_control()) {
- session->set_listen (rl, !_current_route->listening_via_monitor());
+ yn = !_current_route->listening_via_monitor();
} else {
- session->set_solo (rl, !_current_route->soloed());
+ yn = !_current_route->soloed();
}
+
+ _current_route->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::UseGroup);
}
void
@@ -164,10 +165,7 @@ FaderPort::rec_enable ()
return;
}
- boost::shared_ptr<RouteList> rl (new RouteList);
- rl->push_back (_current_route);
-
- session->set_record_enabled (rl, !t->record_enabled());
+ t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
}
void
diff --git a/libs/surfaces/mackie/mcp_buttons.cc b/libs/surfaces/mackie/mcp_buttons.cc
index 1869d5e231..025d56d25a 100644
--- a/libs/surfaces/mackie/mcp_buttons.cc
+++ b/libs/surfaces/mackie/mcp_buttons.cc
@@ -383,7 +383,7 @@ MackieControlProtocol::save_press (Button &)
} else {
save_state ();
}
-
+
return none;
}
@@ -886,15 +886,9 @@ MackieControlProtocol::clearsolo_press (Mackie::Button&)
access_action ("Editor/set-session-from-edit-range");
return none;
}
-
- if (session) {
- if (session->soloing()) {
- session->set_solo (session->get_routes(), false);
- } else if (session->listening()) {
- session->set_listen (session->get_routes(), false);
- }
- session->clear_all_solo_state (session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
+ if (session) {
+ session->clear_all_solo_state (session->get_routes());
}
return none;
}
@@ -1063,7 +1057,7 @@ MackieControlProtocol::nudge_release (Mackie::Button&)
_modifier_state &= ~MODIFIER_NUDGE;
/* XXX these action names are stupid, because the action can affect
- * regions, markers or the playhead depending on selection state.
+ * regions, markers or the playhead depending on selection state.
*/
if (main_modifier_state() & MODIFIER_SHIFT) {
diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc
index caa3a3bc66..0062c3b4fb 100644
--- a/libs/surfaces/mackie/strip.cc
+++ b/libs/surfaces/mackie/strip.cc
@@ -37,14 +37,17 @@
#include "ardour/debug.h"
#include "ardour/midi_ui.h"
#include "ardour/meter.h"
+#include "ardour/monitor_control.h"
#include "ardour/plugin_insert.h"
#include "ardour/pannable.h"
#include "ardour/panner.h"
#include "ardour/panner_shell.h"
+#include "ardour/phase_control.h"
#include "ardour/rc_configuration.h"
#include "ardour/route.h"
#include "ardour/session.h"
#include "ardour/send.h"
+#include "ardour/solo_isolate_control.h"
#include "ardour/track.h"
#include "ardour/midi_track.h"
#include "ardour/user_bundle.h"
@@ -302,7 +305,10 @@ void
Strip::notify_record_enable_changed ()
{
if (_route && _recenable) {
- _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
+ boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (_route);
+ if (trk) {
+ _surface->write (_recenable->set_state (trk->rec_enable_control()->get_value() ? on : off));
+ }
}
}
diff --git a/libs/surfaces/osc/osc.cc b/libs/surfaces/osc/osc.cc
index b26c2d8597..d758e29f03 100644
--- a/libs/surfaces/osc/osc.cc
+++ b/libs/surfaces/osc/osc.cc
@@ -974,7 +974,7 @@ OSC::routes_list (lo_message msg)
|| boost::dynamic_pointer_cast<MidiTrack>(r)) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
- lo_message_add_int32 (reply, t->record_enabled());
+ lo_message_add_int32 (reply, (int32_t) t->rec_enable_control()->get_value());
}
//Automatically listen to routes listed
@@ -1054,7 +1054,7 @@ OSC::route_mute (int rid, int yn)
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
if (r) {
- r->set_mute (yn, PBD::Controllable::NoGroup);
+ r->mute_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
}
return 0;
@@ -1068,7 +1068,7 @@ OSC::route_solo (int rid, int yn)
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
if (r) {
- r->solo_control()->set_value(yn, PBD::Controllable::NoGroup);
+ r->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
}
return 0;
@@ -1082,7 +1082,10 @@ OSC::route_recenable (int rid, int yn)
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
if (r) {
- r->set_record_enabled (yn, PBD::Controllable::NoGroup);
+ boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
+ if (trk) {
+ trk->rec_enable_control()->set_value (yn, PBD::Controllable::UseGroup);
+ }
}
return 0;
@@ -1096,7 +1099,7 @@ OSC::route_set_gain_abs (int rid, float level)
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
if (r) {
- r->set_gain (level, PBD::Controllable::NoGroup);
+ r->gain_control()->set_value (level, PBD::Controllable::NoGroup);
}
return 0;