move speed quietning code into Delivery, where it belongs.
[ardour.git] / libs / ardour / session.cc
index 4b02d8ed7e6b127b319c0ae5e459369ff75f594e..43b5790228b8324d31e09835c3d46010ed579bee 100644 (file)
@@ -46,6 +46,7 @@
 #include "pbd/search_path.h"
 #include "pbd/stacktrace.h"
 #include "pbd/stl_delete.h"
+#include "pbd/replace_all.h"
 #include "pbd/unwind.h"
 
 #include "ardour/amp.h"
 #include "ardour/control_protocol_manager.h"
 #include "ardour/data_type.h"
 #include "ardour/debug.h"
+#include "ardour/directory_names.h"
+#ifdef USE_TRACKS_CODE_FEATURES
+#include "ardour/engine_state_controller.h"
+#endif
 #include "ardour/filename_extensions.h"
 #include "ardour/graph.h"
 #include "ardour/midiport_manager.h"
@@ -77,6 +82,7 @@
 #include "ardour/plugin.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/process_thread.h"
+#include "ardour/profile.h"
 #include "ardour/rc_configuration.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/region.h"
@@ -91,7 +97,9 @@
 #include "ardour/smf_source.h"
 #include "ardour/source_factory.h"
 #include "ardour/speakers.h"
+#include "ardour/tempo.h"
 #include "ardour/track.h"
+#include "ardour/user_bundle.h"
 #include "ardour/utils.h"
 
 #include "midi++/port.h"
 
 #include "i18n.h"
 
+#include <glibmm/checksum.h>
+
 namespace ARDOUR {
 class MidiSource;
 class Processor;
@@ -110,6 +120,7 @@ using namespace ARDOUR;
 using namespace PBD;
 
 bool Session::_disable_all_loaded_plugins = false;
+bool Session::_bypass_all_loaded_plugins = false;
 
 PBD::Signal1<int,uint32_t> Session::AudioEngineSetupRequired;
 PBD::Signal1<void,std::string> Session::Dialog;
@@ -127,10 +138,17 @@ PBD::Signal0<void> Session::FeedbackDetected;
 PBD::Signal0<void> Session::SuccessfulGraphSort;
 PBD::Signal2<void,std::string,std::string> Session::VersionMismatch;
 
-const framecnt_t Session::bounce_chunk_size = 65536;
+const framecnt_t Session::bounce_chunk_size = 8192;
 static void clean_up_session_event (SessionEvent* ev) { delete ev; }
 const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event);
 
