allow grouped AFL/PFL with excl. solo
[ardour.git] / libs / ardour / session.cc
index c3fbd44f0fbc48e9e9bfc3754bf67964c38cc2c2..eb333f8e0de33499dd722e29f4f63f0e69c142a0 100644 (file)
 
 #include "i18n.h"
 
+#include <glibmm/checksum.h>
+
 namespace ARDOUR {
 class MidiSource;
 class Processor;
@@ -118,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;
@@ -135,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,
@@ -184,6 +194,8 @@ Session::Session (AudioEngine &eng,
        , 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)
@@ -199,7 +211,7 @@ Session::Session (AudioEngine &eng,
        , loop_changing (false)
        , last_loopend (0)
        , _session_dir (new SessionDirectory (fullpath))
-       , _current_snapshot_name (snapshot_name)          
+       , _current_snapshot_name (snapshot_name)        
        , state_tree (0)
        , state_was_pending (false)
        , _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading))
@@ -252,7 +264,6 @@ Session::Session (AudioEngine &eng,
        , _route_deletion_in_progress (false)
        , destructive_index (0)
        , _track_number_decimals(1)
-       , solo_update_disabled (false)
        , default_fade_steepness (0)
        , default_fade_msecs (0)
        , _total_free_4k_blocks (0)
@@ -270,6 +281,8 @@ 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)
@@ -293,14 +306,20 @@ Session::Session (AudioEngine &eng,
        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
@@ -314,9 +333,9 @@ Session::Session (AudioEngine &eng,
                 * of a template.
                 */
 
-               if (!mix_template.empty()) { 
+               if (!mix_template.empty()) {
                        if (load_state (_current_snapshot_name)) {
-                               throw failed_constructor ();
+                               throw SessionException (_("Failed to load template/snapshot state"));
                        }
                        store_recent_templates (mix_template);
                }
@@ -327,7 +346,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
@@ -344,13 +363,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);
@@ -369,8 +388,6 @@ 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 */
@@ -400,7 +417,7 @@ Session::Session (AudioEngine &eng,
                        
                        list<boost::shared_ptr<AudioTrack> > tracks;
                        
-                       // Track names after driver 
+                       // 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) {
@@ -410,7 +427,7 @@ Session::Session (AudioEngine &eng,
                                        
                                        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());
                        }
@@ -425,6 +442,7 @@ Session::Session (AudioEngine &eng,
        
        _is_new = false;
        session_loaded ();
+
        BootMessage (_("Session loading complete"));
 }
 
@@ -475,7 +493,7 @@ Session::immediately_post_engine ()
         * know that the engine is running, but before we either create a
         * session or set state for an existing one.
         */
-        
+       
        if (how_many_dsp_threads () > 1) {
                /* For now, only create the graph if we are using >1 DSP threads, as
                   it is a bit slower than the old code with 1 thread.
@@ -532,6 +550,12 @@ Session::destroy ()
 
        drop_connections ();
 
+       /* shutdown control surface protocols while we still have ports
+          and the engine to move data to any devices.
+       */
+       
+       ControlProtocolManager::instance().drop_protocols ();
+       
        _engine.remove_session ();
 
 #ifdef USE_TRACKS_CODE_FEATURES
@@ -797,10 +821,10 @@ Session::setup_bundles ()
        /* mono output bundles */
 
        for (uint32_t np = 0; np < outputs[DataType::AUDIO].size(); ++np) {
-               char buf[32];
+               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.substr(0,12).c_str());
+                       snprintf (buf, sizeof (buf), _("out %s"), pn.c_str());
                } else {
                        snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
                }
@@ -831,10 +855,10 @@ Session::setup_bundles ()
        /* mono input bundles */
 
        for (uint32_t np = 0; np < inputs[DataType::AUDIO].size(); ++np) {
-               char buf[32];
+               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.substr(0,12).c_str());
+                       snprintf (buf, sizeof (buf), _("in %s"), pn.c_str());
                } else {
                        snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
                }
@@ -1009,10 +1033,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);
@@ -1110,7 +1137,7 @@ Session::add_monitor_section ()
        /* Hold process lock while doing this so that we don't hear bits and
         * pieces of audio as we work on each route.
         */
