move ownership of LTC I/O ports to Session, and manage as IO objects
[ardour.git] / libs / ardour / session.cc
index b09d67fb354b009a6b63e65afd2955f02a5dbd52..c335e021aa616e7294ac25542db15af52c68aa2c 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>
 
@@ -45,7 +45,6 @@
 #include "pbd/file_utils.h"
 #include "pbd/convert.h"
 #include "pbd/strsplit.h"
-#include "pbd/strsplit.h"
 #include "pbd/unwind.h"
 
 #include "ardour/amp.h"
@@ -69,7 +68,6 @@
 #include "ardour/graph.h"
 #include "ardour/midi_track.h"
 #include "ardour/midi_ui.h"
-#include "ardour/named_selection.h"
 #include "ardour/operations.h"
 #include "ardour/playlist.h"
 #include "ardour/plugin.h"
@@ -116,8 +114,6 @@ PBD::Signal3<int,Session*,std::string,DataType> Session::MissingFile;
 
 PBD::Signal1<void, framepos_t> Session::StartTimeChanged;
 PBD::Signal1<void, framepos_t> Session::EndTimeChanged;
-PBD::Signal0<void> Session::AutoBindingOn;
-PBD::Signal0<void> Session::AutoBindingOff;
 PBD::Signal2<void,std::string, std::string> Session::Exported;
 PBD::Signal1<int,boost::shared_ptr<Playlist> > Session::AskAboutPlaylistDeletion;
 PBD::Signal0<void> Session::Quit;
@@ -127,7 +123,7 @@ PBD::Signal0<void> Session::SuccessfulGraphSort;
 static void clean_up_session_event (SessionEvent* ev) { delete ev; }
 const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event);
 
-/** @param snapshot_name Snapshot name, without .ardour prefix */
+/** @param snapshot_name Snapshot name, without .ardour suffix */
 Session::Session (AudioEngine &eng,
                   const string& fullpath,
                   const string& snapshot_name,
@@ -145,10 +141,10 @@ Session::Session (AudioEngine &eng,
        , _all_route_group (new RouteGroup (*this, "all"))
        , routes (new RouteList)
        , _total_free_4k_blocks (0)
+       , _total_free_4k_blocks_uncertain (false)
        , _bundles (new BundleList)
        , _bundle_xml_node (0)
        , _current_trans (0)
-       , _click_io ((IO*) 0)
        , click_data (0)
        , click_emphasis_data (0)
        , main_outs (0)
@@ -156,6 +152,9 @@ Session::Session (AudioEngine &eng,
        , _suspend_timecode_transmission (0)
 {
        _locations = new Locations (*this);
+#ifdef HAVE_LTC
+       ltc_encoder = NULL;
+#endif
 
        if (how_many_dsp_threads () > 1) {
                /* For now, only create the graph if we are using >1 DSP threads, as
@@ -235,6 +234,16 @@ Session::destroy ()
 
        _engine.remove_session ();
 
+       /* deregister all ports - there will be no process or any other
+        * callbacks from the engine any more.
+        */
+
+       Port::PortDrop (); /* EMIT SIGNAL */
+
+#ifdef HAVE_LTC
+       ltc_tx_cleanup();
+#endif
+
        /* clear history so that no references to objects are held any more */
 
        _history.clear ();
@@ -249,6 +258,8 @@ Session::destroy ()
 
        _butler->drop_references ();
        delete _butler;
+       _butler = 0;
+       
        delete midi_control_ui;
        delete _all_route_group;
 
@@ -274,9 +285,6 @@ Session::destroy ()
 
        /* tell everyone to drop references and delete objects as we go */
 
-       DEBUG_TRACE (DEBUG::Destruction, "delete named selections\n");
-       named_selections.clear ();
-
        DEBUG_TRACE (DEBUG::Destruction, "delete regions\n");
        RegionFactory::delete_all_regions ();
 
@@ -362,7 +370,30 @@ 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 ();
+               }
+                                               
                _click_io.reset (new ClickIO (*this, "click"));
                _click_gain.reset (new Amp (*this));
                _click_gain->activate ();
@@ -558,7 +589,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 ();
        }
 
@@ -572,6 +603,7 @@ Session::when_engine_running ()
 
        BootMessage (_("Connect to engine"));
        _engine.set_session (this);
+       _engine.reset_timebase ();
 }
 
 void
@@ -623,7 +655,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
@@ -669,7 +701,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);
        }