+// seconds should be added after the region exceeds end marker
+#ifdef USE_TRACKS_CODE_FEATURES
+const uint32_t Session::session_end_shift = 5;
+#else
+const uint32_t Session::session_end_shift = 0;
+#endif
+
 /** @param snapshot_name Snapshot name, without .ardour suffix */
 Session::Session (AudioEngine &eng,
                   const string& fullpath,
@@ -170,11 +188,14 @@ Session::Session (AudioEngine &eng,
        , _writable (false)
        , _was_seamless (Config->get_seamless_loop ())
        , _under_nsm_control (false)
+       , _xrun_count (0)
        , delta_accumulator_cnt (0)
        , average_slave_delta (1800) // !!! why 1800 ???
        , average_dir (0)
        , have_first_delta_accumulator (false)
        , _slave_state (Stopped)
+       , _mtc_active (false)
+       , _ltc_active (false)
        , post_export_sync (false)
        , post_export_position (0)
        , _exporting (false)
@@ -209,6 +230,9 @@ Session::Session (AudioEngine &eng,
        ,  cumulative_rf_motion (0)
        , rf_scale (1.0)
        , _locations (new Locations (*this))
+       , _ignore_skips_updates (false)
+       , _rt_thread_active (false)
+       , _rt_emit_pending (false)
        , step_speed (0)
        , outbound_mtc_timecode_frame (0)
        , next_quarter_frame_to_send (-1)
@@ -236,6 +260,8 @@ Session::Session (AudioEngine &eng,
        , _all_route_group (new RouteGroup (*this, "all"))
        , routes (new RouteList)
        , _adding_routes_in_progress (false)
+       , _reconnecting_routes_in_progress (false)
+       , _route_deletion_in_progress (false)
        , destructive_index (0)
        , _track_number_decimals(1)
        , solo_update_disabled (false)
@@ -256,15 +282,18 @@ Session::Session (AudioEngine &eng,
        , click_emphasis_length (0)
        , _clicks_cleared (0)
        , _play_range (false)
+       , _range_selection (-1,-1)
+       , _object_selection (-1,-1)
        , main_outs (0)
        , first_file_data_format_reset (true)
        , first_file_header_format_reset (true)
        , have_looped (false)
        , _have_rec_enabled_track (false)
+    , _have_rec_disabled_track (true)
        , _step_editors (0)
        , _suspend_timecode_transmission (0)
        ,  _speakers (new Speakers)
-       , _order_hint (0)
+       , _order_hint (-1)
        , ignore_route_processor_changes (false)
        , _scene_changer (0)
        , _midi_ports (0)
@@ -272,17 +301,26 @@ Session::Session (AudioEngine &eng,
 {
        uint32_t sr = 0;
 
+       pthread_mutex_init (&_rt_emit_mutex, 0);
+       pthread_cond_init (&_rt_emit_cond, 0);
+
        pre_engine_init (fullpath);
        
        if (_is_new) {
+
+               Stateful::loading_state_version = CURRENT_SESSION_FILE_VERSION;
+
+#ifdef USE_TRACKS_CODE_FEATURES                
+               sr = EngineStateController::instance()->get_current_sample_rate();
+#endif
                if (ensure_engine (sr)) {
                        destroy ();
-                       throw failed_constructor ();
+                       throw SessionException (_("Cannot connect to audio/midi engine"));
                }
 
                if (create (mix_template, bus_profile)) {
                        destroy ();
-                       throw failed_constructor ();
+                       throw SessionException (_("Session initialization failed"));
                }
 
                /* if a mix template was provided, then ::create() will
@@ -296,8 +334,11 @@ Session::Session (AudioEngine &eng,
                 * of a template.
                 */
 
-               if (!mix_template.empty() && load_state (_current_snapshot_name)) {
-                       throw failed_constructor ();
+               if (!mix_template.empty()) { 
+                       if (load_state (_current_snapshot_name)) {
+                               throw SessionException (_("Failed to load template/snapshot state"));
+                       }
+                       store_recent_templates (mix_template);
                }
 
                /* load default session properties - if any */
@@ -306,7 +347,7 @@ Session::Session (AudioEngine &eng,
        } else {
 
                if (load_state (_current_snapshot_name)) {
-                       throw failed_constructor ();
+                       throw SessionException (_("Failed to load state"));
                }
        
                /* try to get sample rate from XML state so that we
@@ -323,13 +364,13 @@ Session::Session (AudioEngine &eng,
 
                if (ensure_engine (sr)) {
                        destroy ();
-                       throw failed_constructor ();
+                       throw SessionException (_("Cannot connect to audio/midi engine"));
                }
        }
 
        if (post_engine_init ()) {
                destroy ();
-               throw failed_constructor ();
+               throw SessionException (_("Cannot configure audio/midi engine with session parameters"));
        }
 
        store_recent_sessions (_name, _path);
@@ -348,7 +389,7 @@ Session::Session (AudioEngine &eng,
        StartTimeChanged.connect_same_thread (*this, boost::bind (&Session::start_time_changed, this, _1));
        EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1));
 
-       _is_new = false;
+       emit_thread_start ();
 
        /* hook us up to the engine since we are now completely constructed */
 
@@ -357,8 +398,53 @@ Session::Session (AudioEngine &eng,
        _engine.set_session (this);
        _engine.reset_timebase ();
 
-       BootMessage (_("Session loading complete"));
+#ifdef USE_TRACKS_CODE_FEATURES
+       
+       EngineStateController::instance()->set_session(this);
+       
+       if (_is_new ) {
+               if ( ARDOUR::Profile->get_trx () ) {
+
+                       /* Waves Tracks: fill session with tracks basing on the amount of inputs.
+                        * each available input must have corresponding track when session starts.
+                        */
+                       
+                       uint32_t how_many (0);
+                       
+                       std::vector<std::string> inputs;
+                       EngineStateController::instance()->get_physical_audio_inputs(inputs);
+                       
+                       how_many = inputs.size();
+                       
+                       list<boost::shared_ptr<AudioTrack> > tracks;
+                       
+                       // Track names after driver 
+                       if (Config->get_tracks_auto_naming() == NameAfterDriver) {
+                               string track_name = "";
+                               for (std::vector<string>::size_type i = 0; i < inputs.size(); ++i) {
+                                       string track_name;
+                                       track_name = inputs[i];
+                                       replace_all (track_name, "system:capture", "");
+                                       
+                                       list<boost::shared_ptr<AudioTrack> > single_track = new_audio_track (1, 1, Normal, 0, 1, track_name);
+                                       tracks.insert(tracks.begin(), single_track.front());
+                               }   
+                       } else { // Default track names
+                               tracks = new_audio_track (1, 1, Normal, 0, how_many, string());
+                       }
+                       
+                       if (tracks.size() != how_many) {
+                               destroy ();
+                               throw failed_constructor ();
+                       }
+               }
+       }
+#endif
+       
+       _is_new = false;
+       session_loaded ();
 
+       BootMessage (_("Session loading complete"));
 }
 
 Session::~Session ()
@@ -441,6 +527,10 @@ Session::immediately_post_engine ()
                return -1;
        }
 
+       /* TODO, connect in different thread. (PortRegisteredOrUnregistered may be in RT context)
+        * can we do that? */
+        _engine.PortRegisteredOrUnregistered.connect_same_thread (*this, boost::bind (&Session::setup_bundles, this));
+
        return 0;
 }
 
@@ -463,6 +553,10 @@ Session::destroy ()
 
        _engine.remove_session ();
 
+#ifdef USE_TRACKS_CODE_FEATURES
+       EngineStateController::instance()->remove_session();
+#endif
+
        /* deregister all ports - there will be no process or any other
         * callbacks from the engine any more.
         */
@@ -563,6 +657,11 @@ Session::destroy ()
        /* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
        playlists.reset ();
 
+       emit_thread_terminate ();
+
+       pthread_cond_destroy (&_rt_emit_cond);
+       pthread_mutex_destroy (&_rt_emit_mutex);
+
        delete _scene_changer; _scene_changer = 0;
        delete midi_control_ui; midi_control_ui = 0;
 
@@ -570,6 +669,8 @@ Session::destroy ()
        delete _midi_ports; _midi_ports = 0;
        delete _locations; _locations = 0;
 
+       delete _tempo_map;
+       
        DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
 
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
@@ -684,6 +785,19 @@ Session::setup_click_state (const XMLNode* node)
 void
 Session::setup_bundles ()
 {
+
+       {
+               RCUWriter<BundleList> writer (_bundles);
+               boost::shared_ptr<BundleList> b = writer.get_copy ();
+               for (BundleList::iterator i = b->begin(); i != b->end();) {
+                       if (boost::dynamic_pointer_cast<UserBundle>(*i)) {
+                               ++i;
+                               continue;
+                       }
+                       i = b->erase(i);
+               }
+       }
+
        vector<string> inputs[DataType::num_types];
        vector<string> outputs[DataType::num_types];
        for (uint32_t i = 0; i < DataType::num_types; ++i) {
@@ -702,14 +816,19 @@ Session::setup_bundles ()
        /* mono output bundles */
 
        for (uint32_t np = 0; np < outputs[DataType::AUDIO].size(); ++np) {
-               char buf[32];
-               snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
+               char buf[64];
+               std::string pn = _engine.get_pretty_name_by_name (outputs[DataType::AUDIO][np]);
+               if (!pn.empty()) {
+                       snprintf (buf, sizeof (buf), _("out %s"), pn.c_str());
+               } else {
+                       snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
+               }
 
                boost::shared_ptr<Bundle> c (new Bundle (buf, true));
                c->add_channel (_("mono"), DataType::AUDIO);
                c->set_port (0, outputs[DataType::AUDIO][np]);
 
-               add_bundle (c);
+               add_bundle (c, false);
        }
 
        /* stereo output bundles */
@@ -724,21 +843,26 @@ Session::setup_bundles ()
                        c->add_channel (_("R"), DataType::AUDIO);
                        c->set_port (1, outputs[DataType::AUDIO][np + 1]);
 
-                       add_bundle (c);
+                       add_bundle (c, false);
                }
        }
 
        /* mono input bundles */
 
        for (uint32_t np = 0; np < inputs[DataType::AUDIO].size(); ++np) {
-               char buf[32];
-               snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
+               char buf[64];
+               std::string pn = _engine.get_pretty_name_by_name (inputs[DataType::AUDIO][np]);
+               if (!pn.empty()) {
+                       snprintf (buf, sizeof (buf), _("in %s"), pn.c_str());
+               } else {
+                       snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
+               }
 
                boost::shared_ptr<Bundle> c (new Bundle (buf, false));
                c->add_channel (_("mono"), DataType::AUDIO);
                c->set_port (0, inputs[DataType::AUDIO][np]);
 
-               add_bundle (c);
+               add_bundle (c, false);
        }
 
        /* stereo input bundles */
@@ -754,7 +878,7 @@ Session::setup_bundles ()
                        c->add_channel (_("R"), DataType::AUDIO);
                        c->set_port (1, inputs[DataType::AUDIO][np + 1]);
 
-                       add_bundle (c);
+                       add_bundle (c, false);
                }
        }
 
@@ -762,26 +886,36 @@ Session::setup_bundles ()
 
        for (uint32_t np = 0; np < inputs[DataType::MIDI].size(); ++np) {
                string n = inputs[DataType::MIDI][np];
-               boost::erase_first (n, X_("alsa_pcm:"));
-
+               std::string pn = _engine.get_pretty_name_by_name (n);
+               if (!pn.empty()) {
+                       n = pn;
+               } else {
+                       boost::erase_first (n, X_("alsa_pcm:"));
+               }
                boost::shared_ptr<Bundle> c (new Bundle (n, false));
                c->add_channel ("", DataType::MIDI);
                c->set_port (0, inputs[DataType::MIDI][np]);
-               add_bundle (c);
+               add_bundle (c, false);
        }
 
        /* MIDI output bundles */
 
        for (uint32_t np = 0; np < outputs[DataType::MIDI].size(); ++np) {
                string n = outputs[DataType::MIDI][np];
-               boost::erase_first (n, X_("alsa_pcm:"));
-
+               std::string pn = _engine.get_pretty_name_by_name (n);
+               if (!pn.empty()) {
+                       n = pn;
+               } else {
+                       boost::erase_first (n, X_("alsa_pcm:"));
+               }
                boost::shared_ptr<Bundle> c (new Bundle (n, true));
                c->add_channel ("", DataType::MIDI);
                c->set_port (0, outputs[DataType::MIDI][np]);
-               add_bundle (c);
+               add_bundle (c, false);
        }
 
+       // we trust the backend to only calls us if there's a change
+       BundleAddedOrRemoved (); /* EMIT SIGNAL */
 }
 
 void
@@ -790,7 +924,13 @@ Session::auto_connect_master_bus ()
        if (!_master_out || !Config->get_auto_connect_standard_busses() || _monitor_out) {
                return;
        }
-               
+       
+       // Waves Tracks: Do not connect master bas for Tracks if AutoConnectMaster option is not set
+       // In this case it means "Multi Out" output mode
+       if (ARDOUR::Profile->get_trx() && !(Config->get_output_auto_connect() & AutoConnectMaster) ) {
+               return;
+       }
+
        /* if requested auto-connect the outputs to the first N physical ports.
         */
        
@@ -821,7 +961,7 @@ Session::auto_connect_master_bus ()
 void
 Session::remove_monitor_section ()
 {
-       if (!_monitor_out) {
+       if (!_monitor_out || Profile->get_trx()) {
                return;
        }
 
@@ -875,7 +1015,7 @@ Session::add_monitor_section ()
 {
        RouteList rl;
 
-       if (_monitor_out || !_master_out) {
+       if (_monitor_out || !_master_out || Profile->get_trx()) {
                return;
        }
 
@@ -888,10 +1028,13 @@ Session::add_monitor_section ()
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
        // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
 #endif
-       {
+       try {
                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                r->input()->ensure_io (_master_out->output()->n_ports(), false, this);
                r->output()->ensure_io (_master_out->output()->n_ports(), false, this);
+       } catch (...) {
+               error << _("Cannot create monitor section. 'Monitor' Port name is not unique.") << endmsg;
+               return;
        }
 
        rl.push_back (r);
@@ -1018,6 +1161,121 @@ Session::add_monitor_section ()
        }
 }
 
+void
+Session::reset_monitor_section ()
+{
+       /* Process lock should be held by the caller.*/
+
+       if (!_monitor_out || Profile->get_trx()) {
+               return;
+       }
+
+       uint32_t limit = _master_out->n_outputs().n_audio();
+
+       /* connect the inputs to the master bus outputs. this
+        * represents a separate data feed from the internal sends from
+        * each route. as of jan 2011, it allows the monitor section to
+        * conditionally ignore either the internal sends or the normal
+        * input feed, but we should really find a better way to do
+        * this, i think.
+        */
+
+       _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);
+
+       for (uint32_t n = 0; n < limit; ++n) {
+               boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
+               boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n);
+
+               if (o) {
+                       string connect_to = o->name();
+                       if (_monitor_out->input()->connect (p, connect_to, this)) {
+                               error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to)
+                                     << endmsg;
+                               break;
+                       }
+               }
+       }
+
+       /* connect monitor section to physical outs
+        */
+
+       if (Config->get_auto_connect_standard_busses()) {
+
+               if (!Config->get_monitor_bus_preferred_bundle().empty()) {
+
+                       boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
+
+                       if (b) {
+                               _monitor_out->output()->connect_ports_to_bundle (b, true, this);
+                       } else {
+                               warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
+                                                          Config->get_monitor_bus_preferred_bundle())
+                                       << endmsg;
+                       }
+
+               } else {
+
+                       /* Monitor bus is audio only */
+
+                       vector<string> outputs[DataType::num_types];
+
+                       for (uint32_t i = 0; i < DataType::num_types; ++i) {
+                               _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
+                       }
+
+                       uint32_t mod = outputs[DataType::AUDIO].size();
+                       uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
+
+                       if (mod != 0) {
+
+                               for (uint32_t n = 0; n < limit; ++n) {
+
+                                       boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
+                                       string connect_to;
+                                       if (outputs[DataType::AUDIO].size() > (n % mod)) {
+                                               connect_to = outputs[DataType::AUDIO][n % mod];
+                                       }
+
+                                       if (!connect_to.empty()) {
+                                               if (_monitor_out->output()->connect (p, connect_to, this)) {
+                                                       error << string_compose (
+                                                               _("cannot connect control output %1 to %2"),
+                                                               n, connect_to)
+                                                             << endmsg;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* Connect tracks to monitor section. Note that in an
+          existing session, the internal sends will already exist, but we want the
+          routes to notice that they connect to the control out specifically.
+       */
+
+
+       boost::shared_ptr<RouteList> rls = routes.reader ();
+
+       PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+
+       for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) {
+
+               if ((*x)->is_monitor()) {
+                       /* relax */
+               } else if ((*x)->is_master()) {
+                       /* relax */
+               } else {
+                       (*x)->enable_monitor_send ();
+               }
+       }
+}
+
 void
 Session::hookup_io ()
 {
@@ -1175,10 +1433,10 @@ Session::auto_loop_changed (Location* location)
        framepos_t dcp;
        framecnt_t dcl;
        auto_loop_declick_range (location, dcp, dcl);
-       replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl);
 
        if (transport_rolling() && play_loop) {
 
+               replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl);
 
                // if (_transport_frame > location->end()) {
 
@@ -1202,9 +1460,26 @@ Session::auto_loop_changed (Location* location)
                        }
 
                }
+       } else {
+               clear_events (SessionEvent::AutoLoopDeclick);
+               clear_events (SessionEvent::AutoLoop);
+       }
+
+       /* possibly move playhead if not rolling; if we are rolling we'll move
+          to the loop start on stop if that is appropriate.
+        */
+
+       framepos_t pos;
+
+       if (!transport_rolling() && select_playhead_priority_target (pos)) {
+               if (pos == location->start()) {
+                       request_locate (pos);
+               }
        }
 
+       
        last_loopend = location->end();
+       set_dirty ();
 }
 
 void
@@ -1297,9 +1572,21 @@ Session::set_auto_loop_location (Location* location)
        location->StartChanged.connect_same_thread (loop_connections, boost::bind (&Session::auto_loop_changed, this, location));
        location->EndChanged.connect_same_thread (loop_connections, boost::bind (&Session::auto_loop_changed, this, location));
        location->Changed.connect_same_thread (loop_connections, boost::bind (&Session::auto_loop_changed, this, location));
+       location->FlagsChanged.connect_same_thread (loop_connections, boost::bind (&Session::auto_loop_changed, this, location));
 
        location->set_auto_loop (true, this);
 
+       if (Config->get_loop_is_mode() && play_loop && Config->get_seamless_loop()) {
+               // set all tracks to use internal looping
+               boost::shared_ptr<RouteList> rl = routes.reader ();
+               for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                       boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                       if (tr && !tr->hidden()) {
+                               tr->set_loop (location);
+                       }
+               }
+       }
+    
        /* take care of our stuff first */
 
        auto_loop_changed (location);
@@ -1309,33 +1596,35 @@ Session::set_auto_loop_location (Location* location)
        auto_loop_location_changed (location);
 }
 
+void
+Session::update_marks (Location*)
+{
+       set_dirty ();
+}
+
 void
 Session::update_skips (Location* loc, bool consolidate)
 {
-        Locations::LocationList skips;
+       if (_ignore_skips_updates) {
+               return;
+       }
+       
+       Locations::LocationList skips;
 
         if (consolidate) {
-
-                skips = consolidate_skips (loc);
-
-        } else {
-                Locations::LocationList all_locations = _locations->list ();
-                
-                for (Locations::LocationList::iterator l = all_locations.begin(); l != all_locations.end(); ++l) {
-                        if ((*l)->is_skip ()) {
-                                skips.push_back (*l);
-                        }
-                }
+               PBD::Unwinder<bool> uw (_ignore_skips_updates, true);
+               consolidate_skips (loc);
         }
 
-        sync_locations_to_skips (skips);
+       sync_locations_to_skips ();
+        
+       set_dirty ();
 }
 
-Locations::LocationList
+void
 Session::consolidate_skips (Location* loc)
 {
         Locations::LocationList all_locations = _locations->list ();
-        Locations::LocationList skips;
 
         for (Locations::LocationList::iterator l = all_locations.begin(); l != all_locations.end(); ) {
 
@@ -1366,35 +1655,40 @@ Session::consolidate_skips (Location* loc)
                         break;
 
                 case Evoral::OverlapNone:
-                        skips.push_back (*l);
                         ++l;
                         break;
                 }
         }
+}
 