-        
+       
        Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
        /* Connect tracks to monitor section. Note that in an
@@ -1443,6 +1470,19 @@ Session::auto_loop_changed (Location* location)
                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 ();
 }
@@ -1551,7 +1591,7 @@ Session::set_auto_loop_location (Location* location)
                        }
                }
        }
-    
+
        /* take care of our stuff first */
 
        auto_loop_changed (location);
@@ -1561,12 +1601,6 @@ Session::set_auto_loop_location (Location* location)
        auto_loop_location_changed (location);
 }
 
-void
-Session::update_loop (Location*)
-{
-       set_dirty ();
-}
-
 void
 Session::update_marks (Location*)
 {
@@ -1588,7 +1622,7 @@ Session::update_skips (Location* loc, bool consolidate)
         }
 
        sync_locations_to_skips ();
-        
+
        set_dirty ();
 }
 
@@ -1610,7 +1644,7 @@ Session::consolidate_skips (Location* loc)
                         ++l;
                         continue;
                 }
-                        
+
                 switch (Evoral::coverage ((*l)->start(), (*l)->end(), loc->start(), loc->end())) {
                 case Evoral::OverlapInternal:
                 case Evoral::OverlapExternal:
@@ -1670,7 +1704,7 @@ Session::location_added (Location *location)
         if (location->is_auto_loop()) {
                 set_auto_loop_location (location);
         }
-        
+
         if (location->is_session_range()) {
                 /* no need for any signal handling or event setting with the session range,
                    because we keep a direct reference to it and use its start/end directly.
@@ -1697,7 +1731,7 @@ Session::location_added (Location *location)
 
                 update_skips (location, true);
         }
-        
+
        set_dirty ();
 }
 
@@ -1708,7 +1742,7 @@ Session::location_removed (Location *location)
                set_auto_loop_location (0);
                set_track_loop (false);
         }
-        
+
         if (location->is_auto_punch()) {
                 set_auto_punch_location (0);
         }
@@ -1719,7 +1753,7 @@ Session::location_removed (Location *location)
         }
 
         if (location->is_skip()) {
-                
+
                 update_skips (location, false);
         }
 
@@ -1735,23 +1769,20 @@ Session::locations_changed ()
 void
 Session::_locations_changed (const Locations::LocationList& locations)
 {
-        /* There was some mass-change in the Locations object. 
+        /* There was some mass-change in the Locations object.
 
            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.
         */
-    loop_update_connections.drop_connections ();
-    mark_update_connections.drop_connections ();
-    skip_update_connections.drop_connections ();
-    
-    {
-        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);
+       
+       {
+               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
@@ -1791,7 +1822,7 @@ Session::disable_record (bool rt_context, bool force)
 
        if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
 
-               if ((!Config->get_latched_record_enable () && !play_loop) || force) {
+               if (!Config->get_latched_record_enable () || force) {
                        g_atomic_int_set (&_record_status, Disabled);
                        send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit));
                } else {
@@ -1929,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);
 
@@ -2082,7 +2114,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
         *    routes directly or indirectly feed them.  This information
         *    is used by the solo code.
         */
-          
+       
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 
                /* Clear out the route's list of direct or indirect feeds */
@@ -2167,16 +2199,31 @@ 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)
 {
+       /* 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 (vector<string>::const_iterator reserved = reserved_io_names.begin(); reserved != reserved_io_names.end(); ++reserved) {
+               if (base == *reserved) {
+                       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;
@@ -2207,24 +2254,44 @@ 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
  */
 list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost::shared_ptr<PluginInfo> instrument, 
+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;
                }
@@ -2461,7 +2528,7 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing
        }
 }
 
-#ifdef USE_TRACKS_CODE_FEATURES 
+#ifdef USE_TRACKS_CODE_FEATURES
 
 static bool
 compare_routes_by_remote_id (const boost::shared_ptr<Route>& route1, const boost::shared_ptr<Route>& route2)
@@ -2476,42 +2543,42 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
        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();
@@ -2527,52 +2594,52 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
                        } 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 );
@@ -2581,54 +2648,54 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
                                                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 */
 }
 
@@ -2636,16 +2703,16 @@ 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);
@@ -2654,17 +2721,17 @@ Session::reconnect_midi_scene_ports(bool inputs)
         }
 
     } 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);
