Merge branch 'cairocanvas' of git.ardour.org:ardour/ardour into cairocanvas
[ardour.git] / libs / ardour / session.cc
index 687469e5a577783732758153074f2ef268e30fb1..05fa883a9d3b02343d8cec6553ad1f1893021e8d 100644 (file)
@@ -44,8 +44,8 @@
 #include "pbd/stacktrace.h"
 #include "pbd/file_utils.h"
 #include "pbd/convert.h"
-#include "pbd/strsplit.h"
 #include "pbd/unwind.h"
+#include "pbd/search_path.h"
 
 #include "ardour/amp.h"
 #include "ardour/analyser.h"
@@ -68,6 +68,7 @@
 #include "ardour/filename_extensions.h"
 #include "ardour/graph.h"
 #include "ardour/midiport_manager.h"
+#include "ardour/scene_changer.h"
 #include "ardour/midi_track.h"
 #include "ardour/midi_ui.h"
 #include "ardour/operations.h"
@@ -88,6 +89,7 @@
 #include "ardour/smf_source.h"
 #include "ardour/source_factory.h"
 #include "ardour/speakers.h"
+#include "ardour/track.h"
 #include "ardour/utils.h"
 
 #include "midi++/port.h"
@@ -107,7 +109,7 @@ using namespace PBD;
 
 bool Session::_disable_all_loaded_plugins = false;
 
-PBD::Signal0<int> Session::AudioEngineSetupRequired;
+PBD::Signal1<int,uint32_t> Session::AudioEngineSetupRequired;
 PBD::Signal1<void,std::string> Session::Dialog;
 PBD::Signal0<int> Session::AskAboutPendingState;
 PBD::Signal2<int, framecnt_t, framecnt_t> Session::AskAboutSampleRateMismatch;
@@ -132,123 +134,197 @@ Session::Session (AudioEngine &eng,
                   const string& snapshot_name,
                   BusProfile* bus_profile,
                   string mix_template)
-       : _engine (eng)
+       : playlists (new SessionPlaylists)
+       , _engine (eng)
+       , process_function (&Session::process_with_events)
+       , waiting_for_sync_offset (false)
+       , _base_frame_rate (0)
+       , _current_frame_rate (0)
+       , _nominal_frame_rate (0)
+       , transport_sub_state (0)
+       , _record_status (Disabled)
+       , _transport_frame (0)
+       , _session_range_location (0)
+       , _slave (0)
+       , _silent (false)
+       , _transport_speed (0)
+       , _default_transport_speed (1.0)
+       , _last_transport_speed (0)
        , _target_transport_speed (0.0)
+       , auto_play_legal (false)
+       , _last_slave_transport_frame (0)
+       , maximum_output_latency (0)
        , _requested_return_frame (-1)
+       , current_block_size (0)
+       , _worst_output_latency (0)
+       , _worst_input_latency (0)
+       , _worst_track_latency (0)
+       , _have_captured (false)
+       , _meter_hold (0)
+       , _meter_falloff (0)
+       , _non_soloed_outs_muted (false)
+       , _listen_cnt (0)
+       , _solo_isolated_cnt (0)
+       , _writable (false)
+       , _was_seamless (Config->get_seamless_loop ())
        , _under_nsm_control (false)
+       , delta_accumulator_cnt (0)
+       , average_slave_delta (1800) // !!! why 1800 ???
+       , average_dir (0)
+       , have_first_delta_accumulator (false)
+       , _slave_state (Stopped)
+       , post_export_sync (false)
+       , post_export_position (0)
+       , _exporting (false)
+       , _export_started (false)
+       , _export_rolling (false)
+       , _pre_export_mmc_enabled (false)
+       , _name (snapshot_name)
+       , _is_new (true)
+       , _send_qf_mtc (false)
+       , _pframes_since_last_mtc (0)
+       , session_midi_feedback (0)
+       , play_loop (false)
+       , loop_changing (false)
+       , last_loopend (0)
        , _session_dir (new SessionDirectory (fullpath))
+       , _current_snapshot_name (snapshot_name)          
        , state_tree (0)
+       , state_was_pending (false)
        , _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading))
+       , _last_roll_location (0)
+       , _last_roll_or_reversal_location (0)
+       , _last_record_location (0)
+       , pending_locate_roll (false)
+       , pending_locate_frame (0)
+       , pending_locate_flush (false)
+       , pending_abort (false)
+       , pending_auto_loop (false)
        , _butler (new Butler (*this))
        , _post_transport_work (0)
+       ,  cumulative_rf_motion (0)
+       , rf_scale (1.0)
+       , _locations (new Locations (*this))
+       , step_speed (0)
+       , outbound_mtc_timecode_frame (0)
+       , next_quarter_frame_to_send (-1)
+       , _frames_per_timecode_frame (0)
+       , _frames_per_hour (0)
+       , _timecode_frames_per_hour (0)
+       , last_timecode_valid (false)
+       , last_timecode_when (0)
        , _send_timecode_update (false)
+       , ltc_encoder (0)
        , ltc_enc_buf(0)