-        /* add the new one, which now covers the maximal appropriate range based on overlaps with existing skips */
-
-        skips.push_back (loc);
-
-        return skips;
+void
+Session::sync_locations_to_skips ()
+{
+       /* This happens asynchronously (in the audioengine thread). After the clear is done, we will call
+        * Session::_sync_locations_to_skips() from the audioengine thread.
+        */
+       clear_events (SessionEvent::Skip, boost::bind (&Session::_sync_locations_to_skips, this));
 }
 
 void
-Session::sync_locations_to_skips (const Locations::LocationList& locations)
+Session::_sync_locations_to_skips ()
 {
-       clear_events (SessionEvent::Skip);
+       /* called as a callback after existing Skip events have been cleared from a realtime audioengine thread */
 
-       for (Locations::LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
-                
+       Locations::LocationList const & locs (_locations->list());
+
+       for (Locations::LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
+               
                Location* location = *i;
-                
-               if (location->is_skipping()) {
+               
+               if (location->is_skip() && location->is_skipping()) {
                        SessionEvent* ev = new SessionEvent (SessionEvent::Skip, SessionEvent::Add, location->start(), location->end(), 1.0);
                        queue_event (ev);
                }
        }
 }
 
+
 void
 Session::location_added (Location *location)
 {
@@ -1413,17 +1707,26 @@ Session::location_added (Location *location)
                 _session_range_location = location;
         }
 
+        if (location->is_mark()) {
+                /* listen for per-location signals that require us to do any * global updates for marks */
+
+                location->StartChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+                location->EndChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+                location->Changed.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+                location->FlagsChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+        }
+
         if (location->is_skip()) {
                 /* listen for per-location signals that require us to update skip-locate events */
 
-                location->StartChanged.connect_same_thread (skip_connections, boost::bind (&Session::update_skips, this, location, true));
-                location->EndChanged.connect_same_thread (skip_connections, boost::bind (&Session::update_skips, this, location, true));
-                location->Changed.connect_same_thread (skip_connections, boost::bind (&Session::update_skips, this, location, true));
-                location->FlagsChanged.connect_same_thread (skip_connections, boost::bind (&Session::update_skips, this, location, false));
+                location->StartChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_skips, this, location, true));
+                location->EndChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_skips, this, location, true));
+                location->Changed.connect_same_thread (skip_update_connections, boost::bind (&Session::update_skips, this, location, true));
+                location->FlagsChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_skips, this, location, false));
 
                 update_skips (location, true);
         }
-
+        
        set_dirty ();
 }
 
