#include "ardour/recent_sessions.h"
#include "ardour/region.h"
#include "ardour/region_factory.h"
+#include "ardour/revision.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"
, _step_editors (0)
, _suspend_timecode_transmission (0)
, _speakers (new Speakers)
- , _order_hint (-1)
, ignore_route_processor_changes (false)
, midi_clock (0)
, _scene_changer (0)
{
uint32_t sr = 0;
+ created_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
+
pthread_mutex_init (&_rt_emit_mutex, 0);
pthread_cond_init (&_rt_emit_cond, 0);
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;
}
rl.push_back (r);
- add_routes (rl, false, false, false);
+ add_routes (rl, false, false, false, 0);
assert (_monitor_out);
_master_out->output()->disconnect (this);
_monitor_out->output()->disconnect (this);
- _monitor_out->input()->ensure_io (_master_out->output()->n_ports(), false, this);
- _monitor_out->output()->ensure_io (_master_out->output()->n_ports(), false, this);
+ // monitor section follow master bus - except midi
+ ChanCount mon_chn (_master_out->output()->n_ports());
+ mon_chn.set_midi (0);
+
+ _monitor_out->input()->ensure_io (mon_chn, false, this);
+ _monitor_out->output()->ensure_io (mon_chn, false, this);
for (uint32_t n = 0; n < limit; ++n) {
boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
Session::set_all_tracks_record_enabled (bool enable )
{
boost::shared_ptr<RouteList> rl = routes.reader();
- set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), enable, Controllable::NoGroup);
+ set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), enable, Controllable::NoGroup);
}
void
#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().order()));
}
#endif
* @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 (const ChanCount& input, const ChanCount& output,
+ 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;
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;
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) {
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) {
}
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;
}
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;
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) {
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) {
#endif
+void
+Session::ensure_route_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 presentation info to accomodate @param how_many
+ * new objects.
+ */
+ 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().order () >= first_new_order) {
+ rt->set_presentation_order (rt->presentation_info().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;
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;
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:
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) {
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);
}
}
* @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;
}
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;
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;
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
}
}
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
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
(*i)->add_property ("bitslot", buf);
(*i)->add_property ("name", name);
}
+ else if (type && type->value() == X_("intreturn")) {
+ (*i)->remove_property (X_("bitslot"));
+ (*i)->add_property ("ignore-bitslot", "1");
+ }
else if (type && type->value() == X_("return")) {
// Return::set_state() generates a new one
(*i)->remove_property (X_("bitslot"));
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))) {
};
ret.push_back (route);
-
- RouteAddedOrRemoved (true); /* EMIT SIGNAL */
}
catch (failed_constructor &err) {
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 ();
}
}
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;
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);
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
}
}
- 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_route_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);
}
}
- 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()));
- if (!r->has_order_key ()) {
- if (r->is_auditioner()) {
- /* use an arbitrarily high value */
- r->set_order_key (UINT_MAX);
+ /* presentation info order may already have been set from XML */
+
+ if (!r->presentation_info().order_set()) {
+
+ if (order == PresentationInfo::max_order) {
+ /* just add to the end */
+ r->set_presentation_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_order (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().order()));
}
}
+#ifndef __APPLE__
+ /* clang complains: 'operator<<' should be declared prior to the call site or in an associated namespace of one of its
+ * arguments std::ostream& operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid)"
+ */
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("added route %1, group order %2 type %3 (summary: %4)\n",
+ r->name(),
+ r->presentation_info().order(),
+ enum_2_string (r->presentation_info().flags()),
+ r->presentation_info()));
+#endif
+
+
+ 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 ();
}
}
}
}
+
+ reassign_track_numbers ();
}
void
} // end of RCU Writer scope
update_route_solo_state ();
- RouteAddedOrRemoved (false); /* EMIT SIGNAL */
update_latency_compensation ();
set_dirty();
return;
}
- Route::RemoteControlIDChange(); /* EMIT SIGNAL */
+ PresentationInfo::Change(); /* EMIT SIGNAL */
/* save the new state of the world */
save_history (_current_snapshot_name);
}
- reassign_track_numbers();
update_route_record_state ();
}
something_soloed, listeners, isolated));
}
+void
+Session::get_stripables (StripableList& sl) const
+{
+ boost::shared_ptr<RouteList> r = routes.reader ();
+ sl.insert (sl.end(), r->begin(), r->end());
+
+ VCAList v = _vca_manager->vcas ();
+ sl.insert (sl.end(), v.begin(), v.end());
+}
+
boost::shared_ptr<RouteList>
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 ();
}
boost::shared_ptr<Route>
-Session::route_by_name (string name)
+Session::route_by_name (string name) const
{
boost::shared_ptr<RouteList> r = routes.reader ();
}
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 ();
}
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 ();
}
boost::shared_ptr<Route>
-Session::route_by_remote_id (uint32_t id)
+Session::get_remote_nth_route (PresentationInfo::order_t n) const
{
- boost::shared_ptr<RouteList> r = routes.reader ();
+ return boost::dynamic_pointer_cast<Route> (get_remote_nth_stripable (n, PresentationInfo::Route));
+}
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ((*i)->remote_control_id() == id) {
- return *i;
+boost::shared_ptr<Stripable>
+Session::get_nth_stripable (PresentationInfo::order_t n) const
+{
+ StripableList sl;
+
+ get_stripables (sl);
+
+ for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
+ if ((*s)->presentation_info().order() == n) {
+ return *s;
}
}
- return boost::shared_ptr<Route> ((Route*) 0);
-}
+ /* there is no nth stripable */
+ return boost::shared_ptr<Stripable>();
+}
boost::shared_ptr<Stripable>
-Session::stripable_by_remote_id (uint32_t id)
+Session::get_remote_nth_stripable (PresentationInfo::order_t n, PresentationInfo::Flag flags) const
{
- boost::shared_ptr<RouteList> r = routes.reader ();
+ StripableList sl;
+ PresentationInfo::order_t match_cnt = 0;
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ((*i)->remote_control_id() == id) {
- return *i;
+ get_stripables (sl);
+ sl.sort (Stripable::PresentationOrderSorter());
+
+ for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
+ if ((*s)->presentation_info().flag_match (flags)) {
+ if (match_cnt++ == n) {
+ return *s;
+ }
}
}
- return boost::shared_ptr<Route> ((Route*) 0);
+ /* there is no nth stripable that matches the given flags */
+ return boost::shared_ptr<Stripable>();
}
-
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 ();
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().order_set() && a->presentation_info().order_set()) {
+ /* b is not ordered, a is; a comes before b */
+ return true;
+ } else {
+ return a->presentation_info().order() < b->presentation_info().order();
+ }
+ }
+};
void
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);
// trigger GUI re-layout
config.ParameterChanged("track-name-number");
}
+
+#ifndef NDEBUG
+ if (DEBUG_ENABLED(DEBUG::OrderKeys)) {
+ boost::shared_ptr<RouteList> rl = routes.reader ();
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 numbered %2\n", (*i)->name(), (*i)->track_number()));
+ }
+ }
+#endif /* NDEBUG */
+
}
void
if (b->is_monitor()) {
return false;
}
- return a->order_key () < b->order_key ();
+ return a->presentation_info().order() < b->presentation_info().order();
}
bool
the session's saved solo state). So just explicitly turn
them all off.
*/
- set_controls (route_list_to_control_list (get_routes(), &Route::solo_control), 0.0, Controllable::NoGroup);
+ set_controls (route_list_to_control_list (get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
}
}
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;
}
- switch (Config->get_remote_model()) {
- case MixerOrdered:
- Route::RemoteControlIDChange (); /* EMIT SIGNAL */
- break;
- default:
- break;
- }
+ PresentationInfo::Change (); /* EMIT SIGNAL */
+ reassign_track_numbers();
#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);
+ /* 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 */
-
- DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n");
-}
-
bool
Session::operation_in_progress (GQuark op) const
{