+       , ltc_buf_off (0)
+       , ltc_buf_len (0)
+       , ltc_speed (0)
+       , ltc_enc_byte (0)
+       , ltc_enc_pos (0)
+       , ltc_enc_cnt (0)
+       , ltc_enc_off (0)
+       , restarting (false)
+       , ltc_prev_cycle (0)
+       , ltc_timecode_offset (0)
+       , ltc_timecode_negative_offset (false)
+       , midi_control_ui (0)
+       , _tempo_map (0)
        , _all_route_group (new RouteGroup (*this, "all"))
        , routes (new RouteList)
+       , _adding_routes_in_progress (false)
+       , destructive_index (0)
+       , solo_update_disabled (false)
+       , default_fade_steepness (0)
+       , default_fade_msecs (0)
        , _total_free_4k_blocks (0)
        , _total_free_4k_blocks_uncertain (false)
+       , no_questions_about_missing_files (false)
+       , _playback_load (0)
+       , _capture_load (0)
        , _bundles (new BundleList)
        , _bundle_xml_node (0)
        , _current_trans (0)
+       , _clicking (false)
        , click_data (0)
        , click_emphasis_data (0)
-       , main_outs (0)
-       , _have_rec_enabled_track (false)
-       , _suspend_timecode_transmission (0)
-       , _non_soloed_outs_muted (false)
-       , _listen_cnt (0)
-       , _solo_isolated_cnt (0)
-       , _transport_speed (0)
-       , _default_transport_speed (1.0)
-       , _last_transport_speed (0)
-       , auto_play_legal (false)
-       , transport_sub_state (0)
-       , _transport_frame (0)
-       , _session_range_location (0)
-       , loop_changing (false)
-       , play_loop (false)
-       , have_looped (false)
-       , _last_roll_location (0)
-       , _last_roll_or_reversal_location (0)
-       , _last_record_location (0)
-       , pending_locate_frame (0)
-       , pending_locate_roll (false)
-       , pending_locate_flush (false)
-       , state_was_pending (false)
-       , outbound_mtc_timecode_frame (0)
-       , next_quarter_frame_to_send (-1)
-       , current_block_size (0)
-       , solo_update_disabled (false)
-       , _have_captured (false)
-       , _worst_output_latency (0)
-       , _worst_input_latency (0)
-       , _worst_track_latency (0)
-       , _was_seamless (Config->get_seamless_loop ())
-       , _slave (0)
-       , _send_qf_mtc (false)
-       , _pframes_since_last_mtc (0)
+       , click_length (0)
+       , click_emphasis_length (0)
+       , _clicks_cleared (0)
        , _play_range (false)
-       , _exporting (false)
-       , pending_abort (false)
-       , _adding_routes_in_progress (false)
-       , destructive_index (0)
+       , main_outs (0)
        , first_file_data_format_reset (true)
        , first_file_header_format_reset (true)
-       , post_export_sync (false)
-       , midi_control_ui (0)
+       , have_looped (false)
+       , _have_rec_enabled_track (false)
        , _step_editors (0)
-       , no_questions_about_missing_files (false)
+       , _suspend_timecode_transmission (0)
        ,  _speakers (new Speakers)
-       , _clicks_cleared (0)
+       , _order_hint (0)
        , ignore_route_processor_changes (false)
-       , _pre_export_mmc_enabled (false)
-       , _locations (new Locations (*this))
-       , ltc_encoder (0)
-       , playlists (new SessionPlaylists)
-       , _name (snapshot_name)
-       , _current_snapshot_name (snapshot_name)
-       , step_speed (0.0)
-       , click_length (0)
-       , click_emphasis_length (0)
-       , _clicking (false)
-       , process_function (&Session::process_with_events)
-       , last_timecode_when (0)
-       , last_timecode_valid (false)
-       , average_slave_delta (1800) // !!! why 1800 ???
-       , have_first_delta_accumulator (false)
-       , delta_accumulator_cnt (0)
-       , _slave_state (Stopped)
+       , _scene_changer (0)
+       , _midi_ports (0)
+       , _mmc (0)
 {
-       if (_engine.current_backend() == 0 || _engine.setup_required()) {
-               boost::optional<int> r = AudioEngineSetupRequired ();
-               if (r.get_value_or (-1) != 0) {
-                       throw failed_constructor();
-               }
-       }
-
-       if (!_engine.connected()) {
-               throw failed_constructor();
-       }
-
-       first_stage_init (fullpath, snapshot_name);
+       uint32_t sr = 0;
 
+       pre_engine_init (fullpath);
+       
        if (_is_new) {
+               if (ensure_engine (sr)) {
+                       destroy ();
+                       throw failed_constructor ();
+               }
+
                if (create (mix_template, bus_profile)) {
                        destroy ();
                        throw failed_constructor ();
                }
+
+               /* if a mix template was provided, then ::create() will
+                * have copied it into the session and we need to load it
+                * so that we have the state ready for ::set_state()
+                * after the engine is started.
+                *
+                * Note that we do NOT try to get the sample rate from
+                * the template at this time, though doing so would
+                * be easy if we decided this was an appropriate part
+                * of a template.
+                */
+
+               if (!mix_template.empty() && load_state (_current_snapshot_name)) {
+                       throw failed_constructor ();
+               }
+
        } else {
+
                if (load_state (_current_snapshot_name)) {
                        throw failed_constructor ();
                }
+       
+               /* try to get sample rate from XML state so that we
+                * can influence the SR if we set up the audio
+                * engine.
+                */
+
+               if (state_tree) {
+                       const XMLProperty* prop;
+                       if ((prop = state_tree->root()->property (X_("sample-rate"))) != 0) {           
+                               sr = atoi (prop->value());
+                       }
+               }
+
+               if (ensure_engine (sr)) {
+                       destroy ();
+                       throw failed_constructor ();
+               }
        }
 
-       if (second_stage_init ()) {
+       if (post_engine_init ()) {
                destroy ();
                throw failed_constructor ();
        }
 
-       store_recent_sessions(_name, _path);
+       store_recent_sessions (_name, _path);
 
        bool was_dirty = dirty();
 
@@ -265,6 +341,16 @@ Session::Session (AudioEngine &eng,
        EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1));
 
        _is_new = false;
+
+       /* hook us up to the engine since we are now completely constructed */
+
+       BootMessage (_("Connect to engine"));
+
+       _engine.set_session (this);
+       _engine.reset_timebase ();
+
+       BootMessage (_("Session loading complete"));
+
 }
 
 Session::~Session ()