@@ -1431,7 +1734,8 @@ void
 Session::location_removed (Location *location)
 {
         if (location->is_auto_loop()) {
-                set_auto_loop_location (0);
+               set_auto_loop_location (0);
+               set_track_loop (false);
         }
         
         if (location->is_auto_punch()) {
@@ -1465,10 +1769,15 @@ Session::_locations_changed (const Locations::LocationList& locations)
            We might be re-adding a location here but it doesn't actually matter
            for all the locations that the Session takes an interest in.
         */
-
-       for (Locations::LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
-                location_added (*i);
-        }
+       
+       {
+               PBD::Unwinder<bool> protect_ignore_skip_updates (_ignore_skips_updates, true);
+               for (Locations::LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
+                       location_added (*i);
+               }
+       }
+       
+       update_skips (NULL, false);
 }
 
 void
@@ -1559,6 +1868,11 @@ Session::maybe_enable_record ()
 
        save_state ("", true);
 
+        if (Config->get_loop_is_mode()) {
+                /* makes no sense to use loop play as mode when recording */
+                request_play_loop (false);
+        }
+        
        if (_transport_speed) {
                if (!config.get_punch_in()) {
                        enable_record ();
@@ -1646,7 +1960,8 @@ Session::set_frame_rate (framecnt_t frames_per_second)
        sync_time_vars();
 
        clear_clicks ();
-
+       reset_write_sources (false);
+       
        // XXX we need some equivalent to this, somehow
        // SndFileSource::setup_standard_crossfades (frames_per_second);
 
@@ -1884,16 +2199,48 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
  *  and \a id do not reflect a free route name.
  */
 bool
-Session::find_route_name (string const & base, uint32_t& id, char* name, size_t name_len, bool definitely_add_number)
-{
+Session::find_route_name (string const & base, uint32_t& id, string& name, bool definitely_add_number)
+{
+       /* it is unfortunate that we need to include reserved names here that
+          refer to control surfaces. But there's no way to ensure a complete
+          lack of collisions without doing this, since the control surface
+          support may not even be active. Without adding an API to control 
+          surface support that would list their port names, we do have to
+          list them here.
+       */
+
+       char const * const reserved[] = {
+               _("Monitor"),
+               _("Master"),
+               _("Control"),
+               _("Click"),
+               _("Mackie"),
+               0
+       };
+       
+       /* the base may conflict with ports that do not belong to existing
+          routes, but hidden objects like the click track. So check port names
+          before anything else.
+       */
+       
+       for (int n = 0; reserved[n]; ++n) {
+               if (base == reserved[n]) {
+                       definitely_add_number = true;
+                       if (id < 1) {
+                               id = 1;
+                       }
+                       break;
+               }
+       }
+       
        if (!definitely_add_number && route_by_name (base) == 0) {
                /* juse use the base */
-               snprintf (name, name_len, "%s", base.c_str());
+               name = base;
                return true;
        }
 
        do {
-               snprintf (name, name_len, "%s %" PRIu32, base.c_str(), id);
+               name = string_compose ("%1 %2", base, id);
 
                if (route_by_name (name) == 0) {
                        return true;
@@ -1924,6 +2271,25 @@ Session::count_existing_track_channels (ChanCount& in, ChanCount& out)
        }
 }
 
+string
+Session::default_track_name_pattern (DataType t)
+{
+       switch (t) {
+       case DataType::AUDIO:
+               if (Profile->get_trx()) {
+                       return _("Track ");
+               } else {
+                       return _("Audio ");
+               }
+               break;
+
+       case DataType::MIDI:
+               return _("MIDI ");
+       }
+
+       return "";
+}
+
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "MIDI".
  *  @param instrument plugin info for the instrument to insert pre-fader, if any
@@ -1932,16 +2298,17 @@ 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)
 {
-       char track_name[32];
+       string track_name;
        uint32_t track_id = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<MidiTrack> > ret;
 
-       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI");
+       const string name_pattern = default_track_name_pattern (DataType::MIDI);
+       bool const use_number = (how_many != 1) || name_template.empty () || (name_template == name_pattern);
 
        while (how_many) {
-               if (!find_route_name (name_template.empty() ? _("MIDI") : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
+               if (!find_route_name (name_template.empty() ? _("MIDI") : name_template, ++track_id, track_name, use_number)) {
                        error << "cannot find name for new midi track" << endmsg;
                        goto failed;
                }
@@ -1987,6 +2354,8 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
 
                        new_routes.push_back (track);
                        ret.push_back (track);
+
+                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
@@ -2006,7 +2375,11 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
   failed:
        if (!new_routes.empty()) {
                StateProtector sp (this);
-               add_routes (new_routes, true, true, true);
+               if (Profile->get_trx()) {
+                       add_routes (new_routes, false, false, false);
+               } else {
+                       add_routes (new_routes, true, true, false);
+               }
 
                if (instrument) {
                        for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
@@ -2136,6 +2509,17 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing
                        for (uint32_t i = output_start.get(*t); i < route->n_outputs().get(*t); ++i) {
                                string port;
 
+                               /* Waves Tracks:
+                                * do not create new connections if we reached the limit of physical outputs
+                                * in Multi Out mode
+                                */
+
+                               if (!(Config->get_output_auto_connect() & AutoConnectMaster) &&
+                                   ARDOUR::Profile->get_trx () &&
+                                   existing_outputs.get(*t) == nphysical_out ) {
+                                       break;
+                               }
+
                                if ((*t) == DataType::MIDI && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
                                        port = physoutputs[(out_offset.get(*t) + i) % nphysical_out];
                                } else if ((*t) == DataType::AUDIO && (Config->get_output_auto_connect() & AutoConnectMaster)) {
@@ -2150,24 +2534,300 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing
                                             string_compose("Connect route %1 OUT to %2\n",
                                                            route->name(), port));
 
-                               if (!port.empty() && route->output()->connect (route->output()->ports().port(*t, i), port, this)) {
-                                       break;
-                               }
+                               if (!port.empty() && route->output()->connect (route->output()->ports().port(*t, i), port, this)) {
+                                       break;
+                               }
+
+                                ChanCount one_added (*t, 1);
+                                existing_outputs += one_added;
+                       }
+               }
+       }
+}
+
+#ifdef USE_TRACKS_CODE_FEATURES 
+
+static bool
+compare_routes_by_remote_id (const boost::shared_ptr<Route>& route1, const boost::shared_ptr<Route>& route2)
+{
+       return route1->remote_control_id() < route2->remote_control_id();
+}
+
+void
+Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool reconnect_inputs, bool reconnect_outputs)
+{
+       // it is not allowed to perform connection
+       if (!IO::connecting_legal) {
+               return;
+       }
+    
+       // if we are deleting routes we will call this once at the end
+       if (_route_deletion_in_progress) {
+               return;
+       }
+    
+       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
+    
+       if (withLock) {
+               lm.acquire ();
+       }
+    
+       // We need to disconnect the route's inputs and outputs first
+       // basing on autoconnect configuration
+       bool reconnectIputs = !(Config->get_input_auto_connect() & ManualConnect) && reconnect_inputs;
+       bool reconnectOutputs = !(Config->get_output_auto_connect() & ManualConnect) && reconnect_outputs;
+    
+       ChanCount existing_inputs;
+       ChanCount existing_outputs;
+       count_existing_track_channels (existing_inputs, existing_outputs);
+    
+       //ChanCount inputs = ChanCount::ZERO;
+       //ChanCount outputs = ChanCount::ZERO;
+    
+       RouteList existing_routes = *routes.reader ();
+       existing_routes.sort (compare_routes_by_remote_id);
+    
+       {
+               PBD::Unwinder<bool> protect_ignore_changes (_reconnecting_routes_in_progress, true);
+
+               vector<string> physinputs;
+               vector<string> physoutputs;
+        
+               EngineStateController::instance()->get_physical_audio_outputs(physoutputs);
+               EngineStateController::instance()->get_physical_audio_inputs(physinputs);
+                
+               uint32_t input_n = 0;
+               uint32_t output_n = 0;
+               RouteList::iterator rIter = existing_routes.begin();
+               const AutoConnectOption current_input_auto_connection (Config->get_input_auto_connect());
+               const AutoConnectOption current_output_auto_connection (Config->get_output_auto_connect());
+               for (; rIter != existing_routes.end(); ++rIter) {
+                       if (*rIter == _master_out || *rIter == _monitor_out ) {
+                               continue;
+                       }
+
+                       if (current_output_auto_connection == AutoConnectPhysical) {
+                               (*rIter)->amp()->deactivate();
+                       } else if (current_output_auto_connection == AutoConnectMaster) {
+                               (*rIter)->amp()->activate();
+                       }
+            
+                       if (reconnectIputs) {
+                               (*rIter)->input()->disconnect (this); //GZ: check this; could be heavy
+                
+                               for (uint32_t route_input_n = 0; route_input_n < (*rIter)->n_inputs().get(DataType::AUDIO); ++route_input_n) {
+                    
+                                       if (current_input_auto_connection & AutoConnectPhysical) {
+                        
+                                               if ( input_n == physinputs.size() ) {
+                                                       break;
+                                               }
+                        
+                                               string port = physinputs[input_n];
+                    
+                                               if (port.empty() ) {
+                                                       error << "Physical Input number "<< input_n << " is unavailable and cannot be connected" << endmsg;
+                                               }
+                        
+                                               //GZ: check this; could be heavy
+                                               (*rIter)->input()->connect ((*rIter)->input()->ports().port(DataType::AUDIO, route_input_n), port, this);
+                                               ++input_n;
+                                       }
+                               }
+                       }
+            
+                       if (reconnectOutputs) {
+                
+                               //normalize route ouptuts: reduce the amount outputs to be equal to the amount of inputs
+                               if (current_output_auto_connection & AutoConnectPhysical) {
+                
+                                       //GZ: check this; could be heavy
+                                       (*rIter)->output()->disconnect (this);
+                                       size_t route_inputs_count = (*rIter)->n_inputs().get(DataType::AUDIO);
+                    
+                                       //GZ: check this; could be heavy
+                                       (*rIter)->output()->ensure_io(ChanCount(DataType::AUDIO, route_inputs_count), false, this );
+               
+                               } else if (current_output_auto_connection & AutoConnectMaster){
+                    
+                                       if (!reconnect_master) {
+                                               continue;
+                                       }
+                    
+                                       //GZ: check this; could be heavy
+                                       (*rIter)->output()->disconnect (this);
+                    
+                                       if (_master_out) {
+                                               uint32_t master_inputs_count = _master_out->n_inputs().get(DataType::AUDIO);
+                                               (*rIter)->output()->ensure_io(ChanCount(DataType::AUDIO, master_inputs_count), false, this );
+                                       } else {
+                                               error << error << "Master bus is not available" << endmsg;
+                                               break;
+                                       }
+                               }
+                
+                               for (uint32_t route_output_n = 0; route_output_n < (*rIter)->n_outputs().get(DataType::AUDIO); ++route_output_n) {
+                                       if (current_output_auto_connection & AutoConnectPhysical) {
+                        
+                                               if ( output_n == physoutputs.size() ) {
+                                                       break;
+                                               }
+                        
+                                               string port = physoutputs[output_n];
+                        
+                                               if (port.empty() ) {
+                                                       error << "Physical Output number "<< output_n << " is unavailable and cannot be connected" << endmsg;
+                                               }
+                    
+                                               //GZ: check this; could be heavy
+                                               (*rIter)->output()->connect ((*rIter)->output()->ports().port(DataType::AUDIO, route_output_n), port, this);
+                                               ++output_n;
+                        
+                                       } else if (current_output_auto_connection & AutoConnectMaster) {
+                  
+                                               if ( route_output_n == _master_out->n_inputs().get(DataType::AUDIO) ) {
+                                                       break;
+                                               }
+                        
+                                               // connect to master bus
+                                               string port = _master_out->input()->ports().port(DataType::AUDIO, route_output_n)->name();
+                    
+                                               if (port.empty() ) {
+                                                       error << "MasterBus Input number "<< route_output_n << " is unavailable and cannot be connected" << endmsg;
+                                               }
+                        
+                            
+                                               //GZ: check this; could be heavy
+                                               (*rIter)->output()->connect ((*rIter)->output()->ports().port(DataType::AUDIO, route_output_n), port, this);
+                            
+                                       }
+                               }
+                       }
+            
+                       //auto_connect_route (*rIter, inputs, outputs, false, reconnectIputs);
+               }
+        
+               _master_out->output()->disconnect (this);
+               auto_connect_master_bus ();
+       }
+    
+       graph_reordered ();
+    
+       session_routes_reconnected (); /* EMIT SIGNAL */
+}
+
+void
+Session::reconnect_midi_scene_ports(bool inputs)
+{
+    if (inputs ) {
+        
+        boost::shared_ptr<MidiPort> scene_in_ptr = scene_in();
+        if (scene_in_ptr) {
+            scene_in_ptr->disconnect_all ();
+            
+            std::vector<EngineStateController::MidiPortState> midi_port_states;
+            EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
+            
+            std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+            
+            for (; state_iter != midi_port_states.end(); ++state_iter) {
+                if (state_iter->active && state_iter->available && state_iter->scene_connected) {
+                    scene_in_ptr->connect (state_iter->name);
+                }
+            }
+        }
+
+    } else {
+        
+        boost::shared_ptr<MidiPort> scene_out_ptr = scene_out();
+        
+        if (scene_out_ptr ) {
+            scene_out_ptr->disconnect_all ();
+
+            std::vector<EngineStateController::MidiPortState> midi_port_states;
+            EngineStateController::instance()->get_physical_midi_output_states (midi_port_states);
+            
+            std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+            
+            for (; state_iter != midi_port_states.end(); ++state_iter) {
+                if (state_iter->active && state_iter->available && state_iter->scene_connected) {
+                    scene_out_ptr->connect (state_iter->name);
+                }
+            }
+        }
+    }
+}
+
+void
+Session::reconnect_mtc_ports ()
+{
+       boost::shared_ptr<MidiPort> mtc_in_ptr = _midi_ports->mtc_input_port();
 
-                                ChanCount one_added (*t, 1);
-                                existing_outputs += one_added;
-                       }
+       if (!mtc_in_ptr) {
+               return;
+       }
+
+       mtc_in_ptr->disconnect_all ();
+       
+       std::vector<EngineStateController::MidiPortState> midi_port_states;
+       EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
+       
+       std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+       
+       for (; state_iter != midi_port_states.end(); ++state_iter) {
+               if (state_iter->available && state_iter->mtc_in) {
+                       mtc_in_ptr->connect (state_iter->name);
                }
        }
+       
+       if (!_midi_ports->mtc_input_port ()->connected () &&
+           config.get_external_sync () &&
+           (Config->get_sync_source () == MTC) ) {
+               config.set_external_sync (false);
+       }
+       
+       if ( ARDOUR::Profile->get_trx () ) {
+               // Tracks need this signal to update timecode_source_dropdown
+               MtcOrLtcInputPortChanged (); //emit signal
+       }
 }
 
 void
-Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool reconnect_inputs, bool reconnect_outputs)
+Session::reconnect_mmc_ports(bool inputs)
 {
-        /* TRX does stuff here, ardour does not (but probably should). This is called after an engine reset (in particular).
-         */
+       if (inputs ) { // get all enabled midi input ports
+        
+               boost::shared_ptr<MidiPort> mmc_in_ptr = _midi_ports->mmc_in();
+               if (mmc_in_ptr) {
+                       mmc_in_ptr->disconnect_all ();
+                       std::vector<std::string> enabled_midi_inputs;
+                       EngineStateController::instance()->get_physical_midi_inputs (enabled_midi_inputs);
+            
+                       std::vector<std::string>::iterator port_iter = enabled_midi_inputs.begin();
+            
+                       for (; port_iter != enabled_midi_inputs.end(); ++port_iter) {
+                               mmc_in_ptr->connect (*port_iter);
+                       }
+
+               }
+       } else { // get all enabled midi output ports
+        
+               boost::shared_ptr<MidiPort> mmc_out_ptr = _midi_ports->mmc_out();
+               if (mmc_out_ptr ) {
+                       mmc_out_ptr->disconnect_all ();
+                       std::vector<std::string> enabled_midi_outputs;
+                       EngineStateController::instance()->get_physical_midi_outputs (enabled_midi_outputs);
+            
+                       std::vector<std::string>::iterator port_iter = enabled_midi_outputs.begin();
+            
+                       for (; port_iter != enabled_midi_outputs.end(); ++port_iter) {
+                               mmc_out_ptr->connect (*port_iter);
+                       }
+               }
+       }
 }
 
+#endif
 
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "Audio".
@@ -2176,16 +2836,18 @@ 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)
 {
-       char track_name[32];
+       string track_name;
        uint32_t track_id = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<AudioTrack> > ret;
 
-       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio");
-
+       const string name_pattern = default_track_name_pattern (DataType::AUDIO);
+       bool const use_number = (how_many != 1) || name_template.empty () || (name_template == name_pattern);
+       
        while (how_many) {
-               if (!find_route_name (name_template.empty() ? _("Audio") : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
+
+               if (!find_route_name (name_template.empty() ? _(name_pattern.c_str()) : name_template, ++track_id, track_name, use_number)) {
                        error << "cannot find name for new audio track" << endmsg;
                        goto failed;
                }
@@ -2199,6 +2861,20 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                goto failed;
                        }
 
+                       if (ARDOUR::Profile->get_trx ()) {
+                               // TRACKS considers it's not a USE CASE, it's
+                               // a piece of behavior of the session model:
+                               //
+                               // Gain for a newly created route depends on
+                               // the current output_auto_connect mode:
+                               //
+                               //  0 for Stereo Out mode
+                               //  0 Multi Out mode
+                               if (Config->get_output_auto_connect() & AutoConnectMaster) {
+                                       track->set_gain (dB_to_coefficient (0), 0);
+                               }
+                       }
+
                        track->use_new_diskstream();
 
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
@@ -2237,6 +2913,8 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
                        new_routes.push_back (track);
                        ret.push_back (track);
+
+                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
@@ -2256,7 +2934,11 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
   failed:
        if (!new_routes.empty()) {
                StateProtector sp (this);
-               add_routes (new_routes, true, true, true);
+               if (Profile->get_trx()) {
+                       add_routes (new_routes, false, false, false);
+               } else {
+                       add_routes (new_routes, true, true, false);
+               }
        }
 
        return ret;
@@ -2268,7 +2950,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 RouteList
 Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, string name_template)
 {
-       char bus_name[32];
+       string bus_name;
        uint32_t bus_id = 0;
        string port;
        RouteList ret;
@@ -2276,7 +2958,7 @@ 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");
        
        while (how_many) {
-               if (!find_route_name (name_template.empty () ? _("Bus") : name_template, ++bus_id, bus_name, sizeof(bus_name), use_number)) {
+               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;
                        goto failure;
                }
@@ -2321,6 +3003,8 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
 
                        ret.push_back (bus);
                        
+                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
+
                        ARDOUR::GUIIdle ();
                }
 
@@ -2342,7 +3026,11 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
   failure:
        if (!ret.empty()) {
                StateProtector sp (this);
-               add_routes (ret, false, true, true); // autoconnect outputs only
+               if (Profile->get_trx()) {
+                       add_routes (ret, false, false, false);
+               } else {
+                       add_routes (ret, false, true, true); // autoconnect // outputs only
+               }
        }
 
        return ret;
@@ -2376,7 +3064,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                node_copy.remove_property_recursively (X_("id"));
 
                try {
-                       char name[32];
+                       string name;
 
                        if (!name_base.empty()) {
 
@@ -2385,7 +3073,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                                 * numbered, via the final parameter.
                                 */
 
-                               if (!find_route_name (name_base.c_str(), ++number, name, sizeof(name), (being_added > 1))) {
+                               if (!find_route_name (name_base.c_str(), ++number, name, (being_added > 1))) {
                                        fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
                                        /*NOTREACHDE*/
                                }
@@ -2395,7 +3083,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                                string const route_name  = node_copy.property(X_("name"))->value ();
                        
                                /* generate a new name by adding a number to the end of the template name */
-                               if (!find_route_name (route_name.c_str(), ++number, name, sizeof(name), true)) {
+                               if (!find_route_name (route_name.c_str(), ++number, name, true)) {
                                        fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
                                        abort(); /*NOTREACHED*/
                                }
@@ -2441,6 +3129,8 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                        ++control_id;
 
                        ret.push_back (route);
+
+                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
@@ -2459,7 +3149,11 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
   out:
        if (!ret.empty()) {
                StateProtector sp (this);
-               add_routes (ret, true, true, true);
+               if (Profile->get_trx()) {
+                       add_routes (ret, false, false, false);
+               } else {
+                       add_routes (ret, true, true, false);
+               }
                IO::enable_connecting ();
        }
 
@@ -2490,6 +3184,8 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
        
        reassign_track_numbers();
 
+       update_route_record_state ();
+    
        RouteAdded (new_routes); /* EMIT SIGNAL */
 }
 
@@ -2500,9 +3196,9 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
         ChanCount existing_outputs;
        uint32_t order = next_control_id();
 
-       if (_order_hint != 0) {
+       if (_order_hint > -1) {
                order = _order_hint;
-               _order_hint = 0;
+               _order_hint = -1;
        }
 
         count_existing_track_channels (existing_inputs, existing_outputs);
@@ -2547,7 +3243,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                if (tr) {
                        tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
                        track_playlist_changed (boost::weak_ptr<Track> (tr));
-                       tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_have_rec_enabled_track, this));
+                       tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
 
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
                        if (mt) {
@@ -2603,7 +3299,7 @@ Session::globally_set_send_gains_to_zero (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (0.0);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO);
                }
        }
 }
@@ -2616,7 +3312,7 @@ Session::globally_set_send_gains_to_unity (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (1.0);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY);
                }
        }
 }
@@ -2681,100 +3377,128 @@ Session::add_internal_send (boost::shared_ptr<Route> dest, boost::shared_ptr<Pro
        graph_reordered ();
 }
 
+
 void
-Session::remove_route (boost::shared_ptr<Route> route)
+Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 {
-       if (route == _master_out) {
-               return;
-       }
-
-       route->set_solo (false, this);
+       PBD::Unwinder<bool> uw_flag (_route_deletion_in_progress, true);
 
-       {
+       { // RCU Writer scope
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> rs = writer.get_copy ();
+        
+        
+               for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
+            
+                       if (*iter == _master_out) {
+                               continue;
+                       }
+            
+                       (*iter)->set_solo (false, this);
+            
+                       rs->remove (*iter);
+            
+                       /* deleting the master out seems like a dumb
+                          idea, but its more of a UI policy issue
+                          than our concern.
+                       */
+            
+                       if (*iter == _master_out) {
+                               _master_out = boost::shared_ptr<Route> ();
+                       }
+            
+                       if (*iter == _monitor_out) {
+                               _monitor_out.reset ();
+                       }
 
-               rs->remove (route);
-
-               /* deleting the master out seems like a dumb
-                  idea, but its more of a UI policy issue
-                  than our concern.
-               */
-
-               if (route == _master_out) {
-                       _master_out = boost::shared_ptr<Route> ();
-               }
-
-               if (route == _monitor_out) {
-                       _monitor_out.reset ();
+                       // We need to disconnect the route's inputs and outputs
+            
+                       (*iter)->input()->disconnect (0);
+                       (*iter)->output()->disconnect (0);
+            
+                       /* if the route had internal sends sending to it, remove them */
+                       if ((*iter)->internal_return()) {
+                
+                               boost::shared_ptr<RouteList> r = routes.reader ();
+                               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                                       boost::shared_ptr<Send> s = (*i)->internal_send_for (*iter);
+                                       if (s) {
+                                               (*i)->remove_processor (s);
+                                       }
+                               }
+                       }
+            
+                       /* if the monitoring section had a pointer to this route, remove it */
+                       if (_monitor_out && !(*iter)->is_master() && !(*iter)->is_monitor()) {
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+                               (*iter)->remove_aux_or_listen (_monitor_out);
+                       }
+            
+                       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*iter);
+                       if (mt && mt->step_editing()) {
+                               if (_step_editors > 0) {
+                                       _step_editors--;
+                               }
+                       }
                }
-
+    
                /* writer goes out of scope, forces route list update */
-       }
 
+       } // end of RCU Writer scope
+    
        update_route_solo_state ();
-
-       // We need to disconnect the route's inputs and outputs
-
-       route->input()->disconnect (0);
-       route->output()->disconnect (0);
-
-       /* if the route had internal sends sending to it, remove them */
-       if (route->internal_return()) {
-
-               boost::shared_ptr<RouteList> r = routes.reader ();
-               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       boost::shared_ptr<Send> s = (*i)->internal_send_for (route);
-                       if (s) {
-                               (*i)->remove_processor (s);
-                       }
-               }
-       }
-
-       /* if the monitoring section had a pointer to this route, remove it */
-       if (_monitor_out && !route->is_master() && !route->is_monitor()) {
-               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-               PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
-               route->remove_aux_or_listen (_monitor_out);
-       }
-
-       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
-       if (mt && mt->step_editing()) {
-               if (_step_editors > 0) {
-                       _step_editors--;
-               }
-       }
-
+       RouteAddedOrRemoved (false); /* EMIT SIGNAL */
        update_latency_compensation ();
        set_dirty();
-
+    
        /* Re-sort routes to remove the graph's current references to the one that is
         * going away, then flush old references out of the graph.
+        * Wave Tracks: reconnect routes
         */
 
-       resort_routes ();
+#ifdef USE_TRACKS_CODE_FEATURES
+               reconnect_existing_routes(true, false);
+#else
+               routes.flush (); // maybe unsafe, see below.
+               resort_routes ();
+#endif
+    
        if (_process_graph) {
                _process_graph->clear_other_chain ();
        }
-
+    
        /* get rid of it from the dead wood collection in the route list manager */
-
        /* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
-
+    
        routes.flush ();
+    
+       /* try to cause everyone to drop their references
+        * and unregister ports from the backend
+        */
 
-       /* try to cause everyone to drop their references */
-
-       route->drop_references ();
-
+       for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
+               (*iter)->drop_references ();
+       }
+    
        Route::RemoteControlIDChange(); /* EMIT SIGNAL */
-
+    
        /* save the new state of the world */
-
+    
        if (save_state (_current_snapshot_name)) {
                save_history (_current_snapshot_name);
        }
+
        reassign_track_numbers();
+       update_route_record_state ();
+}
+
+void
+Session::remove_route (boost::shared_ptr<Route> route)
+{
+       boost::shared_ptr<RouteList> rl (new RouteList);
+       rl->push_back (route);
+       remove_routes (rl);
 }
 
 void