@@ -2675,66 +2742,67 @@ Session::reconnect_midi_scene_ports(bool inputs)
 }
 
 void
-Session::reconnect_mtc_ports()
+Session::reconnect_mtc_ports ()
 {
-#if 0
        boost::shared_ptr<MidiPort> mtc_in_ptr = _midi_ports->mtc_input_port();
 
-       if (mtc_in_ptr) {
-               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
+       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);
                }
        }
-#endif
+       
+       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_mmc_ports(bool inputs)
 {
        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);
                        }
@@ -2748,28 +2816,21 @@ Session::reconnect_mmc_ports(bool inputs)
  *  @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, 
+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;
 
-       string name_pattern;
-
-       if (Profile->get_trx() ) {
-               name_pattern = "Track ";
-       } else {
-               name_pattern = "Audio ";
-       }
-    
-       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _(name_pattern.c_str() );
+       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() ? _(name_pattern.c_str()) : 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;
                }
@@ -2872,7 +2933,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;
@@ -2880,7 +2941,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;
                }
@@ -2986,7 +3047,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()) {
 
@@ -2995,7 +3056,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*/
                                }
@@ -3005,7 +3066,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*/
                                }
@@ -3107,7 +3168,7 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
        reassign_track_numbers();
 
        update_route_record_state ();
-    
+
        RouteAdded (new_routes); /* EMIT SIGNAL */
 }
 
@@ -3303,44 +3364,44 @@ Session::add_internal_send (boost::shared_ptr<Route> dest, boost::shared_ptr<Pro
 void
 Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 {
+       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 ();
                        }
 
-                       update_route_solo_state ();
-            
                        // 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);
@@ -3349,31 +3410,31 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                                        }
                                }
                        }
-            
+
                        /* 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--;
                                }
                        }
-
-                       RouteAddedOrRemoved (false); /* EMIT SIGNAL */
                }
-    
+
                /* writer goes out of scope, forces route list update */
 
        } // end of RCU Writer scope
-    
+
+       update_route_solo_state ();
+       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
@@ -3382,31 +3443,31 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 #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
         */
-       PBD::Unwinder<bool> uw_flag (_route_deletion_in_progress, true);
 
        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);
        }
@@ -3441,10 +3502,12 @@ Session::route_listen_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
        if (route->listening_via_monitor ()) {
 
                if (Config->get_exclusive_solo()) {
-                       /* new listen: disable all other listen */
+                       /* new listen: disable all other listen, except solo-grouped channels */
+                       RouteGroup* rg = route->route_group ();
+                       bool leave_group_alone = (rg && rg->is_active() && rg->is_solo());
                        boost::shared_ptr<RouteList> r = routes.reader ();
                        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() || (leave_group_alone && ((*i)->route_group() == rg))) {
                                        continue;
                                }
                                (*i)->set_listen (false, this);
@@ -3467,7 +3530,7 @@ Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
 
        if (!route) {
                /* should not happen */
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
+               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_isolated_changed")) << endmsg;
                return;
        }
 
@@ -3500,12 +3563,6 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                return;
        }
 
-       if (solo_update_disabled) {
-               // We know already
-               DEBUG_TRACE (DEBUG::Solo, "solo update disabled - changed ignored\n");
-               return;
-       }
-
        boost::shared_ptr<Route> route = wpr.lock ();
        assert (route);
 
@@ -3536,8 +3593,6 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
 
        DEBUG_TRACE (DEBUG::Solo, string_compose ("propagate solo change, delta = %1\n", delta));
 
-       solo_update_disabled = true;
-
        RouteList uninvolved;
 
        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1\n", route->name()));
@@ -3603,7 +3658,6 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                }
        }
 
-       solo_update_disabled = false;
        DEBUG_TRACE (DEBUG::Solo, "propagation complete\n");
 
        update_route_solo_state (r);