@@ -275,6 +361,81 @@ Session::~Session ()
        destroy ();
 }
 
+int
+Session::ensure_engine (uint32_t desired_sample_rate)
+{
+       if (_engine.current_backend() == 0) {
+               /* backend is unknown ... */
+               boost::optional<int> r = AudioEngineSetupRequired (desired_sample_rate);
+               if (r.get_value_or (-1) != 0) {
+                       return -1;
+               }
+       } else if (_engine.setup_required()) {
+               /* backend is known, but setup is needed */
+               boost::optional<int> r = AudioEngineSetupRequired (desired_sample_rate);
+               if (r.get_value_or (-1) != 0) {
+                       return -1;
+               }
+       } else if (!_engine.running()) {
+               if (_engine.start()) {
+                       return -1;
+               }
+       }
+
+       /* at this point the engine should be running
+       */
+
+       if (!_engine.running()) {
+               return -1;
+       }
+
+       return immediately_post_engine ();
+
+}
+
+int
+Session::immediately_post_engine ()
+{
+       /* Do various initializations that should take place directly after we
+        * know that the engine is running, but before we either create a
+        * session or set state for an existing one.
+        */
+        
+       if (how_many_dsp_threads () > 1) {
+               /* For now, only create the graph if we are using >1 DSP threads, as
+                  it is a bit slower than the old code with 1 thread.
+               */
+               _process_graph.reset (new Graph (*this));
+       }
+
+       /* every time we reconnect, recompute worst case output latencies */
+
+       _engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
+
+       if (synced_to_engine()) {
+               _engine.transport_stop ();
+       }
+
+       if (config.get_jack_time_master()) {
+               _engine.transport_locate (_transport_frame);
+       }
+
+       try {
+               BootMessage (_("Set up LTC"));
+               setup_ltc ();
+               BootMessage (_("Set up Click"));
+               setup_click ();
+               BootMessage (_("Set up standard connections"));
+               setup_bundles ();
+       }
+
+       catch (failed_constructor& err) {
+               return -1;
+       }
+
+       return 0;
+}
+
 void
 Session::destroy ()
 {
@@ -368,13 +529,16 @@ Session::destroy ()
        }
        routes.flush ();
 
-       DEBUG_TRACE (DEBUG::Destruction, "delete sources\n");
-       for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
-               DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for source %1 ; pre-ref = %2\n", i->second->name(), i->second.use_count()));
-               i->second->drop_references ();
-       }
+       {
+               DEBUG_TRACE (DEBUG::Destruction, "delete sources\n");
+               Glib::Threads::Mutex::Lock lm (source_lock);
+               for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
+                       DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for source %1 ; pre-ref = %2\n", i->second->name(), i->second.use_count()));
+                       i->second->drop_references ();
+               }
 
-       sources.clear ();
+               sources.clear ();
+       }
 
        DEBUG_TRACE (DEBUG::Destruction, "delete route groups\n");
        for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