@@ -2844,6 +3568,120 @@ Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
        }
 }
 
+void
+Session::routes_solo_changed (boost::shared_ptr<RouteList> solo_change_routes)
+{
+       if (solo_update_disabled) {
+               // We know already
+               DEBUG_TRACE (DEBUG::Solo, "solo update disabled - changed ignored\n");
+               return;
+       }
+
+       if (solo_change_routes->empty() ) {
+               return;
+       }
+
+       boost::shared_ptr<RouteList> non_solo_change_routes (new RouteList);
+       boost::shared_ptr<RouteList> r = routes.reader ();
+       int32_t delta;
+
+       std::set_difference (r->begin(), r->end(),
+                            solo_change_routes->begin(), solo_change_routes->end(),
+                            std::back_inserter(*non_solo_change_routes) );
+
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("propagate solo change, delta = %1\n", delta));
+
+       solo_update_disabled = true;
+       RouteList uninvolved;
+
+       for (RouteList::iterator route = solo_change_routes->begin(); route != solo_change_routes->end(); ++route) {
+
+               if ((*route)->self_soloed() ) {
+                       delta = 1;
+               } else {
+                       delta = -1;
+               }
+
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1\n", (*route)->name()));
+
+               for (RouteList::iterator i = non_solo_change_routes->begin(); i != non_solo_change_routes->end(); ++i) {
+                       bool via_sends_only;
+                       bool in_signal_flow;
+
+                       if ((*i) == *route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ) {
+                               continue;
+                       }
+
+                       in_signal_flow = false;
+
+                       DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed from %1\n", (*i)->name()));
+
+                       if ((*i)->feeds (*route, &via_sends_only)) {
+                               DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a feed from %1\n", (*i)->name()));
+                               if (!via_sends_only) {
+                                       if (!(*route)->soloed_by_others_upstream()) {
+                                               (*i)->mod_solo_by_others_downstream (delta);
+                                       }
+                               } else {
+                                       DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a send-only feed from %1\n", (*i)->name()));
+                               }
+                               in_signal_flow = true;
+                       } else {
+                               DEBUG_TRACE (DEBUG::Solo, string_compose ("\tno feed from %1\n", (*i)->name()));
+                       }
+
+                       DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed to %1\n", (*i)->name()));
+
+                       if ((*route)->feeds (*i, &via_sends_only)) {
+                               /* propagate solo upstream only if routing other than
+                                  sends is involved, but do consider the other route
+                                  (*i) to be part of the signal flow even if only
+                                  sends are involved.
+                               */
+                               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 feeds %2 via sends only %3 sboD %4 sboU %5\n",
+                                                                         (*route)->name(),
+                                                                         (*i)->name(),
+                                                                         via_sends_only,
+                                                                         (*route)->soloed_by_others_downstream(),
+                                                                         (*route)->soloed_by_others_upstream()));
+                               if (!via_sends_only) {
+                                       if (!(*route)->soloed_by_others_downstream()) {
+                                               DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
+                                               (*i)->mod_solo_by_others_upstream (delta);
+                                       } else {
+                                               DEBUG_TRACE (DEBUG::Solo, "\talready soloed by others downstream\n");
+                                       }
+                               } else {
+                                       DEBUG_TRACE (DEBUG::Solo, string_compose ("\tfeed to %1 ignored, sends-only\n", (*i)->name()));
+                               }
+                               in_signal_flow = true;
+                       } else {
+                               DEBUG_TRACE (DEBUG::Solo, "\tno feed to\n");
+                       }
+
+                       if (!in_signal_flow) {
+                               uninvolved.push_back (*i);
+                       }
+               }
+       }
+       solo_update_disabled = false;
+       DEBUG_TRACE (DEBUG::Solo, "propagation complete\n");
+
+       update_route_solo_state ();
+
+       /* now notify that the mute state of the routes not involved in the signal
+          pathway of the just-solo-changed route may have altered.
+       */
+
+       for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1\n", (*i)->name() ));
+               (*i)->mute_changed (this);
+       }
+
+       SoloChanged (); /* EMIT SIGNAL */
+       set_dirty();
+}
+
 void
 Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_ptr<Route> wpr)
 {
@@ -2968,6 +3806,7 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
 
        for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
                DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
+               (*i)->act_on_mute ();
                (*i)->mute_changed (this);
        }
 
