From e0ff70cf86c01c42f98faf8b0eaf1a8ccf867946 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 16 May 2016 07:30:28 -0400 Subject: first vaguely working version using PresentationInfo remote control ID and "order keys" have been removed. --- libs/ardour/ardour/audio_track.h | 2 +- libs/ardour/ardour/midi_track.h | 2 +- libs/ardour/ardour/mute_control.h | 1 + libs/ardour/ardour/presentation_info.h | 303 +++++++++++++++++++++++++++++++++ libs/ardour/ardour/route.h | 50 +----- libs/ardour/ardour/route_sorters.h | 44 ----- libs/ardour/ardour/session.h | 60 +++---- libs/ardour/ardour/stripable.h | 64 ++++++- libs/ardour/ardour/track.h | 2 +- libs/ardour/audio_track.cc | 4 +- libs/ardour/auditioner.cc | 2 +- libs/ardour/enums.cc | 22 ++- libs/ardour/luabindings.cc | 2 +- libs/ardour/midi_track.cc | 4 +- libs/ardour/presentation_info.cc | 121 +++++++++++++ libs/ardour/route.cc | 247 +-------------------------- libs/ardour/route_graph.cc | 16 +- libs/ardour/route_group.cc | 2 +- libs/ardour/session.cc | 299 +++++++++++++++----------------- libs/ardour/session_midi.cc | 39 +++-- libs/ardour/session_state.cc | 24 +-- libs/ardour/stripable.cc | 160 +++++++++++++++++ libs/ardour/track.cc | 3 +- libs/ardour/vca.cc | 6 +- libs/ardour/wscript | 2 + 25 files changed, 892 insertions(+), 589 deletions(-) create mode 100644 libs/ardour/ardour/presentation_info.h delete mode 100644 libs/ardour/ardour/route_sorters.h create mode 100644 libs/ardour/presentation_info.cc create mode 100644 libs/ardour/stripable.cc (limited to 'libs/ardour') 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 +#include + +#include + +#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 > 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 RemoteControlIDChanged; - - /* for things concerned about *any* route's RID changes */ - - static PBD::Signal0 RemoteControlIDChange; - static PBD::Signal0 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 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 a, boost::shared_ptr 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 DirtyChanged; - PBD::Signal1 RouteAddedOrRemoved; - const SessionDirectory& session_directory () const { return *(_session_dir.get()); } static PBD::Signal1 Dialog; @@ -293,22 +293,20 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop bool operator() (boost::shared_ptr, boost::shared_ptr 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 void foreach_route (T *obj, void (T::*func)(Route&), bool sort = true); template void foreach_route (T *obj, void (T::*func)(boost::shared_ptr), bool sort = true); template 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_by_name (std::string); - boost::shared_ptr route_by_id (PBD::ID); - boost::shared_ptr route_by_remote_id (uint32_t id); - boost::shared_ptr stripable_by_remote_id (uint32_t id); - boost::shared_ptr route_by_selected_count (uint32_t cnt); - boost::shared_ptr track_by_diskstream_id (PBD::ID); + bool io_name_is_legal (const std::string&) const; + boost::shared_ptr route_by_name (std::string) const; + boost::shared_ptr route_by_id (PBD::ID) const; + boost::shared_ptr get_remote_nth_stripable (uint16_t n, PresentationInfo::Flag) const; + boost::shared_ptr get_remote_nth_route (uint16_t n) const; + boost::shared_ptr route_by_selected_count (uint32_t cnt) const; + boost::shared_ptr 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 > 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 > new_midi_track ( const ChanCount& input, const ChanCount& output, - boost::shared_ptr instrument = boost::shared_ptr(), - TrackMode mode = Normal, - RouteGroup* route_group = 0, uint32_t how_many = 1, std::string name_template = "", - Plugin::PresetRecord* pset = 0 + boost::shared_ptr 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 instrument = boost::shared_ptr(), - 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 instrument, Plugin::PresetRecord*, PresentationInfo::Flag, PresentationInfo::order_t); void remove_routes (boost::shared_ptr); void remove_route (boost::shared_ptr); @@ -1658,8 +1651,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop SerializedRCUManager 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 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 #include +#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 PresentationInfoChanged; + + /* for things concerned about *any* route's RID changes */ + + static PBD::Signal0 PresentationInfoChange; + + /*************************************************************** + * Pure interface begins here + ***************************************************************/ + virtual boost::shared_ptr peak_meter() = 0; virtual boost::shared_ptr peak_meter() const = 0; @@ -140,6 +170,28 @@ class Stripable : public SessionObject { virtual boost::shared_ptr 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 a, boost::shared_ptr 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 +#include + +#include + +#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 Route::SyncOrderKeys; -PBD::Signal0 Route::RemoteControlIDChange; PBD::Signal3, boost::shared_ptr, 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 t1 (boost::dynamic_pointer_cast(r1)); boost::shared_ptr t2 (boost::dynamic_pointer_cast(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 r (new Route (*this, _("Monitor"), Route::MonitorOut, DataType::AUDIO)); + boost::shared_ptr 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 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 > -Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost::shared_ptr instrument, - TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template, Plugin::PresetRecord* pset) +Session::new_midi_track (boost::shared_ptr 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 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 instrument, Plugin::PresetRecord* pset) +Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr 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 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 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 rd = routes.reader(); + for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) { + boost::shared_ptr 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 > -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 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 bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO)); + boost::shared_ptr 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; if ((track = boost::dynamic_pointer_cast (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 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 writer (routes); boost::shared_ptr 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 wpr (*x); boost::shared_ptr 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 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 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 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 r = routes.reader (); @@ -4137,7 +4137,7 @@ Session::routes_using_input_from (const string& str, RouteList& rl) } boost::shared_ptr -Session::route_by_name (string name) +Session::route_by_name (string name) const { boost::shared_ptr r = routes.reader (); @@ -4151,7 +4151,7 @@ Session::route_by_name (string name) } boost::shared_ptr -Session::route_by_id (PBD::ID id) +Session::route_by_id (PBD::ID id) const { boost::shared_ptr r = routes.reader (); @@ -4180,7 +4180,7 @@ Session::processor_by_id (PBD::ID id) const } boost::shared_ptr -Session::track_by_diskstream_id (PBD::ID id) +Session::track_by_diskstream_id (PBD::ID id) const { boost::shared_ptr r = routes.reader (); @@ -4195,37 +4195,34 @@ Session::track_by_diskstream_id (PBD::ID id) } boost::shared_ptr -Session::route_by_remote_id (uint32_t id) +Session::get_remote_nth_route (uint16_t n) const { - boost::shared_ptr 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*) 0); + return boost::dynamic_pointer_cast (get_remote_nth_stripable (n, PresentationInfo::Route)); } - boost::shared_ptr -Session::stripable_by_remote_id (uint32_t id) +Session::get_remote_nth_stripable (uint16_t n, PresentationInfo::Flag flags) const { boost::shared_ptr r = routes.reader (); + vector > v; + + if (n > r->size()) { + return boost::shared_ptr (); + } + + v.assign (r->size(), boost::shared_ptr()); 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*) 0); + return v[n]; } - boost::shared_ptr -Session::route_by_selected_count (uint32_t id) +Session::route_by_selected_count (uint32_t id) const { boost::shared_ptr r = routes.reader (); @@ -4236,6 +4233,19 @@ Session::route_by_selected_count (uint32_t id) return boost::shared_ptr ((Route*) 0); } +struct PresentationOrderSorter { + bool operator() (boost::shared_ptr a, boost::shared_ptr 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 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 +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 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(); +} + 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 r = routes.reader(); + boost::shared_ptr r = get_midi_nth_route_by_id (trk); - for (i = r->begin(); i != r->end(); ++i) { - AudioTrack *at; + if (r) { + boost::shared_ptr at; - if ((at = dynamic_cast((*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 (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 r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO)); + boost::shared_ptr 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 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 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 + +#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 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', -- cgit v1.2.3