@@ -385,9 +549,11 @@ Session::destroy ()
        /* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
        playlists.reset ();
 
-       delete _mmc;
-       delete _midi_ports;
-       delete _locations;
+       delete _scene_changer; _scene_changer = 0;
+
+       delete _mmc; _mmc = 0;
+       delete _midi_ports; _midi_ports = 0;
+       delete _locations; _locations = 0;
 
        DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
 
@@ -397,135 +563,112 @@ Session::destroy ()
 }
 
 void
-Session::when_engine_running ()
+Session::setup_ltc ()
 {
-       string first_physical_output;
-
-       BootMessage (_("Set block size and sample rate"));
-
-       set_block_size (_engine.samples_per_cycle());
-       set_frame_rate (_engine.sample_rate());
-
-       BootMessage (_("Using configuration"));
-
-       boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
-       boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
-
-       Config->map_parameters (ff);
-       config.map_parameters (ft);
-
-       /* every time we reconnect, recompute worst case output latencies */
-
-       _engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
-
-       if (synced_to_jack()) {
-               _engine.transport_stop ();
+       XMLNode* child = 0;
+       
+       _ltc_input.reset (new IO (*this, X_("LTC In"), IO::Input));
+       _ltc_output.reset (new IO (*this, X_("LTC Out"), IO::Output));
+       
+       if (state_tree && (child = find_named_node (*state_tree->root(), X_("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 (config.get_jack_time_master()) {
-               _engine.transport_locate (_transport_frame);
+       
+       if (state_tree && (child = find_named_node (*state_tree->root(), X_("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 (X_("LTC-in"));
+       _ltc_output->nth (0)->set_name (X_("LTC-out"));
+}
 
+void
+Session::setup_click ()
+{
        _clicking = false;
+       _click_io.reset (new ClickIO (*this, X_("Click")));
+       _click_gain.reset (new Amp (*this));
+       _click_gain->activate ();
+       if (state_tree) {
+               setup_click_state (state_tree->root());
+       } else {
+               setup_click_state (0);
+       }
+}
 
-       try {
-               XMLNode* child = 0;
+void
+Session::setup_click_state (const XMLNode* node)
+{      
+       const XMLNode* child = 0;
+       
+       if (node && (child = find_named_node (*node, "Click")) != 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 ();
-               }
+               /* existing state for Click */
+               int c = 0;
 
-               if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) {
-                       _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
+               if (Stateful::loading_state_version < 3000) {
+                       c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
                } 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));
-               _click_gain->activate ();
-
-               if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
-
-                       /* existing state for Click */
-                       int c = 0;
-
-                       if (Stateful::loading_state_version < 3000) {
-                               c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
-                       } else {
-                               const XMLNodeList& children (child->children());
-                               XMLNodeList::const_iterator i = children.begin();
-                               if ((c = _click_io->set_state (**i, Stateful::loading_state_version)) == 0) {
-                                       ++i;
-                                       if (i != children.end()) {
-                                               c = _click_gain->set_state (**i, Stateful::loading_state_version);
-                                       }
+                       const XMLNodeList& children (child->children());
+                       XMLNodeList::const_iterator i = children.begin();
+                       if ((c = _click_io->set_state (**i, Stateful::loading_state_version)) == 0) {
+                               ++i;
+                               if (i != children.end()) {
+                                       c = _click_gain->set_state (**i, Stateful::loading_state_version);
                                }
                        }
+               }
                        
-                       if (c == 0) {
-                               _clicking = Config->get_clicking ();
+               if (c == 0) {
+                       _clicking = Config->get_clicking ();
 
-                       } else {
+               } else {
 
-                               error << _("could not setup Click I/O") << endmsg;
-                               _clicking = false;
-                       }
+                       error << _("could not setup Click I/O") << endmsg;
+                       _clicking = false;
+               }
 
 
-               } else {
+       } else {
 
-                       /* default state for Click: dual-mono to first 2 physical outputs */
+               /* default state for Click: dual-mono to first 2 physical outputs */
 
-                       vector<string> outs;
-                       _engine.get_physical_outputs (DataType::AUDIO, outs);
+               vector<string> outs;
+               _engine.get_physical_outputs (DataType::AUDIO, outs);
 
-                       for (uint32_t physport = 0; physport < 2; ++physport) {
-                               if (outs.size() > physport) {
-                                       if (_click_io->add_port (outs[physport], this)) {
-                                               // relax, even though its an error
-                                       }
+               for (uint32_t physport = 0; physport < 2; ++physport) {
+                       if (outs.size() > physport) {
+                               if (_click_io->add_port (outs[physport], this)) {
+                                       // relax, even though its an error
                                }
                        }
-
-                       if (_click_io->n_ports () > ChanCount::ZERO) {
-                               _clicking = Config->get_clicking ();
-                       }
                }
-       }
-
-       catch (failed_constructor& err) {
-               error << _("cannot setup Click I/O") << endmsg;
-       }
 
-       BootMessage (_("Compute I/O Latencies"));
-
-       if (_clicking) {
-               // XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO?
+               if (_click_io->n_ports () > ChanCount::ZERO) {
+                       _clicking = Config->get_clicking ();
+               }
        }
+}
 
-       BootMessage (_("Set up standard connections"));
-
+void
+Session::setup_bundles ()
+{
        vector<string> inputs[DataType::num_types];
        vector<string> outputs[DataType::num_types];
        for (uint32_t i = 0; i < DataType::num_types; ++i) {
@@ -624,54 +767,6 @@ Session::when_engine_running ()
                add_bundle (c);
        }
 
-       BootMessage (_("Setup signal flow and plugins"));
-
-       /* Reset all panners */
-
-       Delivery::reset_panners ();
-
-       /* this will cause the CPM to instantiate any protocols that are in use
-        * (or mandatory), which will pass it this Session, and then call
-        * set_state() on each instantiated protocol to match stored state.
-        */
-
-       ControlProtocolManager::instance().set_session (this);
-
-       /* This must be done after the ControlProtocolManager set_session above,
-          as it will set states for ports which the ControlProtocolManager creates.
-       */
-
-       // XXX set state of MIDI::Port's
-       // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
-
-       /* And this must be done after the MIDI::Manager::set_port_states as
-        * it will try to make connections whose details are loaded by set_port_states.
-        */
-
-       hookup_io ();
-
-       /* Let control protocols know that we are now all connected, so they
-        * could start talking to surfaces if they want to.
-        */
-
-       ControlProtocolManager::instance().midi_connectivity_established ();
-
-       if (_is_new && !no_auto_connect()) {
-               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
-               auto_connect_master_bus ();
-       }
-
-       _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
-
-        /* update latencies */
-
-        initialize_latencies ();
-
-       /* hook us up to the engine */
-
-       BootMessage (_("Connect to engine"));
-       _engine.set_session (this);
-       _engine.reset_timebase ();
 }
 
 void
@@ -718,6 +813,12 @@ Session::remove_monitor_section ()
        /* force reversion to Solo-In-Place */
        Config->set_solo_control_is_listen_control (false);
 
+       /* if we are auditioning, cancel it ... this is a workaround
+          to a problem (auditioning does not execute the process graph,
+          which is needed to remove routes when using >1 core for processing)
+       */
+       cancel_audition ();
+
        {
                /* Hold process lock while doing this so that we don't hear bits and
                 * pieces of audio as we work on each route.
@@ -748,6 +849,10 @@ Session::remove_monitor_section ()
 
        remove_route (_monitor_out);
        auto_connect_master_bus ();
+
+       if (auditioner) {
+               auditioner->connect ();
+       }
 }
 
 void
@@ -833,14 +938,14 @@ Session::add_monitor_section ()
                        
                        /* Monitor bus is audio only */
 
-                       uint32_t mod = n_physical_outputs.get (DataType::AUDIO);
-                       uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
                        vector<string> outputs[DataType::num_types];
 
                        for (uint32_t i = 0; i < DataType::num_types; ++i) {
                                _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
                        }
-                       
+
+                       uint32_t mod = outputs[DataType::AUDIO].size();
+                       uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
                        
                        if (mod != 0) {
                                
@@ -892,6 +997,10 @@ Session::add_monitor_section ()
                        (*x)->enable_monitor_send ();
                }
        }
+
+       if (auditioner) {
+               auditioner->connect ();
+       }
 }
 
 void
@@ -1344,7 +1453,7 @@ Session::audible_frame () const
                offset = current_block_size;
        }
 
-       if (synced_to_jack()) {
+       if (synced_to_engine()) {
                tf = _engine.transport_frame();
        } else {
                tf = _transport_frame;
@@ -1404,6 +1513,7 @@ Session::set_frame_rate (framecnt_t frames_per_second)
        */
 
        _base_frame_rate = frames_per_second;
+       _nominal_frame_rate = frames_per_second;
 
        sync_time_vars();
 
@@ -1612,7 +1722,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
                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 (MixerSort)));
+                                                                  (*i)->name(), (*i)->order_key ()));
                }
 #endif
 
@@ -1897,9 +2007,9 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing
                        for (uint32_t i = output_start.get(*t); i < route->n_outputs().get(*t); ++i) {
                                string port;
 
-                               if ((*t) == DataType::MIDI || Config->get_output_auto_connect() & AutoConnectPhysical) {
+                               if ((*t) == DataType::MIDI && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
                                        port = physoutputs[(out_offset.get(*t) + i) % nphysical_out];
-                               } else if ((*t) == DataType::AUDIO && Config->get_output_auto_connect() & AutoConnectMaster) {
+                               } else if ((*t) == DataType::AUDIO && (Config->get_output_auto_connect() & AutoConnectMaster)) {
                                         /* master bus is audio only */
                                        if (_master_out && _master_out->n_inputs().get(*t) > 0) {
                                                port = _master_out->input()->ports().port(*t,
@@ -2248,6 +2358,11 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
         ChanCount existing_outputs;
        uint32_t order = next_control_id();
 
+       if (_order_hint != 0) {
+               order = _order_hint;
+               _order_hint = 0;
+       }
+
         count_existing_track_channels (existing_inputs, existing_outputs);
 
        {
@@ -2309,15 +2424,13 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                   ID in most situations.
                */
 
-               if (!r->has_order_key (EditorSort)) {
+               if (!r->has_order_key ()) {
                        if (r->is_auditioner()) {
                                /* use an arbitrarily high value */
-                               r->set_order_key (EditorSort, UINT_MAX);
-                               r->set_order_key (MixerSort, UINT_MAX);
+                               r->set_order_key (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);
+                               r->set_order_key (order);
                                order++;
                        }
                }
@@ -3195,12 +3308,16 @@ Session::source_by_id (const PBD::ID& id)
        return source;
 }
 
-boost::shared_ptr<Source>
-Session::source_by_path_and_channel (const string& path, uint16_t chn)
+boost::shared_ptr<AudioFileSource>
+Session::source_by_path_and_channel (const string& path, uint16_t chn) const
 {
+       /* Restricted to audio files because only audio sources have channel
+          as a property.
+       */
+
        Glib::Threads::Mutex::Lock lm (source_lock);
 
-       for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
+       for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
                boost::shared_ptr<AudioFileSource> afs
                        = boost::dynamic_pointer_cast<AudioFileSource>(i->second);
 
@@ -3208,7 +3325,31 @@ Session::source_by_path_and_channel (const string& path, uint16_t chn)
                        return afs;
                }
        }
-       return boost::shared_ptr<Source>();
+
+       return boost::shared_ptr<AudioFileSource>();
+}
+
+boost::shared_ptr<MidiSource>
+Session::source_by_path (const std::string& path) const
+{
+       /* Restricted to MIDI files because audio sources require a channel
+          for unique identification, in addition to a path.
+       */
+
+       Glib::Threads::Mutex::Lock lm (source_lock);
+
+       for (SourceMap::const_iterator s = sources.begin(); s != sources.end(); ++s) {
+               boost::shared_ptr<MidiSource> ms
+                       = boost::dynamic_pointer_cast<MidiSource>(s->second);
+               boost::shared_ptr<FileSource> fs
+                       = boost::dynamic_pointer_cast<FileSource>(s->second);
+               
+               if (ms && fs && fs->path() == path) {
+                       return ms;
+               }
+       }
+
+       return boost::shared_ptr<MidiSource>();
 }
 
 uint32_t
@@ -3229,111 +3370,6 @@ Session::count_sources_by_origin (const string& path)
        return cnt;
 }
 
-
-string
-Session::change_source_path_by_name (string path, string oldname, string newname, bool destructive)
-{
-       string look_for;
-       string old_basename = PBD::basename_nosuffix (oldname);
-       string new_legalized = legalize_for_path (newname);
-
-       /* note: we know (or assume) the old path is already valid */
-
-       if (destructive) {
-
-               /* destructive file sources have a name of the form:
-
-                   /path/to/Tnnnn-NAME(%[LR])?.wav
-
-                   the task here is to replace NAME with the new name.
-               */
-
-               string dir;
-               string prefix;
-               string::size_type dash;
-
-               dir = Glib::path_get_dirname (path);
-               path = Glib::path_get_basename (path);
-
-               /* '-' is not a legal character for the NAME part of the path */
-
-               if ((dash = path.find_last_of ('-')) == string::npos) {
-                       return "";
-               }
-
-               prefix = path.substr (0, dash);
-
-               path += prefix;
-               path += '-';
-               path += new_legalized;
-               path += native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
-               path = Glib::build_filename (dir, path);
-
-       } else {
-
-               /* non-destructive file sources have a name of the form:
-
-                   /path/to/NAME-nnnnn(%[LR])?.ext
-
-                   the task here is to replace NAME with the new name.
-               */
-
-               string dir;
-               string suffix;
-               string::size_type dash;
-               string::size_type postfix;
-
-               dir = Glib::path_get_dirname (path);
-               path = Glib::path_get_basename (path);
-
-               /* '-' is not a legal character for the NAME part of the path */
-
-               if ((dash = path.find_last_of ('-')) == string::npos) {
-                       return "";
-               }
-
-               suffix = path.substr (dash+1);
-
-               // Suffix is now everything after the dash. Now we need to eliminate
-               // the nnnnn part, which is done by either finding a '%' or a '.'
-
-               postfix = suffix.find_last_of ("%");
-               if (postfix == string::npos) {
-                       postfix = suffix.find_last_of ('.');
-               }
-
-               if (postfix != string::npos) {
-                       suffix = suffix.substr (postfix);
-               } else {
-                       error << "Logic error in Session::change_source_path_by_name(), please report" << endl;
-                       return "";
-               }
-
-               const uint32_t limit = 10000;
-               char buf[PATH_MAX+1];
-
-               for (uint32_t cnt = 1; cnt <= limit; ++cnt) {
-
-                       snprintf (buf, sizeof(buf), "%s-%u%s", newname.c_str(), cnt, suffix.c_str());
-
-                       if (!matching_unsuffixed_filename_exists_in (dir, buf)) {
-                               path = Glib::build_filename (dir, buf);
-                               break;
-                       }
-
-                       path = "";
-               }
-
-               if (path.empty()) {
-                       fatal << string_compose (_("FATAL ERROR! Could not find a suitable version of %1 for a rename"),
-                                                newname) << endl;
-                       /*NOTREACHED*/
-               }
-       }
-
-       return path;
-}
-
 /** Return the full path (in some session directory) for a new within-session source.
  * \a name must be a session-unique name that does not contain slashes
  *         (e.g. as returned by new_*_source_name)
@@ -3437,6 +3473,22 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
                                existing++;
                                break;
                        }
+
+                       /* it is possible that we have the path already
+                        * assigned to a source that has not yet been written
+                        * (ie. the write source for a diskstream). we have to
+                        * check this in order to make sure that our candidate
+                        * path isn't used again, because that can lead to
+                        * two Sources point to the same file with different
+                        * notions of their removability.
+                        */
+
+                       string possible_path = Glib::build_filename (spath, buf);
+
+                       if (source_by_path (possible_path)) {
+                               existing++;
+                               break;
+                       }
                }
 
                if (existing == 0) {
@@ -3466,19 +3518,21 @@ Session::create_audio_source_for_session (size_t n_chans, string const & n, uint
                SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
 }
 
-/** Return a unique name based on \a base for a new internal MIDI source */
+/** Return a unique name based on \a owner_name for a new internal MIDI source */
 string
-Session::new_midi_source_name (const string& base)
+Session::new_midi_source_name (const string& owner_name)
 {
        uint32_t cnt;
        char buf[PATH_MAX+1];
        const uint32_t limit = 10000;
        string legalized;
+       string possible_name;
 
        buf[0] = '\0';
-       legalized = legalize_for_path (base);
+       legalized = legalize_for_path (owner_name);
 
        // Find a "version" of the file name that doesn't exist in any of the possible directories.
+
        for (cnt = 1; cnt <= limit; ++cnt) {
 
                vector<space_and_path>::iterator i;
@@ -3487,12 +3541,17 @@ Session::new_midi_source_name (const string& base)
                for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
 
                        SessionDirectory sdir((*i).path);
+                       
+                       snprintf (buf, sizeof(buf), "%s-%u.mid", legalized.c_str(), cnt);
+                       possible_name = buf;
 
-                       std::string p = Glib::build_filename (sdir.midi_path(), legalized);
-
-                       snprintf (buf, sizeof(buf), "%s-%u.mid", p.c_str(), cnt);
+                       std::string possible_path = Glib::build_filename (sdir.midi_path(), possible_name);
+                       
+                       if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
+                               existing++;
+                       }
 
-                       if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
+                       if (source_by_path (possible_path)) {
                                existing++;
                        }
                }
@@ -3504,37 +3563,64 @@ Session::new_midi_source_name (const string& base)
                if (cnt > limit) {
                        error << string_compose(
                                        _("There are already %1 recordings for %2, which I consider too many."),
-                                       limit, base) << endmsg;
+                                       limit, owner_name) << endmsg;
                        destroy ();
                        throw failed_constructor();
                }
        }
 
-       return Glib::path_get_basename(buf);
+       return possible_name;
 }
 
 
 /** Create a new within-session MIDI source */
 boost::shared_ptr<MidiSource>
-Session::create_midi_source_for_session (Track* track, string const & n)
+Session::create_midi_source_for_session (string const & basic_name)
 {
-       /* try to use the existing write source for the track, to keep numbering sane
-        */
+       std::string name;
 
-       if (track) {
-               /*MidiTrack* mt = dynamic_cast<Track*> (track);
-                 assert (mt);
-               */
+       if (name.empty()) {
+               name = new_midi_source_name (basic_name);
+       }
 
-               list<boost::shared_ptr<Source> > l = track->steal_write_sources ();
+       const string path = new_source_path_from_name (DataType::MIDI, name);
 
-               if (!l.empty()) {
-                       assert (boost::dynamic_pointer_cast<MidiSource> (l.front()));
-                       return boost::dynamic_pointer_cast<MidiSource> (l.front());
-               }
+       return boost::dynamic_pointer_cast<SMFSource> (
+               SourceFactory::createWritable (
+                       DataType::MIDI, *this, path, false, frame_rate()));
+}
+
+/** Create a new within-session MIDI source */
+boost::shared_ptr<MidiSource>
+Session::create_midi_source_by_stealing_name (boost::shared_ptr<Track> track)
+{
+       /* the caller passes in the track the source will be used in,
+          so that we can keep the numbering sane. 
+          
+          Rationale: a track with the name "Foo" that has had N
+          captures carried out so far will ALREADY have a write source
+          named "Foo-N+1.mid" waiting to be used for the next capture.
+          
+          If we call new_midi_source_name() we will get "Foo-N+2". But
+          there is no region corresponding to "Foo-N+1", so when
+          "Foo-N+2" appears in the track, the gap presents the user
+          with odd behaviour - why did it skip past Foo-N+1?
+          
+          We could explain this to the user in some odd way, but
+          instead we rename "Foo-N+1.mid" as "Foo-N+2.mid", and then
+          use "Foo-N+1" here.
+          
+          If that attempted rename fails, we get "Foo-N+2.mid" anyway.
+       */
+       
+       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (track);
+       assert (mt);
+       std::string name = track->steal_write_source_name ();
+
+       if (name.empty()) {
+               return boost::shared_ptr<MidiSource>();
        }
 
-       const string name = new_midi_source_name (n);
        const string path = new_source_path_from_name (DataType::MIDI, name);
 
        return boost::dynamic_pointer_cast<SMFSource> (
@@ -3628,7 +3714,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::
        if (b->is_monitor()) {
                return false;
        }
-       return a->order_key (MixerSort) < b->order_key (MixerSort);
+       return a->order_key () < b->order_key ();
 }
 
 bool
@@ -4490,18 +4576,18 @@ Session::end_time_changed (framepos_t old)
        }
 }
 
-string
+std::vector<std::string>
 Session::source_search_path (DataType type) const
 {
-       vector<string> s;
+       Searchpath sp;
 
        if (session_dirs.size() == 1) {
                switch (type) {
                case DataType::AUDIO:
-                       s.push_back (_session_dir->sound_path());
+                       sp.push_back (_session_dir->sound_path());
                        break;
                case DataType::MIDI:
-                       s.push_back (_session_dir->midi_path());
+                       sp.push_back (_session_dir->midi_path());
                        break;
                }
        } else {
@@ -4509,10 +4595,10 @@ Session::source_search_path (DataType type) const
                        SessionDirectory sdir (i->path);
                        switch (type) {
                        case DataType::AUDIO:
-                               s.push_back (sdir.sound_path());
+                               sp.push_back (sdir.sound_path());
                                break;
                        case DataType::MIDI:
-                               s.push_back (sdir.midi_path());
+                               sp.push_back (sdir.midi_path());
                                break;
                        }
                }
@@ -4521,49 +4607,30 @@ 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);
+                       if (find (sp.begin(), sp.end(), sound_path_2X) == sp.end()) {
+                               sp.push_back (sound_path_2X);
                        }
                }
        }
 
-       /* now check the explicit (possibly user-specified) search path
-        */
-
-       vector<string> dirs;
+       // now check the explicit (possibly user-specified) search path
 
        switch (type) {
        case DataType::AUDIO:
-               split (config.get_audio_search_path (), dirs, ':');
+               sp += Searchpath(config.get_audio_search_path ());
                break;
        case DataType::MIDI:
-               split (config.get_midi_search_path (), dirs, ':');
+               sp += Searchpath(config.get_midi_search_path ());
                break;
        }
 
-       for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
-               if (find (s.begin(), s.end(), *i) == s.end()) {
-                       s.push_back (*i);
-               }
-       }
-       
-       string search_path;
-
-       for (vector<string>::iterator si = s.begin(); si != s.end(); ++si) {
-               if (!search_path.empty()) {
-                       search_path += ':';
-               }
-               search_path += *si;
-       }
-
-       return search_path;
+       return sp;
 }
 
 void
 Session::ensure_search_path_includes (const string& path, DataType type)
 {
-       string search_path;
-       vector<string> dirs;
+       Searchpath sp;
 
        if (path == ".") {
                return;
@@ -4571,16 +4638,14 @@ Session::ensure_search_path_includes (const string& path, DataType type)
 
        switch (type) {
        case DataType::AUDIO:
-               search_path = config.get_audio_search_path ();
+               sp += Searchpath(config.get_audio_search_path ());
                break;
        case DataType::MIDI:
-               search_path = config.get_midi_search_path ();
+               sp += Searchpath (config.get_midi_search_path ());
                break;
        }
 
-       split (search_path, dirs, ':');
-
-       for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
+       for (vector<std::string>::iterator i = sp.begin(); i != sp.end(); ++i) {
                /* No need to add this new directory if it has the same inode as
                   an existing one; checking inode rather than name prevents duplicated
                   directories when we are using symlinks.
@@ -4592,18 +4657,14 @@ Session::ensure_search_path_includes (const string& path, DataType type)
                }
        }
 
-       if (!search_path.empty()) {
-               search_path += ':';
-       }
-
-       search_path += path;
+       sp += path;
 
        switch (type) {
        case DataType::AUDIO:
-               config.set_audio_search_path (search_path);
+               config.set_audio_search_path (sp.to_string());
                break;
        case DataType::MIDI:
-               config.set_midi_search_path (search_path);
+               config.set_midi_search_path (sp.to_string());
                break;
        }
 }
@@ -4865,8 +4926,7 @@ Session::notify_remote_id_change ()
        }
 
        switch (Config->get_remote_model()) {
-       case MixerSort:
-       case EditorSort:
+       case MixerOrdered:
                Route::RemoteControlIDChange (); /* EMIT SIGNAL */
                break;
        default:
@@ -4875,7 +4935,7 @@ Session::notify_remote_id_change ()
 }
 
 void
-Session::sync_order_keys (RouteSortOrderKey sort_key_changed)
+Session::sync_order_keys ()
 {
        if (deletion_in_progress()) {
                return;
@@ -4887,9 +4947,9 @@ Session::sync_order_keys (RouteSortOrderKey sort_key_changed)
           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)));
+       DEBUG_TRACE (DEBUG::OrderKeys, "Sync Order Keys.\n");
 
-       Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */
+       Route::SyncOrderKeys (); /* EMIT SIGNAL */
 
        DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n");
 }