fix region fade/env XML save - fixes #5353
[ardour.git] / libs / ardour / session.cc
index 59667b2fce1de96f416972c6d2c2c091dca0da58..3281ff2f98e515ccdd66a24ba66377ffc55ab81d 100644 (file)
@@ -30,7 +30,7 @@
 #include <unistd.h>
 #include <limits.h>
 
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
 #include <glibmm/miscutils.h>
 #include <glibmm/fileutils.h>
 
@@ -145,7 +145,6 @@ Session::Session (AudioEngine &eng,
        , _bundles (new BundleList)
        , _bundle_xml_node (0)
        , _current_trans (0)
-       , _click_io ((IO*) 0)
        , click_data (0)
        , click_emphasis_data (0)
        , main_outs (0)
@@ -153,6 +152,7 @@ Session::Session (AudioEngine &eng,
        , _suspend_timecode_transmission (0)
 {
        _locations = new Locations (*this);
+       ltc_encoder = NULL;
 
        if (how_many_dsp_threads () > 1) {
                /* For now, only create the graph if we are using >1 DSP threads, as
@@ -230,6 +230,10 @@ Session::destroy ()
 
        _state_of_the_state = StateOfTheState (CannotSave|Deletion);
 
+       /* disconnect from any and all signals that we are connected to */
+
+       drop_connections ();
+
        _engine.remove_session ();
 
        /* deregister all ports - there will be no process or any other
@@ -238,6 +242,8 @@ Session::destroy ()
 
        Port::PortDrop (); /* EMIT SIGNAL */
 
+       ltc_tx_cleanup();
+
        /* clear history so that no references to objects are held any more */
 
        _history.clear ();
@@ -364,6 +370,36 @@ Session::when_engine_running ()
 
        try {
                XMLNode* child = 0;
+               
+               _ltc_input.reset (new IO (*this, _("LTC In"), IO::Input));
+               _ltc_output.reset (new IO (*this, _("LTC Out"), IO::Output));
+
+               if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-In")) != 0) {
+                       _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
+               } else {
+                       {
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               _ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
+                       }
+                       reconnect_ltc_input ();
+               }
+
+               if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) {
+                       _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
+               } else {
+                       {
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               _ltc_output->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
+                       }
+                       reconnect_ltc_output ();
+               }
+                                               
+               /* fix up names of LTC ports because we don't want the normal
+                * IO style of NAME/TYPE-{in,out}N
+                */
+               
+               _ltc_input->nth (0)->set_name (_("LTC-in"));
+               _ltc_output->nth (0)->set_name (_("LTC-out"));
 
                _click_io.reset (new ClickIO (*this, "click"));
                _click_gain.reset (new Amp (*this));
@@ -560,7 +596,7 @@ Session::when_engine_running ()
        ControlProtocolManager::instance().midi_connectivity_established ();
 
        if (_is_new && !no_auto_connect()) {
-               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
+               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
                auto_connect_master_bus ();
        }
 
@@ -626,7 +662,7 @@ Session::remove_monitor_section ()
                 * pieces of audio as we work on each route.
                 */
                
-               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                
                /* Connect tracks to monitor section. Note that in an
                   existing session, the internal sends will already exist, but we want the
@@ -672,7 +708,7 @@ Session::add_monitor_section ()
        // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
 #endif
        {
-               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               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);
        }
@@ -725,7 +761,7 @@ Session::add_monitor_section ()
                        boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
                        
                        if (b) {
-                               _monitor_out->output()->connect_ports_to_bundle (b, this);
+                               _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())
@@ -773,7 +809,7 @@ Session::add_monitor_section ()
         * pieces of audio as we work on each route.
         */
         
-       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
        /* Connect tracks to monitor section. Note that in an
           existing session, the internal sends will already exist, but we want the
@@ -1041,7 +1077,7 @@ Session::set_auto_loop_location (Location* location)
        }
 
        if (location->end() <= location->start()) {
-               error << _("Session: you can't use a mark for auto loop") << endmsg;
+               error << _("You cannot use this location for auto-loop because it has zero or negative length") << endmsg;
                return;
        }
 
@@ -1305,8 +1341,6 @@ Session::set_frame_rate (framecnt_t frames_per_second)
 
        sync_time_vars();
 
-       Automatable::set_automation_interval (ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval())));
-
        clear_clicks ();
 
        // XXX we need some equivalent to this, somehow
@@ -1600,8 +1634,6 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
        RouteList new_routes;
        list<boost::shared_ptr<MidiTrack> > ret;
 
-       cerr << "Adding MIDI track with in = " << input << " out = " << output << endl;
-
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI");
 
        while (how_many) {
@@ -1625,7 +1657,7 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
                        // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
 #endif
                        {
-                               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                if (track->input()->ensure_io (input, false, this)) {
                                        error << "cannot configure " << input << " out configuration for new midi track" << endmsg;     
                                        goto failed;
@@ -1660,7 +1692,7 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
 
                catch (AudioEngine::PortRegistrationFailure& pfe) {
 
-                       error << string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with ports if you need this many tracks."), PROGRAM_NAME) << endmsg;
+                       error << string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME) << endmsg;
                        goto failed;
                }
 
@@ -1725,7 +1757,7 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing
                return;
        }
 
-       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::NOT_LOCK);
+       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
 
        if (with_lock) {
                lm.acquire ();
@@ -1860,7 +1892,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                        // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
 #endif
                        {
-                               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                                if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
                                        error << string_compose (
@@ -1946,7 +1978,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                        // boost_debug_shared_ptr_mark_interesting (bus.get(), "Route");
 #endif
                        {
-                               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                                if (bus->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
                                        error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
@@ -1974,6 +2006,8 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                        bus->add_internal_return ();
 
                        ret.push_back (bus);
+                       
+                       ARDOUR::GUIIdle ();
                }
 
 
@@ -2062,7 +2096,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                                   loading this normally happens in a different way.
                                */
 
-                               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                                IOChange change (IOChange::Type (IOChange::ConfigurationChanged | IOChange::ConnectionsChanged));
                                change.after = route->input()->n_ports();
@@ -2101,6 +2135,31 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
 
 void
 Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save)
+{
+       try {
+               PBD::Unwinder<bool> aip (_adding_routes_in_progress, true);
+               add_routes_inner (new_routes, input_auto_connect, output_auto_connect);
+
+       } catch (...) {
+               error << _("Adding new tracks/busses failed") << endmsg;
+       }
+
+       graph_reordered ();
+
+       update_latency (true);
+       update_latency (false);
+               
+       set_dirty();
+       
+       if (save) {
+               save_state (_current_snapshot_name);
+       }
+       
+       RouteAdded (new_routes); /* EMIT SIGNAL */
+}
+
+void
+Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect)
 {
         ChanCount existing_inputs;
         ChanCount existing_outputs;
@@ -2157,6 +2216,7 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
                        }
                }
 