@@ -3278,9 +4117,11 @@ Session::maybe_update_session_range (framepos_t a, framepos_t b)
                return;
        }
 
+       framepos_t session_end_marker_shift_samples = session_end_shift * _nominal_frame_rate;
+
        if (_session_range_location == 0) {
 
-               add_session_range_location (a, b);
+               set_session_range_location (a, b + session_end_marker_shift_samples);
 
        } else {
 
@@ -3556,10 +4397,69 @@ Session::count_sources_by_origin (const string& path)
        return cnt;
 }
 
+static string
+peak_file_helper (const string& peak_path, const string& file_path, const string& file_base, bool hash) {
+       if (hash) {
+               std::string checksum = Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_SHA1, file_path + G_DIR_SEPARATOR + file_base);
+               return Glib::build_filename (peak_path, checksum + peakfile_suffix);
+       } else {
+               return Glib::build_filename (peak_path, file_base + peakfile_suffix);
+       }
+}
+
 string
-Session::peak_path (string base) const
+Session::construct_peak_filepath (const string& filepath, const bool in_session, const bool old_peak_name) const
 {
-       return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix);
+       string interchange_dir_string = string (interchange_dir_name) + G_DIR_SEPARATOR;
+
+       if (Glib::path_is_absolute (filepath)) {
+
+               /* rip the session dir from the audiofile source */
+
+               string session_path;
+               bool in_another_session = true;
+               
+               if (filepath.find (interchange_dir_string) != string::npos) {
+               
+                       session_path = Glib::path_get_dirname (filepath); /* now ends in audiofiles */
+                       session_path = Glib::path_get_dirname (session_path); /* now ends in session name */
+                       session_path = Glib::path_get_dirname (session_path); /* now ends in interchange */
+                       session_path = Glib::path_get_dirname (session_path); /* now has session path */
+
+                       /* see if it is within our session */
+
+                       for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+                               if (i->path == session_path) {
+                                       in_another_session = false;
+                                       break;
+                               }
+                       }
+               } else {
+                       in_another_session = false;
+               }
+               
+
+               if (in_another_session) {
+                       SessionDirectory sd (session_path);
+                       return peak_file_helper (sd.peak_path(), "", Glib::path_get_basename (filepath), !old_peak_name);
+               }
+       }
+
+       /* 1) if file belongs to this session
+        * it may be a relative path (interchange/...)
+        * or just basename (session_state, remove source)
+        * -> just use the basename
+        */
+       std::string filename = Glib::path_get_basename (filepath);
+       std::string path;
+
+       /* 2) if the file is outside our session dir:
+        * (imported but not copied) add the path for check-summming */
+       if (!in_session) {
+               path = Glib::path_get_dirname (filepath);
+       }
+       
+       return peak_file_helper (_session_dir->peak_path(), path, Glib::path_get_basename (filepath), !old_peak_name);
 }
 
 string
