use FileSource::within_session() for peak-files
[ardour.git] / libs / ardour / session.cc
index ac86a3612412f4a63cb06f8f9d1dae67e8eb6b81..91578c9b179f6dfdad81600549bb86a7ef46e45e 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)
@@ -270,6 +282,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)
@@ -294,17 +308,19 @@ Session::Session (AudioEngine &eng,
        
        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
@@ -320,7 +336,7 @@ Session::Session (AudioEngine &eng,
 
                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);
                }
@@ -331,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
@@ -348,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);
@@ -373,8 +389,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 */
@@ -429,6 +443,7 @@ Session::Session (AudioEngine &eng,
        
        _is_new = false;
        session_loaded ();
+
        BootMessage (_("Session loading complete"));
 }
 
@@ -801,10 +816,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);
                }
@@ -835,10 +850,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);
                }
@@ -1447,6 +1462,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 ();
 }
@@ -1837,6 +1865,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 ();
@@ -1924,7 +1957,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);
 
@@ -2162,16 +2196,16 @@ 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)
 {
        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;
@@ -2202,6 +2236,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
@@ -2210,16 +2263,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;
                }
@@ -2670,36 +2724,37 @@ 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
@@ -2746,25 +2801,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;
 
-       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;
                }
@@ -2867,7 +2915,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;
@@ -2875,7 +2923,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;
                }
@@ -2981,7 +3029,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()) {
 
@@ -2990,7 +3038,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*/
                                }
@@ -3000,7 +3048,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*/
                                }
@@ -3377,6 +3425,7 @@ 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
     
@@ -3485,6 +3534,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)
 {
@@ -3920,9 +4083,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 {
 
@@ -4198,20 +4363,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 */
@@ -4231,12 +4407,25 @@ 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
@@ -4359,7 +4548,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;
@@ -4516,7 +4705,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 ();
        }
@@ -5012,12 +5201,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);
@@ -5565,7 +5754,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);
@@ -6086,6 +6275,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
+               }
        }
 }
 
@@ -6094,14 +6288,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 
+}