+
                if (input_auto_connect || output_auto_connect) {
                        auto_connect_route (r, existing_inputs, existing_outputs, true, input_auto_connect);
                }
@@ -2165,7 +2225,7 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
                   reasonable defaults because they also affect the remote control
                   ID in most situations.
                */
-               
+
                if (!r->has_order_key (EditorSort)) {
                        if (r->is_hidden()) {
                                /* use an arbitrarily high value */
@@ -2178,34 +2238,23 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
                                order++;
                        }
                }
+
+               ARDOUR::GUIIdle ();
        }
 
        if (_monitor_out && IO::connecting_legal) {
-
-               {
-                       Glib::Mutex::Lock lm (_engine.process_lock());          
-                       
-                       for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
-                               if ((*x)->is_monitor()) {
-                                       /* relax */
-                               } else if ((*x)->is_master()) {
+               Glib::Threads::Mutex::Lock lm (_engine.process_lock());         
+               
+               for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
+                       if ((*x)->is_monitor()) {
+                               /* relax */
+                       } else if ((*x)->is_master()) {
                                        /* relax */
-                               } else {
-                                       (*x)->enable_monitor_send ();
-                               }
+                       } else {
+                               (*x)->enable_monitor_send ();
                        }
                }
-
-               resort_routes ();
        }
