summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-05-16 07:30:28 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2016-05-31 15:30:42 -0400
commite0ff70cf86c01c42f98faf8b0eaf1a8ccf867946 (patch)
treedcb5ac7037e3b41d850930ea0a1759d79f8ca82a /libs/ardour
parentbae9474e9f04e324b1a2776b0fa9faefb5e6f0c2 (diff)
first vaguely working version using PresentationInfo
remote control ID and "order keys" have been removed.
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/audio_track.h2
-rw-r--r--libs/ardour/ardour/midi_track.h2
-rw-r--r--libs/ardour/ardour/mute_control.h1
-rw-r--r--libs/ardour/ardour/presentation_info.h303
-rw-r--r--libs/ardour/ardour/route.h50
-rw-r--r--libs/ardour/ardour/route_sorters.h44
-rw-r--r--libs/ardour/ardour/session.h60
-rw-r--r--libs/ardour/ardour/stripable.h64
-rw-r--r--libs/ardour/ardour/track.h2
-rw-r--r--libs/ardour/audio_track.cc4
-rw-r--r--libs/ardour/auditioner.cc2
-rw-r--r--libs/ardour/enums.cc22
-rw-r--r--libs/ardour/luabindings.cc2
-rw-r--r--libs/ardour/midi_track.cc4
-rw-r--r--libs/ardour/presentation_info.cc121
-rw-r--r--libs/ardour/route.cc247
-rw-r--r--libs/ardour/route_graph.cc16
-rw-r--r--libs/ardour/route_group.cc2
-rw-r--r--libs/ardour/session.cc299
-rw-r--r--libs/ardour/session_midi.cc39
-rw-r--r--libs/ardour/session_state.cc24
-rw-r--r--libs/ardour/stripable.cc160
-rw-r--r--libs/ardour/track.cc3
-rw-r--r--libs/ardour/vca.cc6
-rw-r--r--libs/ardour/wscript2
25 files changed, 892 insertions, 589 deletions
diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h
index 17e2223680..d80042a252 100644
--- a/libs/ardour/ardour/audio_track.h
+++ b/libs/ardour/ardour/audio_track.h
@@ -34,7 +34,7 @@ class AudioFileSource;
class LIBARDOUR_API AudioTrack : public Track
{
public:
- AudioTrack (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal);
+ AudioTrack (Session&, std::string name, TrackMode m = Normal);
~AudioTrack ();
int set_mode (TrackMode m);
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 69f4981047..f756812e71 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -37,7 +37,7 @@ class Session;
class LIBARDOUR_API MidiTrack : public Track
{
public:
- MidiTrack (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal);
+ MidiTrack (Session&, std::string name, TrackMode m = Normal);
~MidiTrack ();
int init ();
diff --git a/libs/ardour/ardour/mute_control.h b/libs/ardour/ardour/mute_control.h
index 5332fd4fa7..36d5e112cc 100644
--- a/libs/ardour/ardour/mute_control.h
+++ b/libs/ardour/ardour/mute_control.h
@@ -25,6 +25,7 @@
#include "ardour/slavable_automation_control.h"
+#include "ardour/mute_master.h"
#include "ardour/libardour_visibility.h"
namespace ARDOUR {
diff --git a/libs/ardour/ardour/presentation_info.h b/libs/ardour/ardour/presentation_info.h
new file mode 100644
index 0000000000..f7446a7713
--- /dev/null
+++ b/libs/ardour/ardour/presentation_info.h
@@ -0,0 +1,303 @@
+/*
+ Copyright (C) 2016 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_presentation_info_h__
+#define __libardour_presentation_info_h__
+
+#include <iostream>
+#include <string>
+
+#include <stdint.h>
+
+#include "ardour/libardour_visibility.h"
+
+class XMLNode;
+
+namespace ARDOUR {
+
+class LIBARDOUR_API PresentationInfo
+{
+ public:
+
+ /* a PresentationInfo object exists to share information between
+ * different user interfaces (e.g. GUI and a Mackie Control surface)
+ * about:
+ *
+ * - ordering
+ * - selection status
+ * - visibility
+ * - object identity
+ *
+ * ORDERING
+ *
+ * One UI takes control of ordering by setting the "order" value for
+ * the PresentationInfo component of every Stripable object. In Ardour,
+ * this is done by the GUI (mostly because it is very hard for the user
+ * to re-order things on a control surface).
+ *
+ * Ordering is a complex beast, however. Different user interfaces may
+ * display things in different ways. For example, the GUI of Ardour
+ * allows the user to mix busses in between tracks. A control surface
+ * may do the same, but may also allow the user to press a button that
+ * makes it show only busses, or only MIDI tracks. At that point, the
+ * ordering on the surface differs from the ordering in the GUI.
+ *
+ * The ordering is given via a combination of an object type and a
+ * simple numeric position within that type. The object types at this
+ * time are:
+ *
+ * Route
+ * - object has inputs and outputs; processes data
+ * Output
+ * - Route used to connect to outside the application (MasterOut, MonitorOut)
+ * Special
+ * - special type of Route (e.g. Auditioner)
+ * VCA
+ * - no data flows through; control only
+ *
+ * Objects with a numeric order of zero are considered unsorted. This
+ * applies (for now) to special objects such as the master out,
+ * auditioner and monitor out. The rationale here is that the GUI
+ * presents these objects in special ways, rather than as part of some
+ * (potentially) re-orderable container. The same is true for hardware
+ * surfaces, where the master fader (for instance) is typically
+ * separate and distinct from anything else.
+ *
+ * There are several pathways for the order being set:
+ *
+ * - object created during session loading from XML
+ * - numeric order will be set during ::set_state(), based on
+ * - type will be set during ctor call
+ *
+ * - object created in response to user request
+ * - numeric order will be set by Session, before adding
+ * to container.
+ * - type set during ctor call
+ *
+ *
+ * OBJECT IDENTITY
+ *
+ * Control surfaces/protocols often need to be able to get a handle on
+ * an object identified only abstractly, such as the "5th audio track"
+ * or "the master out". A PresentationInfo object uniquely identifies
+ * all objects in this way through the combination of its _order member
+ * and part of its _flags member. The _flags member identifies the type
+ * of object, as well as selection/hidden status. The type may never
+ * change after construction (not strictly the constructor itself, but
+ * a more generalized notion of construction, as in "ready to use").
+ *
+ * SELECTION
+ *
+ * When an object is selected, its _flags member will have the Selected
+ * bit set.
+ *
+ * VISIBILITY
+ *
+ * When an object is hidden, its _flags member will have the Hidden
+ * bit set.
+ *
+ *
+ */
+
+
+ enum Flag {
+ /* Type information */
+ AudioTrack = 0x1,
+ MidiTrack = 0x2,
+ AudioBus = 0x4,
+ MidiBus = 0x8,
+ VCA = 0x10,
+
+ /* These need to be at the high end */
+ MasterOut = 0x800,
+ MonitorOut = 0x1000,
+ Auditioner = 0x2000,
+
+ /* These are for sharing Stripable states between the GUI and other
+ * user interfaces/control surfaces
+ */
+ Selected = 0x4000,
+ Hidden = 0x8000,
+
+ /* single bit indicates that the group order is set */
+ GroupOrderSet = 0x100000000,
+
+ /* Masks */
+
+ GroupMask = (AudioTrack|MidiTrack|AudioBus|MidiBus|VCA),
+ SpecialMask = (MasterOut|MonitorOut|Auditioner),
+ StatusMask = (Selected|Hidden),
+ };
+
+ static const Flag Route;
+ static const Flag Track;
+ static const Flag Bus;
+
+ typedef uint32_t order_t;
+ typedef uint64_t global_order_t;
+
+ PresentationInfo (Flag f) : _order (0), _flags (Flag (f & ~GroupOrderSet)) { /* GroupOrderSet is not set */ }
+ PresentationInfo (order_t o, Flag f) : _order (o), _flags (Flag (f | GroupOrderSet)) { /* GroupOrderSet is set */ }
+
+ static const order_t max_order;
+
+ order_t group_order() const { return _order; }
+ global_order_t global_order () const {
+ if (_flags & Route) {
+
+ /* set all bits related to Route so that all Routes
+ sort together, with order() in the range of
+ 64424509440..68719476735
+
+ Consider the following arrangement:
+
+ Track 1
+ Bus 1
+ Track 2
+ ---------
+ VCA 1
+ ---------
+ Master
+ ---------
+ Monitor
+
+ these translate into the following
+
+ _order | _flags | order()
+ --------------------------------------
+ 1 | 0x1 AudioTrack | ((0x1|0x2|0x4|0x8)<<32)|1 = 64424509441
+ 2 | 0x2 AudioBus | ((0x1|0x2|0x4|0x8)<<32)|2 = 64424509442
+ 3 | 0x1 AudioTrack | ((0x1|0x2|0x4|0x8)<<32)|3 = 64424509443
+
+ 1 | 0x10 VCA | ((0x10)<<32)|1 = 68719476737
+
+ 0 | 0x800 Master | (0x800<<32) = 8796093022208
+
+ 0 | 0x1000 Monitor | (0x1000<<32) = 17592186044416
+
+ */
+
+ return (((global_order_t) (_flags | Route)) << sizeof(order_t)) | _order;
+ } else {
+ return (((global_order_t) _flags) << sizeof(order_t)) | _order;
+ }
+ }
+
+ PresentationInfo::Flag flags() const { return _flags; }
+
+ bool order_set() const { return _order != 0; }
+
+ /* these objects have no defined order */
+ bool special () const { return _flags & SpecialMask; }
+
+ /* detect group order set/not set */
+ bool unordered() const { return !(_flags & GroupOrderSet); }
+ bool ordered() const { return _flags & GroupOrderSet; }
+
+ void set_flag (PresentationInfo::Flag f) {
+ _flags = PresentationInfo::Flag (_flags | f);
+ }
+
+ void unset_flag (PresentationInfo::Flag f) {
+ _flags = PresentationInfo::Flag (_flags & ~f);
+ }
+
+ void set_flags (Flag f) {
+ _flags = f;
+ }
+
+ bool flag_match (Flag f) const {
+ /* no flags, match all */
+
+ if (f == Flag (0)) {
+ return true;
+ }
+
+ if (f & StatusMask) {
+ /* status bits set, must match them */
+ if ((_flags & StatusMask) != (f & StatusMask)) {
+ return false;
+ }
+ }
+
+ /* Generic flags in f, match the right stuff */
+
+ if (f == Bus && (_flags & Bus)) {
+ /* some kind of bus */
+ return true;
+ }
+ if (f == Track && (_flags & Track)) {
+ /* some kind of track */
+ return true;
+ }
+ if (f == Route && (_flags & Route)) {
+ /* any kind of route */
+ return true;
+ }
+
+ return f == _flags;
+ }
+
+ std::string to_string () const;
+
+ uint64_t to_integer () const {
+ return ((uint64_t) _flags << sizeof(order_t)) | _order;
+ }
+
+ bool operator< (PresentationInfo const& other) const {
+ return global_order() < other.global_order();
+ }
+
+ PresentationInfo& operator= (std::string const& str) {
+ parse (str);
+ return *this;
+ }
+
+ bool match (PresentationInfo const& other) const {
+ return (_order == other.group_order()) && flag_match (other.flags());
+ }
+
+ bool operator==(PresentationInfo const& other) {
+ return (_order == other.group_order()) && (_flags == other.flags());
+ }
+
+ bool operator!=(PresentationInfo const& other) {
+ return (_order != other.group_order()) || (_flags != other.flags());
+ }
+
+ static Flag get_flags (XMLNode const& node);
+
+ protected:
+ friend class Stripable;
+ void set_group_order (order_t order) { _order = order; _flags = Flag (_flags|GroupOrderSet); }
+
+ private:
+ order_t _order;
+ Flag _flags;
+
+ PresentationInfo (std::string const & str);
+ int parse (std::string const&);
+ int parse (order_t, Flag f);
+};
+
+}
+
+std::ostream& operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid);
+
+#endif /* __libardour_presentation_info_h__ */
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 2e2c1ccf72..7a6b504368 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -97,13 +97,7 @@ public:
typedef std::list<boost::shared_ptr<Processor> > ProcessorList;
- enum Flag {
- Auditioner = 0x1,
- MasterOut = 0x2,
- MonitorOut = 0x4
- };
-
- Route (Session&, std::string name, Flag flags = Flag(0), DataType default_type = DataType::AUDIO);
+ Route (Session&, std::string name, PresentationInfo::Flag flags = PresentationInfo::Flag(0), DataType default_type = DataType::AUDIO);
virtual ~Route();
virtual int init ();
@@ -127,14 +121,6 @@ public:
bool set_name (const std::string& str);
static void set_name_in_state (XMLNode &, const std::string &, bool rename_playlist = true);
- uint32_t order_key () const;
- bool has_order_key () const;
- void set_order_key (uint32_t);
-
- bool is_auditioner() const { return _flags & Auditioner; }
- bool is_master() const { return _flags & MasterOut; }
- bool is_monitor() const { return _flags & MonitorOut; }
-
MonitorState monitoring_state () const;
virtual MeterState metering_state () const;
@@ -569,28 +555,6 @@ public:
void protect_automation ();
- enum {
- /* These numbers are taken from MIDI Machine Control,
- which can only control up to 317 tracks without
- doing sysex segmentation.
- */
- MasterBusRemoteControlID = 318,
- MonitorBusRemoteControlID = 319,
- };
-
- void set_remote_control_id (uint32_t id, bool notify_class_listeners = true);
- uint32_t remote_control_id () const;
- void set_remote_control_id_explicit (uint32_t order_key);
-
- /* for things concerned about *this* route's RID */
-
- PBD::Signal0<void> RemoteControlIDChanged;
-
- /* for things concerned about *any* route's RID changes */
-
- static PBD::Signal0<void> RemoteControlIDChange;
- static PBD::Signal0<void> SyncOrderKeys;
-
bool has_external_redirects() const;
/* can only be executed by a route for which is_monitor() is true
@@ -663,7 +627,6 @@ public:
gint _pending_process_reorder; // atomic
gint _pending_signals; // atomic
- Flag _flags;
int _pending_declick;
MeterPoint _meter_point;
MeterPoint _pending_meter_point;
@@ -718,16 +681,12 @@ protected:
boost::shared_ptr<Processor> the_instrument_unlocked() const;
-private:
+ private:
+ int64_t _track_number;
+
int set_state_2X (const XMLNode&, int);
void set_processor_state_2X (XMLNodeList const &, int);
- uint32_t _order_key;
- bool _has_order_key;
- uint32_t _remote_control_id;
-
- int64_t _track_number;
-
void input_change_handler (IOChange, void *src);
void output_change_handler (IOChange, void *src);
void sidechain_change_handler (IOChange, void *src);
@@ -810,7 +769,6 @@ 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);
};
diff --git a/libs/ardour/ardour/route_sorters.h b/libs/ardour/ardour/route_sorters.h
deleted file mode 100644
index 022d5a24c3..0000000000
--- a/libs/ardour/ardour/route_sorters.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- Copyright (C) 2000-2014 Paul Davis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __libardour_route_sorters_h__
-#define __libardour_route_sorters_h__
-
-#include "ardour/route.h"
-
-namespace ARDOUR {
-
-struct SignalOrderRouteSorter {
- bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- if (a->is_master() || a->is_monitor()) {
- /* "a" is a special route (master, monitor, etc), and comes
- * last in the mixer ordering
- */
- return false;
- } else if (b->is_master() || b->is_monitor()) {
- /* everything comes before b */
- return true;
- }
- return a->order_key () < b->order_key ();
- }
-};
-
-} // namespace
-
-#endif /* __libardour_route_sorters_h__ */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 6f2c0f1fa9..f3a11a953c 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -64,11 +64,13 @@
#include "ardour/luascripting.h"
#include "ardour/location.h"
#include "ardour/monitor_processor.h"
+#include "ardour/presentation_info.h"
#include "ardour/rc_configuration.h"
#include "ardour/session_configuration.h"
#include "ardour/session_event.h"
#include "ardour/interpolation.h"
#include "ardour/plugin.h"
+#include "ardour/presentation_info.h"
#include "ardour/route.h"
#include "ardour/route_graph.h"
@@ -215,8 +217,6 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
PBD::Signal0<void> DirtyChanged;
- PBD::Signal1<void, bool> RouteAddedOrRemoved;
-
const SessionDirectory& session_directory () const { return *(_session_dir.get()); }
static PBD::Signal1<void,std::string> Dialog;
@@ -293,22 +293,20 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
bool operator() (boost::shared_ptr<Route>, boost::shared_ptr<Route> b);
};
- void set_order_hint (int32_t order_hint) {_order_hint = order_hint;};
- void notify_remote_id_change ();
- void sync_order_keys ();
+ void notify_presentation_info_change ();
template<class T> void foreach_route (T *obj, void (T::*func)(Route&), bool sort = true);
template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>), bool sort = true);
template<class T, class A> void foreach_route (T *obj, void (T::*func)(Route&, A), A arg, bool sort = true);
static char session_name_is_legal (const std::string&);
- bool io_name_is_legal (const std::string&);
- boost::shared_ptr<Route> route_by_name (std::string);
- boost::shared_ptr<Route> route_by_id (PBD::ID);
- boost::shared_ptr<Route> route_by_remote_id (uint32_t id);
- boost::shared_ptr<Stripable> stripable_by_remote_id (uint32_t id);
- boost::shared_ptr<Route> route_by_selected_count (uint32_t cnt);
- boost::shared_ptr<Track> track_by_diskstream_id (PBD::ID);
+ bool io_name_is_legal (const std::string&) const;
+ boost::shared_ptr<Route> route_by_name (std::string) const;
+ boost::shared_ptr<Route> route_by_id (PBD::ID) const;
+ boost::shared_ptr<Stripable> get_remote_nth_stripable (uint16_t n, PresentationInfo::Flag) const;
+ boost::shared_ptr<Route> get_remote_nth_route (uint16_t n) const;
+ boost::shared_ptr<Route> route_by_selected_count (uint32_t cnt) const;
+ boost::shared_ptr<Track> track_by_diskstream_id (PBD::ID) const;
void routes_using_input_from (const std::string& str, RouteList& rl);
bool route_name_unique (std::string) const;
@@ -595,29 +593,24 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
std::list<boost::shared_ptr<AudioTrack> > new_audio_track (
int input_channels,
int output_channels,
- TrackMode mode = Normal,
- RouteGroup* route_group = 0,
- uint32_t how_many = 1,
- std::string name_template = ""
- );
-
- RouteList new_audio_route (
- int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, std::string name_template = ""
+ RouteGroup* route_group,
+ uint32_t how_many,
+ std::string name_template,
+ PresentationInfo::order_t order,
+ TrackMode mode = Normal
);
std::list<boost::shared_ptr<MidiTrack> > new_midi_track (
const ChanCount& input, const ChanCount& output,
- boost::shared_ptr<PluginInfo> instrument = boost::shared_ptr<PluginInfo>(),
- TrackMode mode = Normal,
- RouteGroup* route_group = 0, uint32_t how_many = 1, std::string name_template = "",
- Plugin::PresetRecord* pset = 0
+ boost::shared_ptr<PluginInfo> instrument,
+ Plugin::PresetRecord* pset = 0,
+ RouteGroup* route_group, uint32_t how_many, std::string name_template,
+ PresentationInfo::order_t,
+ TrackMode mode = Normal
);
- RouteList new_midi_route (RouteGroup* route_group,
- uint32_t how_many,
- std::string name_template = "",
- boost::shared_ptr<PluginInfo> instrument = boost::shared_ptr<PluginInfo>(),
- Plugin::PresetRecord* pset = 0);
+ RouteList new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, std::string name_template, PresentationInfo::Flag, PresentationInfo::order_t);
+ RouteList new_midi_route (RouteGroup* route_group, uint32_t how_many, std::string name_template, boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord*, PresentationInfo::Flag, PresentationInfo::order_t);
void remove_routes (boost::shared_ptr<RouteList>);
void remove_route (boost::shared_ptr<Route>);
@@ -1658,8 +1651,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
SerializedRCUManager<RouteList> routes;
- void add_routes (RouteList&, bool input_auto_connect, bool output_auto_connect, bool save);
- void add_routes_inner (RouteList&, bool input_auto_connect, bool output_auto_connect);
+ void add_routes (RouteList&, bool input_auto_connect, bool output_auto_connect, bool save, PresentationInfo::order_t);
+ void add_routes_inner (RouteList&, bool input_auto_connect, bool output_auto_connect, PresentationInfo::order_t);
bool _adding_routes_in_progress;
bool _reconnecting_routes_in_progress;
bool _route_deletion_in_progress;
@@ -1976,8 +1969,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
*/
GraphEdges _current_route_graph;
- uint32_t next_control_id () const;
- int32_t _order_hint;
+ void ensure_presentation_info_gap (PresentationInfo::order_t, uint32_t gap_size);
bool ignore_route_processor_changes;
MidiClockTicker* midi_clock;
@@ -2005,6 +1997,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
std::string _template_state_dir;
VCAManager* _vca_manager;
+
+ boost::shared_ptr<Route> get_midi_nth_route_by_id (PresentationInfo::order_t n) const;
};
diff --git a/libs/ardour/ardour/stripable.h b/libs/ardour/ardour/stripable.h
index cee6075a51..1b82397074 100644
--- a/libs/ardour/ardour/stripable.h
+++ b/libs/ardour/ardour/stripable.h
@@ -26,7 +26,11 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
+#include "pbd/signals.h"
+
+#include "ardour/presentation_info.h"
#include "ardour/session_object.h"
+#include "ardour/libardour_visibility.h"
namespace ARDOUR {
@@ -46,18 +50,44 @@ class MonitorControl;
* and behaviour of the object.
*/
-class Stripable : public SessionObject {
+class LIBARDOUR_API Stripable : public SessionObject {
public:
- Stripable (Session& session, const std::string& name)
- : SessionObject (session, name) {}
+ Stripable (Session& session, std::string const & name, PresentationInfo const &);
+ virtual ~Stripable () {}
/* XXX
midi on/off
- selected status
- visible/hidden
*/
- virtual uint32_t remote_control_id () const = 0;
+ bool is_auditioner() const { return _presentation_info.flags() & PresentationInfo::Auditioner; }
+ bool is_master() const { return _presentation_info.flags() & PresentationInfo::MasterOut; }
+ bool is_monitor() const { return _presentation_info.flags() & PresentationInfo::MonitorOut; }
+
+ int set_state (XMLNode const&, int);
+
+ bool is_hidden() const { return _presentation_info.flags() & PresentationInfo::Hidden; }
+ bool is_selected() const { return _presentation_info.flags() & PresentationInfo::Selected; }
+
+ PresentationInfo const & presentation_info () const { return _presentation_info; }
+ PresentationInfo& presentation_info () { return _presentation_info; }
+
+ /* set just the order */
+
+ void set_presentation_group_order (PresentationInfo::order_t, bool notify_class_listeners = true);
+ void set_presentation_group_order_explicit (PresentationInfo::order_t);
+
+ /* for things concerned about *this* route's RID */
+
+ PBD::Signal0<void> PresentationInfoChanged;
+
+ /* for things concerned about *any* route's RID changes */
+
+ static PBD::Signal0<void> PresentationInfoChange;
+
+ /***************************************************************
+ * Pure interface begins here
+ ***************************************************************/
+
virtual boost::shared_ptr<PeakMeter> peak_meter() = 0;
virtual boost::shared_ptr<const PeakMeter> peak_meter() const = 0;
@@ -140,6 +170,28 @@ class Stripable : public SessionObject {
virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const = 0;
virtual bool muted_by_others_soloing () const = 0;
+
+ protected:
+ PresentationInfo _presentation_info;
+
+ /* set the entire info. This should only be used in cases where the
+ * derived could not supply the correct Flag and/or order information
+ * in its constructor.
+ */
+
+ void set_presentation_info (PresentationInfo id, bool notify_class_listeners = true);
+ void set_presentation_info_explicit (PresentationInfo);
+
+ void add_state (XMLNode&) const;
+
+ private:
+ void set_presentation_info_internal (PresentationInfo id, bool notify_class_listeners = true);
+};
+
+struct PresentationInfoSorter {
+ bool operator() (boost::shared_ptr<Stripable> a, boost::shared_ptr<Stripable> b) {
+ return a->presentation_info() < b->presentation_info();
+ }
};
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index bb955265c8..d57e0a2b5a 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -45,7 +45,7 @@ class MonitorControl;
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);
+ Track (Session&, std::string name, PresentationInfo::Flag f = PresentationInfo::Flag (0), TrackMode m = Normal, DataType default_type = DataType::AUDIO);
virtual ~Track ();
int init ();
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 2ed200d6f6..1b544bfb57 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -50,8 +50,8 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
- : Track (sess, name, flag, mode)
+AudioTrack::AudioTrack (Session& sess, string name, TrackMode mode)
+ : Track (sess, name, PresentationInfo::AudioTrack, mode)
{
}
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index 33f74faf80..0c7ba0bc1c 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -46,7 +46,7 @@ using namespace PBD;
#include "i18n.h"
Auditioner::Auditioner (Session& s)
- : Track (s, "auditioner", Route::Auditioner)
+ : Track (s, "auditioner", PresentationInfo::Auditioner)
, current_frame (0)
, _auditioning (0)
, length (0)
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index 85634640b9..817126847d 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -32,6 +32,7 @@
#include "ardour/location.h"
#include "ardour/midi_model.h"
#include "ardour/mute_master.h"
+#include "ardour/presentation_info.h"
#include "ardour/session.h"
#include "ardour/source.h"
#include "ardour/tempo.h"
@@ -99,7 +100,6 @@ setup_enum_writer ()
AutoConnectOption _AutoConnectOption;
TracksAutoNamingRule _TracksAutoNamingRule;
Session::StateOfTheState _Session_StateOfTheState;
- Route::Flag _Route_Flag;
Source::Flag _Source_Flag;
Diskstream::Flag _Diskstream_Flag;
Location::Flags _Location_Flags;
@@ -134,6 +134,7 @@ setup_enum_writer ()
Evoral::OverlapType _OverlapType;
BufferingPreset _BufferingPreset;
AutoReturnTarget _AutoReturnTarget;
+ PresentationInfo::Flag _PresentationInfo_Flag;
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
@@ -491,11 +492,6 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Session, pullup_Minus4Minus1);
REGISTER (_Session_PullupFormat);
- REGISTER_CLASS_ENUM (Route, Auditioner);
- REGISTER_CLASS_ENUM (Route, MasterOut);
- REGISTER_CLASS_ENUM (Route, MonitorOut);
- REGISTER_BITS (_Route_Flag);
-
REGISTER_CLASS_ENUM (Source, Writable);
REGISTER_CLASS_ENUM (Source, CanRename);
REGISTER_CLASS_ENUM (Source, Broadcast);
@@ -709,6 +705,20 @@ setup_enum_writer ()
REGISTER_ENUM (Loop);
REGISTER_ENUM (RegionSelectionStart);
REGISTER_BITS (_AutoReturnTarget);
+
+ REGISTER_CLASS_ENUM (PresentationInfo, AudioTrack);
+ REGISTER_CLASS_ENUM (PresentationInfo, MidiTrack);
+ REGISTER_CLASS_ENUM (PresentationInfo, AudioBus);
+ REGISTER_CLASS_ENUM (PresentationInfo, MidiBus);
+ REGISTER_CLASS_ENUM (PresentationInfo, MasterOut);
+ REGISTER_CLASS_ENUM (PresentationInfo, MonitorOut);
+ REGISTER_CLASS_ENUM (PresentationInfo, VCA);
+ REGISTER_CLASS_ENUM (PresentationInfo, Bus);
+ REGISTER_CLASS_ENUM (PresentationInfo, Track);
+ REGISTER_CLASS_ENUM (PresentationInfo, Route);
+ REGISTER_CLASS_ENUM (PresentationInfo, Selected);
+ REGISTER_CLASS_ENUM (PresentationInfo, Hidden);
+ REGISTER (_PresentationInfo_Flag);
}
} /* namespace ARDOUR */
diff --git a/libs/ardour/luabindings.cc b/libs/ardour/luabindings.cc
index 28214b7e62..765402efac 100644
--- a/libs/ardour/luabindings.cc
+++ b/libs/ardour/luabindings.cc
@@ -1033,7 +1033,7 @@ LuaBindings::common (lua_State* L)
.addFunction ("record_status", &Session::record_status)
.addFunction ("route_by_id", &Session::route_by_id)
.addFunction ("route_by_name", &Session::route_by_name)
- .addFunction ("route_by_remote_id", &Session::route_by_remote_id)
+ // STRIPABLE .addFunction ("route_by_remote_id", &Session::route_by_remote_id)
.addFunction ("track_by_diskstream_id", &Session::track_by_diskstream_id)
.addFunction ("source_by_id", &Session::source_by_id)
.addFunction ("controllable_by_id", &Session::controllable_by_id)
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index f078f1afc2..6402d9057c 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -67,8 +67,8 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
- : Track (sess, name, flag, mode, DataType::MIDI)
+MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode)
+ : Track (sess, name, PresentationInfo::MidiTrack, mode, DataType::MIDI)
, _immediate_events(1024) // FIXME: size?
, _step_edit_ring_buffer(64) // FIXME: size?
, _note_mode(Sustained)
diff --git a/libs/ardour/presentation_info.cc b/libs/ardour/presentation_info.cc
new file mode 100644
index 0000000000..6ec45a7d04
--- /dev/null
+++ b/libs/ardour/presentation_info.cc
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2016 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <sstream>
+#include <typeinfo>
+
+#include <cassert>
+
+#include "pbd/enumwriter.h"
+#include "pbd/error.h"
+#include "pbd/failed_constructor.h"
+#include "pbd/xml++.h"
+
+#include "ardour/presentation_info.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using std::string;
+
+const PresentationInfo::order_t PresentationInfo::max_order = UINT32_MAX;
+const PresentationInfo::Flag PresentationInfo::Bus = PresentationInfo::Flag (PresentationInfo::AudioBus|PresentationInfo::MidiBus);
+const PresentationInfo::Flag PresentationInfo::Track = PresentationInfo::Flag (PresentationInfo::AudioTrack|PresentationInfo::MidiTrack);
+const PresentationInfo::Flag PresentationInfo::Route = PresentationInfo::Flag (PresentationInfo::Bus|PresentationInfo::Track);
+
+PresentationInfo::PresentationInfo (std::string const & str)
+{
+ if (parse (str)) {
+ throw failed_constructor ();
+ }
+}
+
+int
+PresentationInfo::parse (string const& str)
+{
+ std::stringstream s (str);
+
+ /* new school, segmented string "NNN:TYPE" */
+ string f;
+ char c;
+ s >> _order;
+ /* skip colon */
+ s >> c;
+ /* grab flags */
+ s >> f;
+ _flags = Flag (string_2_enum (f, _flags)|GroupOrderSet);
+ std::cerr << "Parsed [" << str << "] as " << _order << " + " << enum_2_string (_flags) << std::endl;
+ return 0;
+}
+
+int
+PresentationInfo::parse (uint32_t n, Flag f)
+{
+ if (n < UINT16_MAX) {
+ assert (f != Flag (0));
+ _order = n;
+ _flags = Flag (f|GroupOrderSet);
+ } else {
+ _order = (n & 0xffff);
+ _flags = Flag ((n >> 16)|GroupOrderSet);
+ }
+
+ return 0;
+}
+
+std::string
+PresentationInfo::to_string() const
+{
+ std::stringstream ss;
+
+ /* Do not save or selected hidden status, or group-order set bit */
+
+ Flag f = Flag (_flags & ~(Hidden|Selected|GroupOrderSet));
+
+ ss << _order << ':' << enum_2_string (f);
+
+ return ss.str();
+}
+
+PresentationInfo::Flag
+PresentationInfo::get_flags (XMLNode const& node)
+{
+ const XMLProperty *prop;
+ XMLNodeList nlist = node.children ();
+ XMLNodeConstIterator niter;
+ XMLNode *child;
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter){
+ child = *niter;
+
+ if (child->name() == X_("PresentationInfo")) {
+ if ((prop = child->property (X_("value"))) != 0) {
+ PresentationInfo pi (prop->value());
+ return pi.flags ();
+ }
+ }
+ }
+ return Flag (0);
+}
+
+std::ostream&
+operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid)
+{
+ return o << rid.to_string ();
+}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index a449540c6f..fead0dc234 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -80,14 +80,12 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-PBD::Signal0<void> Route::SyncOrderKeys;
-PBD::Signal0<void> Route::RemoteControlIDChange;
PBD::Signal3<int,boost::shared_ptr<Route>, boost::shared_ptr<PluginInsert>, Route::PluginSetupOptions > Route::PluginSetup;
/** Base class for all routable/mixable objects (tracks and busses) */
-Route::Route (Session& sess, string name, Flag flg, DataType default_type)
+Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType default_type)
: GraphNode (sess._process_graph)
- , Stripable (sess, name)
+ , Stripable (sess, name, PresentationInfo (flag))
, Muteable (sess, name)
, Automatable (sess)
, _active (true)
@@ -98,7 +96,6 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
, _roll_delay (0)
, _pending_process_reorder (0)
, _pending_signals (0)
- , _flags (flg)
, _pending_declick (true)
, _meter_point (MeterPostFader)
, _pending_meter_point (MeterPostFader)
@@ -109,10 +106,6 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
, _declickable (false)
, _have_internal_generator (false)
, _default_type (default_type)
- , _order_key (0)
- , _has_order_key (false)
- , _remote_control_id (0)
- , _track_number (0)
, _in_configure_processors (false)
, _initial_io_setup (false)
, _in_sidechain_setup (false)
@@ -162,7 +155,7 @@ Route::init ()
/* panning */
- if (!(_flags & Route::MonitorOut)) {
+ if (!(_presentation_info.flags() & PresentationInfo::MonitorOut)) {
_pannable.reset (new Pannable (_session));
}
@@ -270,120 +263,6 @@ Route::~Route ()
_processors.clear ();
}
-void
-Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
-{
- if (Config->get_remote_model() != UserOrdered) {
- return;
- }
-
- set_remote_control_id_internal (id, notify_class_listeners);
-}
-
-void
-Route::set_remote_control_id_internal (uint32_t id, bool notify_class_listeners)
-{
- /* force IDs for master/monitor busses and prevent
- any other route from accidentally getting these IDs
- (i.e. legacy sessions)
- */
-
- if (is_master() && id != MasterBusRemoteControlID) {
- id = MasterBusRemoteControlID;
- }
-
- if (is_monitor() && id != MonitorBusRemoteControlID) {
- id = MonitorBusRemoteControlID;
- }
-
- if (id < 1) {
- return;
- }
-
- /* don't allow it to collide */
-
- if (!is_master () && !is_monitor() &&
- (id == MasterBusRemoteControlID || id == MonitorBusRemoteControlID)) {
- id += MonitorBusRemoteControlID;
- }
-
- if (id != remote_control_id()) {
- _remote_control_id = id;
- RemoteControlIDChanged ();
-
- if (notify_class_listeners) {
- RemoteControlIDChange ();
- }
- }
-}
-
-uint32_t
-Route::remote_control_id() const
-{
- if (is_master()) {
- return MasterBusRemoteControlID;
- }
-
- if (is_monitor()) {
- return MonitorBusRemoteControlID;
- }
-
- return _remote_control_id;
-}
-
-bool
-Route::has_order_key () const
-{
- return _has_order_key;
-}
-
-uint32_t
-Route::order_key () const
-{
- return _order_key;
-}
-
-void
-Route::set_remote_control_id_explicit (uint32_t rid)
-{
- if (is_master() || is_monitor() || is_auditioner()) {
- /* hard-coded remote IDs, or no remote ID */
- return;
- }
-
- if (_remote_control_id != rid) {
- DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: set edit-based RID to %2\n", name(), rid));
- _remote_control_id = rid;
- RemoteControlIDChanged (); /* EMIT SIGNAL (per-route) */
- }
-
- /* don't emit the class-level RID signal RemoteControlIDChange here,
- leave that to the entity that changed the order key, so that we
- don't get lots of emissions for no good reasons (e.g. when changing
- all route order keys).
-
- See Session::sync_remote_id_from_order_keys() for the (primary|only)
- spot where that is emitted.
- */
-}
-
-void
-Route::set_order_key (uint32_t n)
-{
- _has_order_key = true;
-
- if (_order_key == n) {
- return;
- }
-
- _order_key = n;
-
- DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key set to %2\n",
- name(), order_key ()));
-
- _session.set_dirty ();
-}
-
string
Route::ensure_track_or_route_name(string name, Session &session)
{
@@ -2357,9 +2236,7 @@ Route::state(bool full_state)
node->add_property("default-type", _default_type.to_string());
node->add_property ("strict-io", _strict_io);
- if (_flags) {
- node->add_property("flags", enum_2_string (_flags));
- }
+ Stripable::add_state (*node);
node->add_property("active", _active?"yes":"no");
string p;
@@ -2372,9 +2249,6 @@ Route::state(bool full_state)
node->add_property("route-group", _route_group->name());
}
- snprintf (buf, sizeof (buf), "%d", _order_key);
- node->add_property ("order-key", buf);
-
node->add_child_nocopy (_solo_control->get_state ());
node->add_child_nocopy (_solo_isolate_control->get_state ());
node->add_child_nocopy (_solo_safe_control->get_state ());
@@ -2390,11 +2264,6 @@ Route::state(bool full_state)
node->add_child_nocopy (Automatable::get_automation_xml_state ());
}
- XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
- snprintf (buf, sizeof (buf), "%d", _remote_control_id);
- remote_control_node->add_property (X_("id"), buf);
- node->add_child_nocopy (*remote_control_node);
-
if (_comment.length()) {
XMLNode *cmt = node->add_child ("Comment");
cmt->add_content (_comment);
@@ -2474,11 +2343,7 @@ Route::set_state (const XMLNode& node, int version)
set_id (node);
_initial_io_setup = true;
- if ((prop = node.property (X_("flags"))) != 0) {
- _flags = Flag (string_2_enum (prop->value(), _flags));
- } else {
- _flags = Flag (0);
- }
+ Stripable::set_state (node, version);
if ((prop = node.property (X_("strict-io"))) != 0) {
_strict_io = string_is_affirmative (prop->value());
@@ -2575,46 +2440,6 @@ Route::set_state (const XMLNode& node, int version)
set_active (yn, this);
}
- if ((prop = node.property (X_("order-key"))) != 0) { // New order key (no separate mixer/editor ordering)
- set_order_key (atoi(prop->value()));
- }
-
- if ((prop = node.property (X_("order-keys"))) != 0) { // Deprecated order keys
-
- int32_t n;
-
- string::size_type colon, equal;
- string remaining = prop->value();
-
- while (remaining.length()) {
-
- if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- string keyname = remaining.substr (0, equal);
-
- if ((keyname == "EditorSort") || (keyname == "editor")) {
- cerr << "Setting " << name() << " order key to " << n << " using saved Editor order." << endl;
- set_order_key (n);
- }
- }
- }
-
- colon = remaining.find_first_of (':');
-
- if (colon != string::npos) {
- remaining = remaining.substr (colon+1);
- } else {
- break;
- }
- }
- }
-
if ((prop = node.property (X_("processor-after-last-custom-meter"))) != 0) {
PBD::ID id (prop->value ());
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
@@ -2646,13 +2471,6 @@ Route::set_state (const XMLNode& node, int version)
_mute_control->set_state (*child, version);
}
- } else if (child->name() == X_("RemoteControl")) {
- if ((prop = child->property (X_("id"))) != 0) {
- int32_t x;
- sscanf (prop->value().c_str(), "%d", &x);
- set_remote_control_id_internal (x);
- }
-
} else if (child->name() == MuteMaster::xml_node_name) {
_mute_master->set_state (*child, version);
@@ -2684,13 +2502,7 @@ Route::set_state_2X (const XMLNode& node, int version)
return -1;
}
- if ((prop = node.property (X_("flags"))) != 0) {
- string f = prop->value ();
- boost::replace_all (f, "ControlOut", "MonitorOut");
- _flags = Flag (string_2_enum (f, _flags));
- } else {
- _flags = Flag (0);
- }
+ Stripable::set_state (node, version);
if (is_master() || is_monitor() || is_auditioner()) {
_mute_master->set_solo_ignore (true);
@@ -2764,46 +2576,6 @@ Route::set_state_2X (const XMLNode& node, int version)
_meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
}
- /* do not carry over edit/mix groups from 2.X because (a) its hard (b) they
- don't mean the same thing.
- */
-
- if ((prop = node.property (X_("order-keys"))) != 0) {
-
- int32_t n;
-
- string::size_type colon, equal;
- string remaining = prop->value();
-
- while (remaining.length()) {
-
- if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
- error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
- } else {
- string keyname = remaining.substr (0, equal);
-
- if (keyname == "EditorSort" || keyname == "editor") {
- info << string_compose(_("Converting deprecated order key for %1 using Editor order %2"), name (), n) << endmsg;
- set_order_key (n);
- }
- }
- }
-
- colon = remaining.find_first_of (':');
-
- if (colon != string::npos) {
- remaining = remaining.substr (colon+1);
- } else {
- break;
- }
- }
- }
-
/* IOs */
nlist = node.children ();
@@ -2893,13 +2665,6 @@ Route::set_state_2X (const XMLNode& node, int version)
_mute_control->set_state (*child, version);
}
- } else if (child->name() == X_("RemoteControl")) {
- if ((prop = child->property (X_("id"))) != 0) {
- int32_t x;
- sscanf (prop->value().c_str(), "%d", &x);
- set_remote_control_id_internal (x);
- }
-
}
}
diff --git a/libs/ardour/route_graph.cc b/libs/ardour/route_graph.cc
index 70b9b48d6f..7939b29c7c 100644
--- a/libs/ardour/route_graph.cc
+++ b/libs/ardour/route_graph.cc
@@ -198,11 +198,13 @@ struct RouteRecEnabledComparator
{
boost::shared_ptr<Track> t1 (boost::dynamic_pointer_cast<Track>(r1));
boost::shared_ptr<Track> t2 (boost::dynamic_pointer_cast<Track>(r2));
+ PresentationInfo::global_order_t r1o = r1->presentation_info().global_order();
+ PresentationInfo::global_order_t r2o = r2->presentation_info().global_order();
if (!t1) {
if (!t2) {
- /* makes no difference which is first, use signal order */
- return r1->order_key () < r2->order_key ();
+ /* makes no difference which is first, use presentation order */
+ return r1o < r2o;
} else {
/* r1 is not a track, r2 is, run it early */
return false;
@@ -210,14 +212,14 @@ struct RouteRecEnabledComparator
}
if (!t2) {
- /* we already tested !t1, so just use signal order */
- return r1->order_key () < r2->order_key ();
+ /* we already tested !t1, so just use presentation order */
+ return r1o < r2o;
}
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 ();
+ return r1o < r2o;
} else {
/* t1 rec-enabled, t2 not rec-enabled, run t2 early */
return false;
@@ -227,8 +229,8 @@ struct RouteRecEnabledComparator
/* t2 rec-enabled, t1 not rec-enabled, run t1 early */
return true;
} else {
- /* neither rec-enabled, use signal order */
- return t1->order_key () < t2->order_key ();
+ /* neither rec-enabled, use presentation order */
+ return r1o < r2o;
}
}
}
diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc
index 137e2c4734..b5f15412f9 100644
--- a/libs/ardour/route_group.cc
+++ b/libs/ardour/route_group.cc
@@ -473,7 +473,7 @@ RouteGroup::make_subgroup (bool aux, Placement placement)
* (since tracks can't have fewer outs than ins,
* "nin" currently defines the number of outpus if nin > 2)
*/
- rl = _session.new_audio_route (nin, 2 /*XXX*/, 0, 1);
+ rl = _session.new_audio_route (nin, 2, 0, 1, string(), PresentationInfo::AudioBus, PresentationInfo::max_order);
} catch (...) {
return;
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 55cd1f9ae8..8856d9d323 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -92,7 +92,6 @@
#include "ardour/region_factory.h"
#include "ardour/route_graph.h"
#include "ardour/route_group.h"
-#include "ardour/route_sorters.h"
#include "ardour/send.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
@@ -308,7 +307,6 @@ Session::Session (AudioEngine &eng,
, _step_editors (0)
, _suspend_timecode_transmission (0)
, _speakers (new Speakers)
- , _order_hint (-1)
, ignore_route_processor_changes (false)
, midi_clock (0)
, _scene_changer (0)
@@ -1149,7 +1147,7 @@ Session::add_monitor_section ()
return;
}
- boost::shared_ptr<Route> r (new Route (*this, _("Monitor"), Route::MonitorOut, DataType::AUDIO));
+ boost::shared_ptr<Route> r (new Route (*this, _("Monitor"), PresentationInfo::MonitorOut, DataType::AUDIO));
if (r->init ()) {
return;
@@ -1167,7 +1165,7 @@ Session::add_monitor_section ()
}
rl.push_back (r);
- add_routes (rl, false, false, false);
+ add_routes (rl, false, false, false, 0);
assert (_monitor_out);
@@ -2307,8 +2305,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
#ifndef NDEBUG
DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2\n",
- (*i)->name(), (*i)->order_key ()));
+ DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 presentation order %2\n", (*i)->name(), (*i)->presentation_info().global_order()));
}
#endif
@@ -2426,8 +2423,9 @@ Session::default_track_name_pattern (DataType t)
* @param instrument plugin info for the instrument to insert pre-fader, if any
*/
list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost::shared_ptr<PluginInfo> instrument,
- TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template, Plugin::PresetRecord* pset)
+Session::new_midi_track (boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset,
+ RouteGroup* route_group, uint32_t how_many, string name_template, PresentationInfo::order_t order,
+ TrackMode mode)
{
string track_name;
uint32_t track_id = 0;
@@ -2447,7 +2445,7 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
boost::shared_ptr<MidiTrack> track;
try {
- track.reset (new MidiTrack (*this, track_name, Route::Flag (0), mode));
+ track.reset (new MidiTrack (*this, track_name, mode));
if (track->init ()) {
goto failed;
@@ -2482,14 +2480,8 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
- if (Config->get_remote_model() == UserOrdered) {
- track->set_remote_control_id (next_control_id());
- }
-
new_routes.push_back (track);
ret.push_back (track);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
}
catch (failed_constructor &err) {
@@ -2510,9 +2502,9 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
if (!new_routes.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (new_routes, false, false, false);
+ add_routes (new_routes, false, false, false, order);
} else {
- add_routes (new_routes, true, true, false);
+ add_routes (new_routes, true, true, false, order);
}
if (instrument) {
@@ -2532,7 +2524,8 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
}
RouteList
-Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset)
+Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset,
+ PresentationInfo::Flag flag, PresentationInfo::order_t order)
{
string bus_name;
uint32_t bus_id = 0;
@@ -2546,9 +2539,9 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
error << "cannot find name for new midi bus" << endmsg;
goto failure;
}
-
+
try {
- boost::shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO)); // XXX Editor::add_routes is not ready for ARDOUR::DataType::MIDI
+ boost::shared_ptr<Route> bus (new Route (*this, bus_name, flag, DataType::AUDIO)); // XXX Editor::add_routes is not ready for ARDOUR::DataType::MIDI
if (bus->init ()) {
goto failure;
@@ -2578,13 +2571,8 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
if (route_group) {
route_group->add (bus);
}
- if (Config->get_remote_model() == UserOrdered) {
- bus->set_remote_control_id (next_control_id());
- }
ret.push_back (bus);
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
- ARDOUR::GUIIdle ();
}
catch (failed_constructor &err) {
@@ -2604,7 +2592,7 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
failure:
if (!ret.empty()) {
StateProtector sp (this);
- add_routes (ret, false, false, false);
+ add_routes (ret, false, false, false, order);
if (instrument) {
for (RouteList::iterator r = ret.begin(); r != ret.end(); ++r) {
@@ -2931,12 +2919,36 @@ Session::reconnect_mmc_ports(bool inputs)
#endif
+void
+Session::ensure_presentation_info_gap (PresentationInfo::order_t first_new_order, uint32_t how_many)
+{
+ if (first_new_order == PresentationInfo::max_order) {
+ /* adding at end, no worries */
+ return;
+ }
+
+ /* create a gap in the existing route order keys to accomodate new routes.*/
+ boost::shared_ptr <RouteList> rd = routes.reader();
+ for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
+ boost::shared_ptr<Route> rt (*ri);
+
+ if (rt->presentation_info().special()) {
+ continue;
+ }
+
+ if (rt->presentation_info().group_order () >= first_new_order) {
+ rt->set_presentation_group_order (rt->presentation_info().group_order () + how_many);
+ }
+ }
+}
+
/** Caller must not hold process lock
* @param name_template string to use for the start of the name, or "" to use "Audio".
*/
list< boost::shared_ptr<AudioTrack> >
-Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group,
- uint32_t how_many, string name_template)
+Session::new_audio_track (int input_channels, int output_channels, RouteGroup* route_group,
+ uint32_t how_many, string name_template, PresentationInfo::order_t order,
+ TrackMode mode)
{
string track_name;
uint32_t track_id = 0;
@@ -2957,7 +2969,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
boost::shared_ptr<AudioTrack> track;
try {
- track.reset (new AudioTrack (*this, track_name, Route::Flag (0), mode));
+ track.reset (new AudioTrack (*this, track_name, mode));
if (track->init ()) {
goto failed;
@@ -2967,7 +2979,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
track->set_strict_io (true);
}
-
if (ARDOUR::Profile->get_trx ()) {
// TRACKS considers it's not a USE CASE, it's
// a piece of behavior of the session model:
@@ -3013,14 +3024,9 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
track->non_realtime_input_change();
track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
- if (Config->get_remote_model() == UserOrdered) {
- track->set_remote_control_id (next_control_id());
- }
new_routes.push_back (track);
ret.push_back (track);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
}
catch (failed_constructor &err) {
@@ -3041,9 +3047,9 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
if (!new_routes.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (new_routes, false, false, false);
+ add_routes (new_routes, false, false, false, order);
} else {
- add_routes (new_routes, true, true, false);
+ add_routes (new_routes, true, true, false, order);
}
}
@@ -3054,7 +3060,8 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
* @param name_template string to use for the start of the name, or "" to use "Bus".
*/
RouteList
-Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, string name_template)
+Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, string name_template,
+ PresentationInfo::Flag flags, PresentationInfo::order_t order)
{
string bus_name;
uint32_t bus_id = 0;
@@ -3063,6 +3070,8 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
+ ensure_presentation_info_gap (order, how_many);
+
while (how_many) {
if (!find_route_name (name_template.empty () ? _("Bus") : name_template, ++bus_id, bus_name, use_number)) {
error << "cannot find name for new audio bus" << endmsg;
@@ -3070,7 +3079,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
}
try {
- boost::shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO));
+ boost::shared_ptr<Route> bus (new Route (*this, bus_name, flags, DataType::AUDIO));
if (bus->init ()) {
goto failure;
@@ -3104,20 +3113,11 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
if (route_group) {
route_group->add (bus);
}
- if (Config->get_remote_model() == UserOrdered) {
- bus->set_remote_control_id (next_control_id());
- }
bus->add_internal_return ();
-
ret.push_back (bus);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
-
- ARDOUR::GUIIdle ();
}
-
catch (failed_constructor &err) {
error << _("Session: could not create new audio route.") << endmsg;
goto failure;
@@ -3136,9 +3136,9 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
if (!ret.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (ret, false, false, false);
+ add_routes (ret, false, false, false, order);
} else {
- add_routes (ret, false, true, true); // autoconnect // outputs only
+ add_routes (ret, false, true, true, order); // autoconnect // outputs only
}
}
@@ -3162,7 +3162,6 @@ RouteList
Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::string& name_base, PlaylistDisposition pd)
{
RouteList ret;
- uint32_t control_id;
uint32_t number = 0;
const uint32_t being_added = how_many;
/* This will prevent the use of any existing XML-provided PBD::ID
@@ -3171,8 +3170,6 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
Stateful::ForceIDRegeneration force_ids;
IO::disable_connecting ();
- control_id = next_control_id ();
-
while (how_many) {
/* We're going to modify the node contents a bit so take a
@@ -3293,9 +3290,6 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
route->output()->changed (change, this);
}
- route->set_remote_control_id (control_id);
- ++control_id;
-
boost::shared_ptr<Track> track;
if ((track = boost::dynamic_pointer_cast<Track> (route))) {
@@ -3312,8 +3306,6 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
};
ret.push_back (route);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
}
catch (failed_constructor &err) {
@@ -3333,9 +3325,9 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
if (!ret.empty()) {
StateProtector sp (this);
if (Profile->get_trx()) {
- add_routes (ret, false, false, false);
+ add_routes (ret, false, false, false, PresentationInfo::max_order);
} else {
- add_routes (ret, true, true, false);
+ add_routes (ret, true, true, false, PresentationInfo::max_order);
}
IO::enable_connecting ();
}
@@ -3344,11 +3336,11 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
}
void
-Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save)
+Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save, PresentationInfo::order_t order)
{
try {
PBD::Unwinder<bool> aip (_adding_routes_in_progress, true);
- add_routes_inner (new_routes, input_auto_connect, output_auto_connect);
+ add_routes_inner (new_routes, input_auto_connect, output_auto_connect, order);
} catch (...) {
error << _("Adding new tracks/busses failed") << endmsg;
@@ -3365,25 +3357,18 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
save_state (_current_snapshot_name);
}
- reassign_track_numbers();
-
update_route_record_state ();
RouteAdded (new_routes); /* EMIT SIGNAL */
}
void
-Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect)
+Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, PresentationInfo::order_t order)
{
ChanCount existing_inputs;
ChanCount existing_outputs;
- uint32_t order = next_control_id();
-
-
- if (_order_hint > -1) {
- order = _order_hint;
- _order_hint = -1;
- }
+ uint32_t n_routes;
+ uint32_t added = 0;
count_existing_track_channels (existing_inputs, existing_outputs);
@@ -3391,6 +3376,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
RCUWriter<RouteList> writer (routes);
boost::shared_ptr<RouteList> r = writer.get_copy ();
r->insert (r->end(), new_routes.begin(), new_routes.end());
+ n_routes = r->size();
/* if there is no control out and we're not in the middle of loading,
* resort the graph here. if there is a control out, we will resort
@@ -3403,7 +3389,10 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
}
}
- for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("ensure order gap starting at %1 for %2\n", order, new_routes.size()));
+ ensure_presentation_info_gap (order, new_routes.size());
+
+ for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x, ++added) {
boost::weak_ptr<Route> wpr (*x);
boost::shared_ptr<Route> r (*x);
@@ -3436,28 +3425,41 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
}
}
- if (input_auto_connect || output_auto_connect) {
- auto_connect_route (r, input_auto_connect, ChanCount (), ChanCount (), existing_inputs, existing_outputs);
- existing_inputs += r->n_inputs();
- existing_outputs += r->n_outputs();
- }
+ if (!r->presentation_info().special()) {
- /* order keys are a GUI responsibility but we need to set up
- reasonable defaults because they also affect the remote control
- ID in most situations.
- */
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("checking PI state for %1\n", r->name()));
+
+ /* presentation info order may already have been set from XML */
+
+ if (r->presentation_info().unordered()) {
- if (!r->has_order_key ()) {
- if (r->is_auditioner()) {
- /* use an arbitrarily high value */
- r->set_order_key (UINT_MAX);
+ if (order == PresentationInfo::max_order) {
+ /* just add to the end */
+ r->set_presentation_group_order_explicit (n_routes + added);
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to NR %1 + %2 = %3\n", n_routes, added, n_routes + added));
+ } else {
+ r->set_presentation_group_order_explicit (order + added);
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to %1 + %2 = %3\n", order, added, order + added));
+ }
} else {
- DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("while adding, set %1 to order key %2\n", r->name(), order));
- r->set_order_key (order);
- order++;
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order already set to %1\n", r->presentation_info().group_order()));
}
}
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("added route %1, group order %2 global order %3 type %4 (summary: %5)\n",
+ r->name(),
+ r->presentation_info().group_order(),
+ r->presentation_info().global_order(),
+ enum_2_string (r->presentation_info().flags()),
+ r->presentation_info().to_string()));
+
+
+ if (input_auto_connect || output_auto_connect) {
+ auto_connect_route (r, input_auto_connect, ChanCount (), ChanCount (), existing_inputs, existing_outputs);
+ existing_inputs += r->n_inputs();
+ existing_outputs += r->n_outputs();
+ }
+
ARDOUR::GUIIdle ();
}
@@ -3631,7 +3633,6 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
} // end of RCU Writer scope
update_route_solo_state ();
- RouteAddedOrRemoved (false); /* EMIT SIGNAL */
update_latency_compensation ();
set_dirty();
@@ -3668,7 +3669,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
return;
}
- Route::RemoteControlIDChange(); /* EMIT SIGNAL */
+ Stripable::PresentationInfoChange(); /* EMIT SIGNAL */
/* save the new state of the world */
@@ -3676,7 +3677,6 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
save_history (_current_snapshot_name);
}
- reassign_track_numbers();
update_route_record_state ();
}
@@ -4028,7 +4028,7 @@ Session::get_routes_with_internal_returns() const
}
bool
-Session::io_name_is_legal (const std::string& name)
+Session::io_name_is_legal (const std::string& name) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
@@ -4137,7 +4137,7 @@ Session::routes_using_input_from (const string& str, RouteList& rl)
}
boost::shared_ptr<Route>
-Session::route_by_name (string name)
+Session::route_by_name (string name) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
@@ -4151,7 +4151,7 @@ Session::route_by_name (string name)
}
boost::shared_ptr<Route>
-Session::route_by_id (PBD::ID id)
+Session::route_by_id (PBD::ID id) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
@@ -4180,7 +4180,7 @@ Session::processor_by_id (PBD::ID id) const
}
boost::shared_ptr<Track>
-Session::track_by_diskstream_id (PBD::ID id)
+Session::track_by_diskstream_id (PBD::ID id) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
@@ -4195,37 +4195,34 @@ Session::track_by_diskstream_id (PBD::ID id)
}
boost::shared_ptr<Route>
-Session::route_by_remote_id (uint32_t id)
+Session::get_remote_nth_route (uint16_t n) const
{
- boost::shared_ptr<RouteList> r = routes.reader ();
-
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ((*i)->remote_control_id() == id) {
- return *i;
- }
- }
-
- return boost::shared_ptr<Route> ((Route*) 0);
+ return boost::dynamic_pointer_cast<Route> (get_remote_nth_stripable (n, PresentationInfo::Route));
}
-
boost::shared_ptr<Stripable>
-Session::stripable_by_remote_id (uint32_t id)
+Session::get_remote_nth_stripable (uint16_t n, PresentationInfo::Flag flags) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
+ vector<boost::shared_ptr<Route> > v;
+
+ if (n > r->size()) {
+ return boost::shared_ptr<Route> ();
+ }
+
+ v.assign (r->size(), boost::shared_ptr<Route>());
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ((*i)->remote_control_id() == id) {
- return *i;
+ if ((*i)->presentation_info().flag_match (flags)) {
+ v[(*i)->presentation_info().group_order()] = (*i);
}
}
- return boost::shared_ptr<Route> ((Route*) 0);
+ return v[n];
}
-
boost::shared_ptr<Route>
-Session::route_by_selected_count (uint32_t id)
+Session::route_by_selected_count (uint32_t id) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
@@ -4236,6 +4233,19 @@ Session::route_by_selected_count (uint32_t id)
return boost::shared_ptr<Route> ((Route*) 0);
}
+struct PresentationOrderSorter {
+ bool operator() (boost::shared_ptr<Stripable> a, boost::shared_ptr<Stripable> b) {
+ if (a->presentation_info().special() && !b->presentation_info().special()) {
+ /* a is not ordered, b is; b comes before a */
+ return false;
+ } else if (b->presentation_info().unordered() && !a->presentation_info().unordered()) {
+ /* b is not ordered, a is; a comes before b */
+ return true;
+ } else {
+ return a->presentation_info().global_order() < b->presentation_info().global_order();
+ }
+ }
+};
void
Session::reassign_track_numbers ()
@@ -4243,7 +4253,7 @@ Session::reassign_track_numbers ()
int64_t tn = 0;
int64_t bn = 0;
RouteList r (*(routes.reader ()));
- SignalOrderRouteSorter sorter;
+ PresentationOrderSorter sorter;
r.sort (sorter);
StateProtector sp (this);
@@ -5319,7 +5329,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::
if (b->is_monitor()) {
return false;
}
- return a->order_key () < b->order_key ();
+ return a->presentation_info() < b->presentation_info();
}
bool
@@ -6659,31 +6669,8 @@ Session::session_name_is_legal (const string& path)
return 0;
}
-uint32_t
-Session::next_control_id () const
-{
- int subtract = 0;
-
- /* the monitor bus remote ID is in a different
- * "namespace" than regular routes. its existence doesn't
- * affect normal (low) numbered routes.
- */
-
- if (_monitor_out) {
- subtract++;
- }
-
- /* the same about masterbus in Waves Tracks */
-
- if (Profile->get_trx() && _master_out) {
- subtract++;
- }
-
- return nroutes() - subtract;
-}
-
void
-Session::notify_remote_id_change ()
+Session::notify_presentation_info_change ()
{
if (deletion_in_progress()) {
return;
@@ -6691,41 +6678,21 @@ Session::notify_remote_id_change ()
switch (Config->get_remote_model()) {
case MixerOrdered:
- Route::RemoteControlIDChange (); /* EMIT SIGNAL */
+ Stripable::PresentationInfoChange (); /* EMIT SIGNAL */
break;
default:
break;
}
-#ifdef USE_TRACKS_CODE_FEATURES
- /* Waves Tracks: for Waves Tracks session it's required to reconnect their IOs
- * if track order has been changed by user
- */
- reconnect_existing_routes(true, true);
-#endif
-
-}
-
-void
-Session::sync_order_keys ()
-{
- if (deletion_in_progress()) {
- return;
- }
-
- /* tell everyone that something has happened to the sort keys
- and let them sync up with the change(s)
- this will give objects that manage the sort order keys the
- opportunity to keep them in sync if they wish to.
- */
-
- DEBUG_TRACE (DEBUG::OrderKeys, "Sync Order Keys.\n");
-
reassign_track_numbers();
- Route::SyncOrderKeys (); /* EMIT SIGNAL */
+#ifdef USE_TRACKS_CODE_FEATURES
+ /* Waves Tracks: for Waves Tracks session it's required to reconnect their IOs
+ * if track order has been changed by user
+ */
+ reconnect_existing_routes(true, true);
+#endif
- DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n");
}
bool
diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc
index 390f1de32f..f3a8d7dd81 100644
--- a/libs/ardour/session_midi.cc
+++ b/libs/ardour/session_midi.cc
@@ -335,6 +335,30 @@ Session::mmc_shuttle (MIDI::MachineControl &/*mmc*/, float speed, bool forw)
}
}
+boost::shared_ptr<Route>
+Session::get_midi_nth_route_by_id (PresentationInfo::order_t n) const
+{
+ PresentationInfo id (PresentationInfo::Flag (0));
+
+ if (n == 318) {
+ id.set_flags (PresentationInfo::MasterOut);
+ } else if (n == 319) {
+ id.set_flags (PresentationInfo::MonitorOut);
+ } else {
+ id = PresentationInfo (n, PresentationInfo::Route);
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ if ((*i)->presentation_info().match (id)) {
+ return *i;
+ }
+ }
+
+ return boost::shared_ptr<Route>();
+}
+
void
Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled)
{
@@ -342,17 +366,13 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled)
return;
}
- RouteList::iterator i;
- boost::shared_ptr<RouteList> r = routes.reader();
+ boost::shared_ptr<Route> r = get_midi_nth_route_by_id (trk);
- for (i = r->begin(); i != r->end(); ++i) {
- AudioTrack *at;
+ if (r) {
+ boost::shared_ptr<AudioTrack> at;
- if ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) {
- if (trk == at->remote_control_id()) {
- at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
- break;
- }
+ if ((at = boost::dynamic_pointer_cast<AudioTrack> (r))) {
+ at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
}
}
}
@@ -696,4 +716,3 @@ Session::mtc_input_port () const
{
return _midi_ports->mtc_input_port ();
}
-
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index ebbd37e4f9..5b10389a3f 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -628,7 +628,7 @@ Session::create (const string& session_template, BusProfile* bus_profile)
_state_of_the_state = Clean;
- /* set up Master Out and Control Out if necessary */
+ /* set up Master Out and Monitor Out if necessary */
if (bus_profile) {
@@ -637,7 +637,7 @@ Session::create (const string& session_template, BusProfile* bus_profile)
// Waves Tracks: always create master bus for Tracks
if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
- boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
+ boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
if (r->init ()) {
return -1;
}
@@ -658,7 +658,7 @@ Session::create (const string& session_template, BusProfile* bus_profile)
}
if (!rl.empty()) {
- add_routes (rl, false, false, false);
+ add_routes (rl, false, false, false, PresentationInfo::max_order);
}
// Waves Tracks: Skip this. Always use autoconnection for Tracks
@@ -1593,7 +1593,7 @@ Session::load_routes (const XMLNode& node, int version)
BootMessage (_("Tracks/busses loaded; Adding to Session"));
- add_routes (new_routes, false, false, false);
+ add_routes (new_routes, false, false, false, PresentationInfo::max_order);
BootMessage (_("Finished adding tracks/busses"));
@@ -1642,12 +1642,7 @@ Session::XMLRouteFactory (const XMLNode& node, int version)
ret = track;
} else {
- enum Route::Flag flags = Route::Flag(0);
- XMLProperty const * prop = node.property("flags");
- if (prop) {
- flags = Route::Flag (string_2_enum (prop->value(), flags));
- }
-
+ PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
if (r->init () == 0 && r->set_state (node, version) == 0) {
@@ -1716,12 +1711,7 @@ Session::XMLRouteFactory_2X (const XMLNode& node, int version)
ret = track;
} else {
- enum Route::Flag flags = Route::Flag(0);
- XMLProperty const * prop = node.property("flags");
- if (prop) {
- flags = Route::Flag (string_2_enum (prop->value(), flags));
- }
-
+ PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
if (r->init () == 0 && r->set_state (node, version) == 0) {
@@ -3423,7 +3413,7 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc)
}
case ControllableDescriptor::RemoteControlID:
- r = route_by_remote_id (desc.rid());
+ r = get_remote_nth_route (desc.rid());
break;
case ControllableDescriptor::SelectionCount:
diff --git a/libs/ardour/stripable.cc b/libs/ardour/stripable.cc
new file mode 100644
index 0000000000..d322fd75de
--- /dev/null
+++ b/libs/ardour/stripable.cc
@@ -0,0 +1,160 @@
+/*
+ Copyright (C) 2016 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/algorithm/string.hpp>
+
+#include "pbd/compose.h"
+#include "pbd/convert.h"
+
+#include "ardour/debug.h"
+#include "ardour/rc_configuration.h"
+#include "ardour/stripable.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using std::string;
+
+PBD::Signal0<void> Stripable::PresentationInfoChange;
+
+Stripable::Stripable (Session& s, string const & name, PresentationInfo const & pi)
+ : SessionObject (s, name)
+ , _presentation_info (pi)
+{
+}
+
+void
+Stripable::set_presentation_group_order (PresentationInfo::order_t order, bool notify_class_listeners)
+{
+ set_presentation_info_internal (PresentationInfo (order, _presentation_info.flags()), notify_class_listeners);
+}
+
+void
+Stripable::set_presentation_group_order_explicit (PresentationInfo::order_t order)
+{
+ set_presentation_group_order (order, false);
+}
+
+void
+Stripable::set_presentation_info (PresentationInfo pi, bool notify_class_listeners)
+{
+ if (Config->get_remote_model() != UserOrdered) {
+ return;
+ }
+
+ set_presentation_info_internal (pi, notify_class_listeners);
+}
+
+void
+Stripable::set_presentation_info_internal (PresentationInfo pi, bool notify_class_listeners)
+{
+ if (pi != presentation_info()) {
+
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: set edit-based RID to %2\n", name(), pi));
+
+ if (is_master()) {
+ _presentation_info = PresentationInfo (0, PresentationInfo::MasterOut);
+ } else if (is_monitor()) {
+ _presentation_info = PresentationInfo (0, PresentationInfo::MonitorOut);
+ } else {
+ _presentation_info = pi;
+ }
+
+ PresentationInfoChanged ();
+
+ if (notify_class_listeners) {
+ PresentationInfoChange ();
+ }
+ }
+}
+
+void
+Stripable::set_presentation_info_explicit (PresentationInfo pi)
+{
+ set_presentation_info_internal (pi, false);
+}
+
+int
+Stripable::set_state (XMLNode const& node, int version)
+{
+ const XMLProperty *prop;
+ XMLNodeList const & nlist (node.children());
+ XMLNodeConstIterator niter;
+ XMLNode *child;
+
+ if (version > 3000) {
+
+ std::cerr << "Looking for PI\n";
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter){
+ child = *niter;
+
+ if (child->name() == X_("PresentationInfo")) {
+ std::cerr << "Found it\n";
+ if ((prop = child->property (X_("value"))) != 0) {
+ _presentation_info = prop->value ();
+ std::cerr << "Set pinfo to " << _presentation_info << " from " << prop->value() << std::endl;
+ }
+ }
+ }
+
+ } else {
+ std::cerr << "Old\n";
+
+ /* Older versions of Ardour stored "_flags" as a property of the Route
+ * node, only for 3 special Routes (MasterOut, MonitorOut, Auditioner.
+ *
+ * Their presentation order was stored in a node called "RemoteControl"
+ *
+ * This information is now part of the PresentationInfo of every Stripable.
+ */
+
+ if ((prop = node.property (X_("flags"))) != 0) {
+
+ /* 4.x and earlier - didn't have Stripable but the
+ * relevant enums have the same names (MasterOut,
+ * MonitorOut, Auditioner), so we can use string_2_enum
+ */
+
+ PresentationInfo::Flag flags;
+
+ if (version < 3000) {
+ string f (prop->value());
+ boost::replace_all (f, "ControlOut", "MonitorOut");
+ flags = PresentationInfo::Flag (string_2_enum (f, flags));
+ } else {
+ flags = PresentationInfo::Flag (string_2_enum (prop->value(), flags));
+ }
+
+ _presentation_info.set_flags (flags);
+
+ }
+ }
+
+ return 0;
+}
+
+void
+Stripable::add_state (XMLNode& node) const
+{
+ XMLNode* remote_control_node = new XMLNode (X_("PresentationInfo"));
+ remote_control_node->add_property (X_("value"), _presentation_info.to_string());
+ node.add_child_nocopy (*remote_control_node);
+}
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index 80169bf5a1..17a7c13295 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -40,7 +40,7 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type)
+Track::Track (Session& sess, string name, PresentationInfo::Flag flag, TrackMode mode, DataType default_type)
: Route (sess, name, flag, default_type)
, _saved_meter_point (_meter_point)
, _mode (mode)
@@ -75,7 +75,6 @@ Track::init ()
_monitoring_control.reset (new MonitorControl (_session, X_("monitoring"), *this));
add_control (_monitoring_control);
- 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));
_monitoring_control->Changed.connect_same_thread (*this, boost::bind (&Track::monitoring_changed, this, _1, _2));
diff --git a/libs/ardour/vca.cc b/libs/ardour/vca.cc
index 3310c924cb..d3c614debf 100644
--- a/libs/ardour/vca.cc
+++ b/libs/ardour/vca.cc
@@ -65,7 +65,7 @@ VCA::get_next_vca_number ()
}
VCA::VCA (Session& s, uint32_t num, const string& name)
- : Stripable (s, name)
+ : Stripable (s, name, PresentationInfo (num, PresentationInfo::VCA))
, Muteable (s, name)
, Automatable (s)
, _number (num)
@@ -106,6 +106,8 @@ VCA::get_state ()
node->add_property (X_("name"), _name);
node->add_property (X_("number"), _number);
+ Stripable::add_state (*node);
+
node->add_child_nocopy (_gain_control->get_state());
node->add_child_nocopy (_solo_control->get_state());
node->add_child_nocopy (_mute_control->get_state());
@@ -121,6 +123,8 @@ VCA::set_state (XMLNode const& node, int version)
{
XMLProperty const* prop;
+ Stripable::set_state (node, version);
+
if ((prop = node.property ("name")) != 0) {
set_name (prop->value());
}
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 9a9b650a66..1be40f7f63 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -169,6 +169,7 @@ libardour_sources = [
'port_insert.cc',
'port_manager.cc',
'port_set.cc',
+ 'presentation_info.cc',
'process_thread.cc',
'processor.cc',
'progress.cc',
@@ -225,6 +226,7 @@ libardour_sources = [
'source_factory.cc',
'speakers.cc',
'srcfilesource.cc',
+ 'stripable.cc',
'strip_silence.cc',
'system_exec.cc',
'revision.cc',