@@ -3622,8 +4522,19 @@ Session::new_audio_source_path_for_embedded (const std::string& path)
        return newpath;
 }
 
+/** Return true if there are no audio file sources that use @param name as 
+ * the filename component of their path. 
+ *
+ * Return false otherwise.
+ *
+ * This method MUST ONLY be used to check in-session, mono files since it 
+ * hard-codes the channel of the audio file source we are looking for as zero.
+ * 
+ * If/when Ardour supports native files in non-mono formats, the logic here
+ * will need to be revisited.
+ */
 bool
-Session::audio_source_name_is_unique (const string& name, uint32_t chan)
+Session::audio_source_name_is_unique (const string& name)
 {
        std::vector<string> sdirs = source_search_path (DataType::AUDIO);
        vector<space_and_path>::iterator i;
@@ -3656,7 +4567,7 @@ Session::audio_source_name_is_unique (const string& name, uint32_t chan)
                
                string possible_path = Glib::build_filename (spath, name);
 
-               if (audio_source_by_path_and_channel (possible_path, chan)) {
+               if (audio_source_by_path_and_channel (possible_path, 0)) {
                        existing++;
                        break;
                }
@@ -3671,7 +4582,7 @@ Session::format_audio_source_name (const string& legalized_base, uint32_t nchan,
        ostringstream sstr;
        const string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
        
-       if (destructive) {
+       if (Profile->get_trx() && destructive) {
                sstr << 'T';
                sstr << setfill ('0') << setw (4) << cnt;
                sstr << legalized_base;
@@ -3724,7 +4635,7 @@ Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t cha
 
                possible_name = format_audio_source_name (legalized, nchan, chan, destructive, take_required, cnt, some_related_source_name_exists);
                
-               if (audio_source_name_is_unique (possible_name, chan)) {
+               if (audio_source_name_is_unique (possible_name)) {
                        break;
                }
                
@@ -3828,7 +4739,7 @@ Session::create_audio_source_for_session (size_t n_chans, string const & base, u
 
        if (!path.empty()) {
                return boost::dynamic_pointer_cast<AudioFileSource> (
-                       SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
+                       SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate(), true, true));
        } else {
                throw failed_constructor ();
        }
@@ -4001,7 +4912,7 @@ Session::graph_reordered ()
           from a set_state() call or creating new tracks. Ditto for deletion.
        */
 
-       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress) {
+       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress || _reconnecting_routes_in_progress || _route_deletion_in_progress) {
                return;
        }
 
@@ -4071,7 +4982,7 @@ Session::available_capture_duration ()
 }
 
 void
-Session::add_bundle (boost::shared_ptr<Bundle> bundle)
+Session::add_bundle (boost::shared_ptr<Bundle> bundle, bool emit_signal)
 {
        {
                RCUWriter<BundleList> writer (_bundles);
@@ -4079,7 +4990,9 @@ Session::add_bundle (boost::shared_ptr<Bundle> bundle)
                b->push_back (bundle);
        }
 
-       BundleAdded (bundle); /* EMIT SIGNAL */
+       if (emit_signal) {
+               BundleAddedOrRemoved (); /* EMIT SIGNAL */
+       }
 
        set_dirty();
 }
@@ -4101,7 +5014,7 @@ Session::remove_bundle (boost::shared_ptr<Bundle> bundle)
        }
 
        if (removed) {
-                BundleRemoved (bundle); /* EMIT SIGNAL */
+                BundleAddedOrRemoved (); /* EMIT SIGNAL */
        }
 
        set_dirty();
@@ -4322,12 +5235,12 @@ void
 Session::reset_native_file_format ()
 {
        boost::shared_ptr<RouteList> rl = routes.reader ();
+
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
                if (tr) {
                        /* don't save state as we do this, there's no point
                         */
-
                        _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
                        tr->reset_write_sources (false);
                        _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
@@ -4485,8 +5398,13 @@ Session::write_one_track (Track& track, framepos_t start, framepos_t end,
 
        for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
                boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
-               if (afs)
+               boost::shared_ptr<MidiSource> ms;
+               if (afs) {
                        afs->prepare_for_peakfile_writes ();
+               } else if ((ms = boost::dynamic_pointer_cast<MidiSource>(*src))) {
+                       Source::Lock lock(ms->mutex());
+                       ms->mark_streaming_write_started(lock);
+               }
        }
 
        while (to_do && !itt.cancel) {
@@ -4519,11 +5437,12 @@ Session::write_one_track (Track& track, framepos_t start, framepos_t end,
                                }
                        } else if ((ms = boost::dynamic_pointer_cast<MidiSource>(*src))) {
                                Source::Lock lock(ms->mutex());
-                               ms->mark_streaming_write_started(lock);
 
                                const MidiBuffer& buf = buffers.get_midi(0);
                                for (MidiBuffer::const_iterator i = buf.begin(); i != buf.end(); ++i) {
-                                       ms->append_event_frames(lock, *i, ms->timeline_position());
+                                       Evoral::Event<framepos_t> ev = *i;
+                                       ev.set_time(ev.time() - position);
+                                       ms->append_event_frames(lock, ev, ms->timeline_position());
                                }
                        }
                }
@@ -4618,6 +5537,12 @@ Session::gain_automation_buffer() const
        return ProcessThread::gain_automation_buffer ();
 }
 
+gain_t*
+Session::trim_automation_buffer() const
+{
+       return ProcessThread::trim_automation_buffer ();
+}
+
 gain_t*
 Session::send_gain_automation_buffer() const
 {
@@ -4698,9 +5623,15 @@ Session::have_rec_enabled_track () const
        return g_atomic_int_get (const_cast<gint*>(&_have_rec_enabled_track)) == 1;
 }
 
+bool
+Session::have_rec_disabled_track () const
+{
+    return g_atomic_int_get (const_cast<gint*>(&_have_rec_disabled_track)) == 1;
+}
+
 /** Update the state of our rec-enabled tracks flag */
 void
-Session::update_have_rec_enabled_track ()
+Session::update_route_record_state ()
 {
        boost::shared_ptr<RouteList> rl = routes.reader ();
        RouteList::iterator i = rl->begin();
@@ -4721,6 +5652,22 @@ Session::update_have_rec_enabled_track ()
        if (g_atomic_int_get (&_have_rec_enabled_track) != old) {
                RecordStateChanged (); /* EMIT SIGNAL */
        }
+
+       for (i = rl->begin(); i != rl->end (); ++i) {
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (tr && !tr->record_enabled ()) {
+                       break;
+               }
+       }
+    
+       g_atomic_int_set (&_have_rec_disabled_track, i != rl->end () ? 1 : 0);
+
+       bool record_arm_state_changed = (old != g_atomic_int_get (&_have_rec_enabled_track) );
+    
+       if (record_status() == Recording && record_arm_state_changed ) {
+               RecordArmStateChanged ();
+       }
+       
 }
 
 void
@@ -4763,7 +5710,8 @@ Session::route_added_to_route_group (RouteGroup* rg, boost::weak_ptr<Route> r)
 void
 Session::route_removed_from_route_group (RouteGroup* rg, boost::weak_ptr<Route> r)
 {
-       RouteRemovedFromRouteGroup (rg, r);
+       update_route_record_state ();
+       RouteRemovedFromRouteGroup (rg, r); /* EMIT SIGNAL */
 }
 
 boost::shared_ptr<RouteList>
@@ -4840,7 +5788,7 @@ Session::current_end_frame () const
 }
 
 void
-Session::add_session_range_location (framepos_t start, framepos_t end)
+Session::set_session_range_location (framepos_t start, framepos_t end)
 {
        _session_range_location = new Location (*this, start, end, _("session"), Location::IsSessionRange);
        _locations->add (_session_range_location);
@@ -5276,6 +6224,12 @@ Session::next_control_id () const
                subtract++;
        }
 
+       /* the same about masterbus in Waves Tracks */
+
+       if (Profile->get_trx() && _master_out) {
+               subtract++;
+       }
+
        return nroutes() - subtract;
 }
 
@@ -5293,6 +6247,14 @@ Session::notify_remote_id_change ()
        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
@@ -5347,6 +6309,11 @@ Session::reconnect_ltc_input ()
                if (src != _("None") && !src.empty())  {
                        _ltc_input->nth (0)->connect (src);
                }
+
+               if ( ARDOUR::Profile->get_trx () ) {
+                       // Tracks need this signal to update timecode_source_dropdown
+                       MtcOrLtcInputPortChanged (); //emit signal
+               }
        }
 }
 
@@ -5355,14 +6322,48 @@ Session::reconnect_ltc_output ()
 {
        if (_ltc_output) {
 
-#if 0
-               string src = Config->get_ltc_sink_port();
+               string src = Config->get_ltc_output_port();
 
                _ltc_output->disconnect (this);
 
                if (src != _("None") && !src.empty())  {
                        _ltc_output->nth (0)->connect (src);
                }
-#endif
        }
 }
+
+void
+Session::set_range_selection (framepos_t start, framepos_t end)
+{
+       _range_selection = Evoral::Range<framepos_t> (start, end);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
+#endif
+}
+
+void
+Session::set_object_selection (framepos_t start, framepos_t end)
+{
+       _object_selection = Evoral::Range<framepos_t> (start, end);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
+#endif
+}
+
+void
+Session::clear_range_selection ()
+{
+       _range_selection = Evoral::Range<framepos_t> (-1,-1);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
+#endif
+}
+
+void
+Session::clear_object_selection ()
+{
+       _object_selection = Evoral::Range<framepos_t> (-1,-1);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
+#endif 
+}