-
-       set_dirty();
-
-       if (save) {
-               save_state (_current_snapshot_name);
-       }
-
-       RouteAdded (new_routes); /* EMIT SIGNAL */
 }
 
 void
@@ -2515,14 +2564,17 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                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, "\tno feed from\n");
+                       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()));
@@ -2543,7 +2595,11 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                                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 {
@@ -2565,7 +2621,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\n", (*i)->name()));
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
                (*i)->mute_changed (this);
        }
 
@@ -2615,6 +2671,9 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                _solo_isolated_cnt = isolated;
                IsolatedChanged (); /* EMIT SIGNAL */
        }
+
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("solo state updated by session, soloed? %1 listeners %2 isolated %3\n",
+                                                 something_soloed, listeners, isolated));
 }
 
 boost::shared_ptr<RouteList>
@@ -2650,44 +2709,68 @@ Session::io_name_is_legal (const std::string& name)
 }
 
 void
-Session::set_exclusive_input_active (boost::shared_ptr<Route> rt, bool /*others_on*/)
+Session::set_exclusive_input_active (boost::shared_ptr<RouteList> rl, bool onoff, bool flip_others)
 {
-       RouteList rl;
+       RouteList rl2;
        vector<string> connections;
 
-       PortSet& ps (rt->input()->ports());
-
-       for (PortSet::iterator p = ps.begin(); p != ps.end(); ++p) {
-               p->get_connections (connections);
-       }
+       /* if we are passed only a single route and we're not told to turn
+        * others off, then just do the simple thing.
+        */
 
-       for (vector<string>::iterator s = connections.begin(); s != connections.end(); ++s) {
-               routes_using_input_from (*s, rl);
+       if (flip_others == false && rl->size() == 1) {
+               boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (rl->front());
+               if (mt) {
+                       mt->set_input_active (onoff);
+                       return;
+               }
        }
 
-       /* scan all relevant routes to see if others are on or off */
+       for (RouteList::iterator rt = rl->begin(); rt != rl->end(); ++rt) {
 
-       bool others_are_already_on = false;
+               PortSet& ps ((*rt)->input()->ports());
+               
+               for (PortSet::iterator p = ps.begin(); p != ps.end(); ++p) {
+                       p->get_connections (connections);
+               }
+               
+               for (vector<string>::iterator s = connections.begin(); s != connections.end(); ++s) {
+                       routes_using_input_from (*s, rl2);
+               }
+               
+               /* scan all relevant routes to see if others are on or off */
+               
+               bool others_are_already_on = false;
+               
+               for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) {
 
-       for (RouteList::iterator r = rl.begin(); r != rl.end(); ++r) {
-               if ((*r) != rt) {
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
-                       if (mt) {
+
+                       if (!mt) {
+                               continue;
+                       }
+
+                       if ((*r) != (*rt)) {
                                if (mt->input_active()) {
                                        others_are_already_on = true;
-                                       break;
                                }
+                       } else {
+                               /* this one needs changing */
+                               mt->set_input_active (onoff);
                        }
                }
-       }
-
-       /* globally reverse other routes */
+               
+               if (flip_others) {
 
-       for (RouteList::iterator r = rl.begin(); r != rl.end(); ++r) {
-               if ((*r) != rt) {
-                       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
-                       if (mt) {
-                               mt->set_input_active (!others_are_already_on);
+                       /* globally reverse other routes */
+                       
+                       for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) {
+                               if ((*r) != (*rt)) {
+                                       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
+                                       if (mt) {
+                                               mt->set_input_active (!others_are_already_on);
+                                       }
+                               }
                        }
                }
        }
@@ -2696,7 +2779,7 @@ Session::set_exclusive_input_active (boost::shared_ptr<Route> rt, bool /*others_
 void
 Session::routes_using_input_from (const string& str, RouteList& rl)
 {
-       boost::shared_ptr<RouteList> r = routes.reader ();
+       boost::shared_ptr<RouteList> r = routes.reader();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((*i)->input()->connected_to (str)) {
@@ -2854,7 +2937,7 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child) const
        RegionFactory::RegionMap::const_iterator i;
        boost::shared_ptr<Region> region;
 
-       Glib::Mutex::Lock lm (region_lock);
+       Glib::Threads::Mutex::Lock lm (region_lock);
 
        for (i = regions.begin(); i != regions.end(); ++i) {
 
@@ -2900,7 +2983,7 @@ Session::destroy_sources (list<boost::shared_ptr<Source> > srcs)
        for (list<boost::shared_ptr<Source> >::iterator s = srcs.begin(); s != srcs.end(); ) {
 
                {
-                       Glib::Mutex::Lock ls (source_lock);
+                       Glib::Threads::Mutex::Lock ls (source_lock);
                        /* remove from the main source list */
                        sources.erase ((*s)->id());
                }
@@ -2953,7 +3036,7 @@ Session::add_source (boost::shared_ptr<Source> source)
        entry.second = source;
 
        {
-               Glib::Mutex::Lock lm (source_lock);
+               Glib::Threads::Mutex::Lock lm (source_lock);
                result = sources.insert (entry);
        }
 
@@ -2998,7 +3081,7 @@ Session::remove_source (boost::weak_ptr<Source> src)
        }
 
        {
-               Glib::Mutex::Lock lm (source_lock);
+               Glib::Threads::Mutex::Lock lm (source_lock);
 
                if ((i = sources.find (source->id())) != sources.end()) {
                        sources.erase (i);
@@ -3018,7 +3101,7 @@ Session::remove_source (boost::weak_ptr<Source> src)
 boost::shared_ptr<Source>
 Session::source_by_id (const PBD::ID& id)
 {
-       Glib::Mutex::Lock lm (source_lock);
+       Glib::Threads::Mutex::Lock lm (source_lock);
        SourceMap::iterator i;
        boost::shared_ptr<Source> source;
 
@@ -3032,7 +3115,7 @@ Session::source_by_id (const PBD::ID& id)
 boost::shared_ptr<Source>
 Session::source_by_path_and_channel (const string& path, uint16_t chn)
 {
-       Glib::Mutex::Lock lm (source_lock);
+       Glib::Threads::Mutex::Lock lm (source_lock);
 
        for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
                boost::shared_ptr<AudioFileSource> afs
@@ -3049,7 +3132,7 @@ uint32_t
 Session::count_sources_by_origin (const string& path)
 {
        uint32_t cnt = 0;
-       Glib::Mutex::Lock lm (source_lock);
+       Glib::Threads::Mutex::Lock lm (source_lock);
 
        for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
                boost::shared_ptr<FileSource> fs
@@ -3483,7 +3566,7 @@ Session::graph_reordered ()
           from a set_state() call or creating new tracks. Ditto for deletion.
        */
 
-       if (_state_of_the_state & (InitialConnecting|Deletion)) {
+       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress) {
                return;
        }
 
@@ -3514,7 +3597,7 @@ Session::graph_reordered ()
 boost::optional<framecnt_t>
 Session::available_capture_duration ()
 {
-       Glib::Mutex::Lock lm (space_lock);
+       Glib::Threads::Mutex::Lock lm (space_lock);
 
        if (_total_free_4k_blocks_uncertain) {
                return boost::optional<framecnt_t> ();
@@ -4118,7 +4201,7 @@ Session::add_automation_list(AutomationList *al)
 bool
 Session::have_rec_enabled_track () const
 {
-       return g_atomic_int_get (&_have_rec_enabled_track) == 1;
+       return g_atomic_int_get (const_cast<gint*>(&_have_rec_enabled_track)) == 1;
 }
 
 /** Update the state of our rec-enabled tracks flag */
@@ -4189,18 +4272,6 @@ Session::route_removed_from_route_group (RouteGroup* rg, boost::weak_ptr<Route>
        RouteRemovedFromRouteGroup (rg, r);
 }
 
-vector<SyncSource>
-Session::get_available_sync_options () const
-{
-       vector<SyncSource> ret;
-
-       ret.push_back (JACK);
-       ret.push_back (MTC);
-       ret.push_back (MIDIClock);
-
-       return ret;
-}
-
 boost::shared_ptr<RouteList>
 Session::get_routes_with_regions_at (framepos_t const p) const
 {
@@ -4337,7 +4408,7 @@ Session::source_search_path (DataType type) const
        if (session_dirs.size() == 1) {
                switch (type) {
                case DataType::AUDIO:
-                       s.push_back ( _session_dir->sound_path());
+                       s.push_back (_session_dir->sound_path());
                        break;
                case DataType::MIDI:
                        s.push_back (_session_dir->midi_path());
@@ -4357,6 +4428,15 @@ Session::source_search_path (DataType type) const
                }
        }
 
+       if (type == DataType::AUDIO) {
+               const string sound_path_2X = _session_dir->sound_path_2X();
+               if (Glib::file_test (sound_path_2X, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
+                       if (find (s.begin(), s.end(), sound_path_2X) == s.end()) {
+                               s.push_back (sound_path_2X);
+                       }
+               }
+       }
+
        /* now check the explicit (possibly user-specified) search path
         */
 
@@ -4372,16 +4452,7 @@ Session::source_search_path (DataType type) const
        }
 
        for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
-
-               vector<string>::iterator si;
-
-               for (si = s.begin(); si != s.end(); ++si) {
-                       if ((*si) == *i) {
-                               break;
-                       }
-               }
-
-               if (si == s.end()) {
+               if (find (s.begin(), s.end(), *i) == s.end()) {
                        s.push_back (*i);
                }
        }
@@ -4475,7 +4546,7 @@ Session::update_latency (bool playback)
 {
        DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
 
-       if (_state_of_the_state & (InitialConnecting|Deletion)) {
+       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress) {
                return;
        }
 
@@ -4562,7 +4633,7 @@ void
 Session::initialize_latencies ()
 {
         {
-                Glib::Mutex::Lock lm (_engine.process_lock());
+                Glib::Threads::Mutex::Lock lm (_engine.process_lock());
                 update_latency (false);
                 update_latency (true);
         }
@@ -4738,3 +4809,47 @@ Session::operation_in_progress (GQuark op) const
 {
        return (find (_current_trans_quarks.begin(), _current_trans_quarks.end(), op) != _current_trans_quarks.end());
 }
+
+boost::shared_ptr<Port>
+Session::ltc_input_port () const
+{
+       return _ltc_input->nth (0);
+}
+
+boost::shared_ptr<Port>
+Session::ltc_output_port () const
+{
+       return _ltc_output->nth (0);
+}
+
+void
+Session::reconnect_ltc_input ()
+{
+       if (_ltc_input) {
+
+               string src = Config->get_ltc_source_port();
+
+               _ltc_input->disconnect (this);
+
+               if (src != _("None") && !src.empty())  {
+                       _ltc_input->nth (0)->connect (src);
+               }
+       }
+}
+
+void
+Session::reconnect_ltc_output ()
+{
+       if (_ltc_output) {
+
+#if 0
+               string src = Config->get_ltc_sink_port();
+
+               _ltc_output->disconnect (this);
+
+               if (src != _("None") && !src.empty())  {
+                       _ltc_output->nth (0)->connect (src);
+               }
+#endif
+       }
+}