@@ -3688,6 +3742,12 @@ Session::io_name_is_legal (const std::string& name)
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
+       for (vector<string>::const_iterator reserved = reserved_io_names.begin(); reserved != reserved_io_names.end(); ++reserved) {
+               if (name == *reserved) {
+                       return false;
+               }
+       }
+       
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((*i)->name() == name) {
                        return false;
@@ -3925,9 +3985,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 {
 
@@ -4203,20 +4265,31 @@ 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
 {
-       if (Glib::path_is_absolute (base)) {
+       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;
-               string interchange_dir_string = string (interchange_dir_name) + G_DIR_SEPARATOR;
                bool in_another_session = true;
                
-               if (base.find (interchange_dir_string) != string::npos) {
+               if (filepath.find (interchange_dir_string) != string::npos) {
                
-                       session_path = Glib::path_get_dirname (base); /* now ends in audiofiles */
+                       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 */
@@ -4236,31 +4309,44 @@ Session::peak_path (string base) const
 
                if (in_another_session) {
                        SessionDirectory sd (session_path);
-                       return Glib::build_filename (sd.peak_path(), Glib::path_get_basename (base) + peakfile_suffix);
+                       return peak_file_helper (sd.peak_path(), "", Glib::path_get_basename (filepath), !old_peak_name);
                }
        }
 
-       base = Glib::path_get_basename (base);
-       return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix);
+       /* 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
 Session::new_audio_source_path_for_embedded (const std::string& path)
 {
-       /* embedded source: 
+       /* embedded source:
         *
         * we know that the filename is already unique because it exists
-        * out in the filesystem. 
+        * out in the filesystem.
         *
         * However, when we bring it into the session, we could get a
         * collision.
         *
         * Eg. two embedded files:
-        * 
+        *
         *          /foo/bar/baz.wav
         *          /frob/nic/baz.wav
         *
-        * When merged into session, these collide. 
+        * When merged into session, these collide.
         *
         * There will not be a conflict with in-memory sources
         * because when the source was created we already picked
@@ -4304,14 +4390,14 @@ 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 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 
+ * 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.
  */
@@ -4364,7 +4450,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;
@@ -4521,7 +4607,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 ();
        }
@@ -4547,21 +4633,21 @@ boost::shared_ptr<MidiSource>
 Session::create_midi_source_by_stealing_name (boost::shared_ptr<Track> track)
 {
        /* the caller passes in the track the source will be used in,
-          so that we can keep the numbering sane. 
-          
+          so that we can keep the numbering sane.
+       
           Rationale: a track with the name "Foo" that has had N
           captures carried out so far will ALREADY have a write source
           named "Foo-N+1.mid" waiting to be used for the next capture.
-          
+       
           If we call new_midi_source_name() we will get "Foo-N+2". But
           there is no region corresponding to "Foo-N+1", so when
           "Foo-N+2" appears in the track, the gap presents the user
           with odd behaviour - why did it skip past Foo-N+1?
-          
+       
           We could explain this to the user in some odd way, but
           instead we rename "Foo-N+1.mid" as "Foo-N+2.mid", and then
           use "Foo-N+1" here.
-          
+       
           If that attempted rename fails, we get "Foo-N+2.mid" anyway.
        */
        
@@ -4694,7 +4780,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 || _reconnecting_routes_in_progress) {
+       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress || _reconnecting_routes_in_progress || _route_deletion_in_progress) {
                return;
        }
 
@@ -5017,12 +5103,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);
@@ -5081,7 +5167,7 @@ Session::freeze_all (InterThreadInfo& itt)
 boost::shared_ptr<Region>
 Session::write_one_track (Track& track, framepos_t start, framepos_t end,
                          bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
-                         InterThreadInfo& itt, 
+                         InterThreadInfo& itt,
                          boost::shared_ptr<Processor> endpoint, bool include_endpoint,
                          bool for_export, bool for_freeze)
 {
@@ -5441,11 +5527,11 @@ Session::update_route_record_state ()
                        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 ();
        }
@@ -5570,7 +5656,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);
@@ -5992,7 +6078,7 @@ Session::session_name_is_legal (const string& path)
        return 0;
 }
 
-uint32_t 
+uint32_t
 Session::next_control_id () const
 {
        int subtract = 0;
@@ -6006,6 +6092,12 @@ Session::next_control_id () const
                subtract++;
        }
 
+       /* the same about masterbus in Waves Tracks */
+
+       if (Profile->get_trx() && _master_out) {
+               subtract++;
+       }
+
        return nroutes() - subtract;
 }
 
@@ -6085,6 +6177,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
+               }
        }
 }
 
@@ -6093,14 +6190,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 
+}