@@ -722,7 +754,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())
@@ -770,7 +802,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
@@ -928,10 +960,25 @@ Session::auto_punch_changed (Location* location)
        replace_event (SessionEvent::PunchOut, when_to_stop);
 }
 
+/** @param loc A loop location.
+ *  @param pos Filled in with the start time of the required fade-out (in session frames).
+ *  @param length Filled in with the length of the required fade-out.
+ */
+void
+Session::auto_loop_declick_range (Location* loc, framepos_t & pos, framepos_t & length)
+{
+       pos = max (loc->start(), loc->end() - 64);
+       length = loc->end() - pos;
+}
+
 void
 Session::auto_loop_changed (Location* location)
 {
        replace_event (SessionEvent::AutoLoop, location->end(), location->start());
+       framepos_t dcp;
+       framecnt_t dcl;
+       auto_loop_declick_range (location, dcp, dcl);
+       replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl);
 
        if (transport_rolling() && play_loop) {
 
@@ -1009,6 +1056,10 @@ Session::set_auto_loop_location (Location* location)
                loop_connections.drop_connections ();
                existing->set_auto_loop (false, this);
                remove_event (existing->end(), SessionEvent::AutoLoop);
+               framepos_t dcp;
+               framecnt_t dcl;
+               auto_loop_declick_range (existing, dcp, dcl);
+               remove_event (dcp, SessionEvent::AutoLoopDeclick);
                auto_loop_location_changed (0);
        }
 
@@ -1238,7 +1289,7 @@ Session::audible_frame () const
                   of audible frames, we have not moved yet.
 
                   `Start position' in this context means the time we last
-                  either started or changed transport direction.
+                  either started, located, or changed transport direction.
                */
 
                if (_transport_speed > 0.0f) {
@@ -1484,13 +1535,13 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
                        trace_terminal (*i, *i);
                }
 
-               r = sorted_routes;
+               *r = *sorted_routes;
 
 #ifndef NDEBUG
                DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2\n",
-                                                                  (*i)->name(), (*i)->order_key ("signal")));
+                                                                  (*i)->name(), (*i)->order_key (MixerSort)));
                }
 #endif
 
@@ -1569,16 +1620,16 @@ Session::count_existing_track_channels (ChanCount& in, ChanCount& out)
  *  @param instrument plugin info for the instrument to insert pre-fader, if any
  */
 list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (boost::shared_ptr<PluginInfo> instrument, TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template)
+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];
        uint32_t track_id = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<MidiTrack> > ret;
-       uint32_t control_id;
 
-       control_id = next_control_id ();
+       cerr << "Adding MIDI track with in = " << input << " out = " << output << endl;
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI");
 
@@ -1603,14 +1654,14 @@ Session::new_midi_track (boost::shared_ptr<PluginInfo> instrument, TrackMode mod
                        // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
 #endif
                        {
-                               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                               if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
-                                       error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
+                               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;
                                }
 
-                               if (track->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
-                                       error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
+                               if (track->output()->ensure_io (output, false, this)) {
+                                       error << "cannot configure " << output << " out configuration for new midi track" << endmsg;
                                        goto failed;
                                }
                        }
@@ -1622,7 +1673,10 @@ Session::new_midi_track (boost::shared_ptr<PluginInfo> instrument, TrackMode mod
                        }
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
-                       track->set_remote_control_id (control_id);
+
+                       if (Config->get_remote_model() == UserOrdered) {
+                               track->set_remote_control_id (next_control_id());
+                       }
 
                        new_routes.push_back (track);
                        ret.push_back (track);
@@ -1700,7 +1754,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 ();
@@ -1811,9 +1865,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<AudioTrack> > ret;
-       uint32_t control_id;
-
-       control_id = next_control_id ();
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio");
 
@@ -1838,7 +1889,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 (
@@ -1864,8 +1915,9 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                        track->non_realtime_input_change();
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
-                       track->set_remote_control_id (control_id);
-                       ++control_id;
+                       if (Config->get_remote_model() == UserOrdered) {
+                               track->set_remote_control_id (next_control_id());
+                       }
 
                        new_routes.push_back (track);
                        ret.push_back (track);
@@ -1893,33 +1945,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
        return ret;
 }
 
-void
-Session::set_remote_control_ids ()
-{
-       RemoteModel m = Config->get_remote_model();
-       bool emit_signal = false;
-
-       boost::shared_ptr<RouteList> r = routes.reader ();
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (MixerOrdered == m) {
-                       int32_t order = (*i)->order_key(N_("signal"));
-                       (*i)->set_remote_control_id (order+1, false);
-                       emit_signal = true;
-               } else if (EditorOrdered == m) {
-                       int32_t order = (*i)->order_key(N_("editor"));
-                       (*i)->set_remote_control_id (order+1, false);
-                       emit_signal = true;
-               } else if (UserOrdered == m) {
-                       //do nothing ... only changes to remote id's are initiated by user
-               }
-       }
-
-       if (emit_signal) {
-               Route::RemoteControlIDChange();
-       }
-}
-
 /** Caller must not hold process lock.
  *  @param name_template string to use for the start of the name, or "" to use "Bus".
  */
@@ -1930,9 +1955,6 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
        uint32_t bus_id = 0;
        string port;
        RouteList ret;
-       uint32_t control_id;
-
-       control_id = next_control_id ();
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
        
@@ -1953,7 +1975,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,8 +1996,9 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                        if (route_group) {
                                route_group->add (bus);
                        }
-                       bus->set_remote_control_id (control_id);
-                       ++control_id;
+                       if (Config->get_remote_model() == UserOrdered) {
+                               bus->set_remote_control_id (next_control_id());
+                       }
 
                        bus->add_internal_return ();
 
@@ -2068,7 +2091,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();
@@ -2110,6 +2133,7 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
 {
         ChanCount existing_inputs;
         ChanCount existing_outputs;
+       uint32_t order = next_control_id();
 
         count_existing_track_channels (existing_inputs, existing_outputs);
 
@@ -2140,7 +2164,6 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
                r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this, _1));
                r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2));
                r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1));
-               r->order_key_changed.connect_same_thread (*this, boost::bind (&Session::route_order_key_changed, this));
 
                if (r->is_master()) {
                        _master_out = r;
@@ -2166,12 +2189,30 @@ 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);
                }
+
+               /* order keys are a GUI responsibility but we need to set up
+                  reasonable defaults because they also affect the remote control
+                  ID in most situations.
+               */
+               
+               if (!r->has_order_key (EditorSort)) {
+                       if (r->is_hidden()) {
+                               /* use an arbitrarily high value */
+                               r->set_order_key (EditorSort, UINT_MAX);
+                               r->set_order_key (MixerSort, UINT_MAX);
+                       } else {
+                               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("while adding, set %1 to order key %2\n", r->name(), order));
+                               r->set_order_key (EditorSort, order);
+                               r->set_order_key (MixerSort, order);
+                               order++;
+                       }
+               }
        }
 
        if (_monitor_out && IO::connecting_legal) {
 
                {
-                       Glib::Mutex::Lock lm (_engine.process_lock());          
+                       Glib::Threads::Mutex::Lock lm (_engine.process_lock());         
                        
                        for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
                                if ((*x)->is_monitor()) {
@@ -2194,7 +2235,6 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
        }
 
        RouteAdded (new_routes); /* EMIT SIGNAL */
-       Route::RemoteControlIDChange (); /* EMIT SIGNAL */
 }
 
 void
@@ -2362,8 +2402,6 @@ Session::remove_route (boost::shared_ptr<Route> route)
 
        route->drop_references ();
 
-       sync_order_keys (N_("session"));
-
        Route::RemoteControlIDChange(); /* EMIT SIGNAL */
 
        /* save the new state of the world */
@@ -2845,7 +2883,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) {
 
@@ -2891,7 +2929,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());
                }
@@ -2944,7 +2982,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);
        }
 
@@ -2952,6 +2990,14 @@ Session::add_source (boost::shared_ptr<Source> source)
 
                /* yay, new source */
 
+               boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (source);
+               
+               if (fs) {
+                       if (!fs->within_session()) {
+                               ensure_search_path_includes (Glib::path_get_dirname (fs->path()), fs->type());
+                       }
+               }
+               
                set_dirty();
 
                boost::shared_ptr<AudioFileSource> afs;
@@ -2981,7 +3027,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);
@@ -3001,7 +3047,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;
 
@@ -3015,7 +3061,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
@@ -3032,7 +3078,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
@@ -3162,7 +3208,7 @@ Session::new_source_path_from_name (DataType type, const string& name)
 
        SessionDirectory sdir(get_best_session_directory_for_new_source());
 
-       sys::path p;
+       std::string p;
        if (type == DataType::AUDIO) {
                p = sdir.sound_path();
        } else if (type == DataType::MIDI) {
@@ -3172,16 +3218,13 @@ Session::new_source_path_from_name (DataType type, const string& name)
                return "";
        }
 
-       p /= name;
-       return p.to_string();
+       return Glib::build_filename (p, name);
 }
 
 string
 Session::peak_path (string base) const
 {
-       sys::path peakfile_path(_session_dir->peak_path());
-       peakfile_path /= base + peakfile_suffix;
-       return peakfile_path.to_string();
+       return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix);
 }
 
 /** Return a unique name based on \a base for a new internal audio source */
@@ -3245,7 +3288,7 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
 
                        SessionDirectory sdir((*i).path);
 
-                       string spath = sdir.sound_path().to_string();
+                       string spath = sdir.sound_path();
 
                        /* note that we search *without* the extension so that
                           we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
@@ -3308,12 +3351,11 @@ Session::new_midi_source_name (const string& base)
 
                        SessionDirectory sdir((*i).path);
 
-                       sys::path p = sdir.midi_path();
-                       p /= legalized;
+                       std::string p = Glib::build_filename (sdir.midi_path(), legalized);
 
-                       snprintf (buf, sizeof(buf), "%s-%u.mid", p.to_string().c_str(), cnt);
+                       snprintf (buf, sizeof(buf), "%s-%u.mid", p.c_str(), cnt);
 
-                       if (sys::exists (buf)) {
+                       if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
                                existing++;
                        }
                }
@@ -3449,7 +3491,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::
        if (b->is_monitor()) {
                return false;
        }
-       return a->order_key(N_("signal")) < b->order_key(N_("signal"));
+       return a->order_key (MixerSort) < b->order_key (MixerSort);
 }
 
 bool
@@ -3495,9 +3537,18 @@ Session::graph_reordered ()
        }
 }
 
-framecnt_t
+/** @return Number of frames that there is disk space available to write,
+ *  if known.
+ */
+boost::optional<framecnt_t>
 Session::available_capture_duration ()
 {
+       Glib::Threads::Mutex::Lock lm (space_lock);
+
+       if (_total_free_4k_blocks_uncertain) {
+               return boost::optional<framecnt_t> ();
+       }
+       
        float sample_bytes_on_disk = 4.0; // keep gcc happy
 
        switch (config.get_native_file_data_format()) {
@@ -3778,56 +3829,6 @@ Session::unmark_insert_id (uint32_t id)
        }
 }
 
-
-/* Named Selection management */
-
-boost::shared_ptr<NamedSelection>
-Session::named_selection_by_name (string name)
-{
-       Glib::Mutex::Lock lm (named_selection_lock);
-       for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) {
-               if ((*i)->name == name) {
-                       return *i;
-               }
-       }
-       return boost::shared_ptr<NamedSelection>();
-}
-
-void
-Session::add_named_selection (boost::shared_ptr<NamedSelection> named_selection)
-{
-       {
-               Glib::Mutex::Lock lm (named_selection_lock);
-               named_selections.insert (named_selections.begin(), named_selection);
-       }
-
-       set_dirty();
-
-       NamedSelectionAdded (); /* EMIT SIGNAL */
-}
-
-void
-Session::remove_named_selection (boost::shared_ptr<NamedSelection> named_selection)
-{
-       bool removed = false;
-
-       {
-               Glib::Mutex::Lock lm (named_selection_lock);
-
-               NamedSelectionList::iterator i = find (named_selections.begin(), named_selections.end(), named_selection);
-
-               if (i != named_selections.end()) {
-                       named_selections.erase (i);
-                       set_dirty();
-                       removed = true;
-               }
-       }
-
-       if (removed) {
-                NamedSelectionRemoved (); /* EMIT SIGNAL */
-       }
-}
-
 void
 Session::reset_native_file_format ()
 {
@@ -3911,7 +3912,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
        framepos_t to_do;
        BufferSet buffers;
        SessionDirectory sdir(get_best_session_directory_for_new_source ());
-       const string sound_dir = sdir.sound_path().to_string();
+       const string sound_dir = sdir.sound_path();
        framepos_t len = end - start;
        bool need_block_size_reset = false;
        string ext;
@@ -4076,6 +4077,12 @@ Session::gain_automation_buffer() const
        return ProcessThread::gain_automation_buffer ();
 }
 
+gain_t*
+Session::send_gain_automation_buffer() const
+{
+       return ProcessThread::send_gain_automation_buffer ();
+}
+
 pan_t**
 Session::pan_automation_buffer() const
 {
@@ -4136,31 +4143,6 @@ Session::add_automation_list(AutomationList *al)
        automation_lists[al->id()] = al;
 }
 
-void
-Session::sync_order_keys (std::string const & base)
-{
-       if (deletion_in_progress()) {
-               return;
-       }
-
-       if (!Config->get_sync_all_route_ordering()) {
-               /* leave order keys as they are */
-               return;
-       }
-
-       boost::shared_ptr<RouteList> r = routes.reader ();
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               (*i)->sync_order_keys (base);
-       }
-
-       Route::SyncOrderKeys (base); // EMIT SIGNAL
-
-       /* this might not do anything */
-
-       set_remote_control_ids ();
-}
-
 /** @return true if there is at least one record-enabled track, otherwise false */
 bool
 Session::have_rec_enabled_track () const
@@ -4236,18 +4218,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
 {
@@ -4312,13 +4282,6 @@ Session::add_session_range_location (framepos_t start, framepos_t end)
        _locations->add (_session_range_location);
 }
 
-/** Called when one of our routes' order keys has changed */
-void
-Session::route_order_key_changed ()
-{
-       RouteOrderKeyChanged (); /* EMIT SIGNAL */
-}
-
 void
 Session::step_edit_status_change (bool yn)
 {
@@ -4391,10 +4354,10 @@ Session::source_search_path (DataType type) const
        if (session_dirs.size() == 1) {
                switch (type) {
                case DataType::AUDIO:
-                       s.push_back ( _session_dir->sound_path().to_string());
+                       s.push_back ( _session_dir->sound_path());
                        break;
                case DataType::MIDI:
-                       s.push_back (_session_dir->midi_path().to_string());
+                       s.push_back (_session_dir->midi_path());
                        break;
                }
        } else {
@@ -4402,15 +4365,22 @@ Session::source_search_path (DataType type) const
                        SessionDirectory sdir (i->path);
                        switch (type) {
                        case DataType::AUDIO:
-                               s.push_back (sdir.sound_path().to_string());
+                               s.push_back (sdir.sound_path());
                                break;
                        case DataType::MIDI:
-                               s.push_back (sdir.midi_path().to_string());
+                               s.push_back (sdir.midi_path());
                                break;
                        }
                }
        }
 
+       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)) {
+                       s.push_back (sound_path_2X);
+               }
+       }
+
        /* now check the explicit (possibly user-specified) search path
         */
 
@@ -4470,7 +4440,7 @@ Session::ensure_search_path_includes (const string& path, DataType type)
                search_path = config.get_midi_search_path ();
                break;
        }
-       
+
        split (search_path, dirs, ':');
 
        for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
@@ -4480,7 +4450,7 @@ Session::ensure_search_path_includes (const string& path, DataType type)
 
                   On Windows, I think we could just do if (*i == path) here.
                */
-               if (inodes_same (*i, path)) {
+               if (PBD::equivalent_paths (*i, path)) {
                        return;
                }
        }
@@ -4616,7 +4586,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);
         }
@@ -4736,5 +4706,103 @@ Session::session_name_is_legal (const string& path)
 uint32_t 
 Session::next_control_id () const
 {
-       return ntracks() + nbusses() + 1;
+       int subtract = 0;
+
+       /* the monitor bus remote ID is in a different
+        * "namespace" than regular routes. its existence doesn't
+        * affect normal (low) numbered routes.
+        */
+
+       if (_monitor_out) {
+               subtract++;
+       }
+
+       return nroutes() - subtract;
+}
+
+void
+Session::notify_remote_id_change ()
+{
+       if (deletion_in_progress()) {
+               return;
+       }
+
+       switch (Config->get_remote_model()) {
+       case MixerSort:
+       case EditorSort:
+               Route::RemoteControlIDChange (); /* EMIT SIGNAL */
+               break;
+       default:
+               break;
+       }
+}
+
+void
+Session::sync_order_keys (RouteSortOrderKey sort_key_changed)
+{
+       if (deletion_in_progress()) {
+               return;
+       }
+
+       /* tell everyone that something has happened to the sort keys
+          and let them sync up with the change(s)
+          this will give objects that manage the sort order keys the
+          opportunity to keep them in sync if they wish to.
+       */
+
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("Sync Order Keys, based on %1\n", enum_2_string (sort_key_changed)));
+
+       Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */
+
+       DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n");
+}
+
+bool
+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
+       }
 }