Remove some unused code.
[ardour.git] / libs / ardour / session.cc
index 9a4b4f65ed722f7d591425d3da7401eb2bcb4d46..559ca640620556e2ca8c35f3d4a64a44a2c1b3e1 100644 (file)
@@ -45,6 +45,8 @@
 #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"
 #include "ardour/analyser.h"
 #include "ardour/audio_track.h"
 #include "ardour/audioengine.h"
 #include "ardour/audiofilesource.h"
-#include "ardour/audioplaylist.h"
-#include "ardour/audioregion.h"
 #include "ardour/auditioner.h"
 #include "ardour/buffer_manager.h"
 #include "ardour/buffer_set.h"
 #include "ardour/bundle.h"
 #include "ardour/butler.h"
 #include "ardour/click.h"
-#include "ardour/configuration.h"
 #include "ardour/control_protocol_manager.h"
-#include "ardour/crossfade.h"
-#include "ardour/cycle_timer.h"
 #include "ardour/data_type.h"
 #include "ardour/debug.h"
 #include "ardour/filename_extensions.h"
-#include "ardour/internal_send.h"
-#include "ardour/io_processor.h"
-#include "ardour/midi_diskstream.h"
-#include "ardour/midi_playlist.h"
-#include "ardour/midi_region.h"
+#include "ardour/graph.h"
 #include "ardour/midi_track.h"
 #include "ardour/midi_ui.h"
 #include "ardour/named_selection.h"
-#include "ardour/process_thread.h"
+#include "ardour/operations.h"
 #include "ardour/playlist.h"
+#include "ardour/plugin.h"
 #include "ardour/plugin_insert.h"
-#include "ardour/port_insert.h"
-#include "ardour/processor.h"
+#include "ardour/process_thread.h"
 #include "ardour/rc_configuration.h"
 #include "ardour/recent_sessions.h"
+#include "ardour/region.h"
 #include "ardour/region_factory.h"
-#include "ardour/return.h"
 #include "ardour/route_graph.h"
 #include "ardour/route_group.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
 #include "ardour/session_directory.h"
-#include "ardour/session_directory.h"
-#include "ardour/session_metadata.h"
 #include "ardour/session_playlists.h"
-#include "ardour/slave.h"
 #include "ardour/smf_source.h"
 #include "ardour/source_factory.h"
-#include "ardour/tape_file_matcher.h"
-#include "ardour/tempo.h"
 #include "ardour/utils.h"
-#include "ardour/graph.h"
-#include "ardour/speakers.h"
-#include "ardour/operations.h"
 
 #include "midi++/port.h"
+#include "midi++/jack_midi_port.h"
 #include "midi++/mmc.h"
 #include "midi++/manager.h"
 
 #include "i18n.h"
 
+namespace ARDOUR {
+class MidiSource;
+class Processor;
+class Speakers;
+}
+
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
@@ -124,8 +116,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;
@@ -151,7 +141,6 @@ Session::Session (AudioEngine &eng,
        , _post_transport_work (0)
        , _send_timecode_update (false)
        , _all_route_group (new RouteGroup (*this, "all"))
-       , _process_graph (new Graph (*this))
        , routes (new RouteList)
        , _total_free_4k_blocks (0)
        , _bundles (new BundleList)
@@ -161,12 +150,18 @@ Session::Session (AudioEngine &eng,
        , click_data (0)
        , click_emphasis_data (0)
        , main_outs (0)
-       , _metadata (new SessionMetadata())
        , _have_rec_enabled_track (false)
        , _suspend_timecode_transmission (0)
 {
        _locations = new Locations (*this);
 
+       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));
+       }
+
        playlists.reset (new SessionPlaylists);
 
        _all_route_group->set_active (true, this);
@@ -217,6 +212,9 @@ Session::Session (AudioEngine &eng,
 
 Session::~Session ()
 {
+#ifdef PT_TIMING       
+       ST.dump ("ST.dump");
+#endif 
        destroy ();
 }
 
@@ -316,8 +314,6 @@ Session::destroy ()
                delete *i;
        }
 
-       Crossfade::set_buffer_size (0);
-
        /* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
        playlists.reset ();
 
@@ -366,19 +362,27 @@ Session::when_engine_running ()
                XMLNode* child = 0;
 
                _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;
+                       int c = 0;
 
                        if (Stateful::loading_state_version < 3000) {
                                c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
                        } else {
-                               c = _click_io->set_state (*child->children().front(), 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 ();
 
@@ -522,11 +526,21 @@ Session::when_engine_running ()
 
        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.
        */
+
        MIDI::Manager::instance()->set_port_states (Config->midi_port_states ());
 
        /* And this must be done after the MIDI::Manager::set_port_states as
@@ -535,106 +549,214 @@ Session::when_engine_running ()
 
        hookup_io ();
 
-       if (_is_new && !no_auto_connect()) {
+       /* 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::Mutex::Lock lm (AudioEngine::instance()->process_lock());
+               auto_connect_master_bus ();
+       }
 
-               /* don't connect the master bus outputs if there is a monitor bus */
+       _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
 
-               if (_master_out && Config->get_auto_connect_standard_busses() && !_monitor_out) {
+        /* update latencies */
 
-                       /* if requested auto-connect the outputs to the first N physical ports.
-                        */
+        initialize_latencies ();
 
-                       uint32_t limit = _master_out->n_outputs().n_total();
+       /* hook us up to the engine */
 
-                       for (uint32_t n = 0; n < limit; ++n) {
-                               boost::shared_ptr<Port> p = _master_out->output()->nth (n);
-                               string connect_to;
-                               if (outputs[p->type()].size() > n) {
-                                       connect_to = outputs[p->type()][n];
-                               }
+       BootMessage (_("Connect to engine"));
+       _engine.set_session (this);
+}
 
-                               if (!connect_to.empty() && p->connected_to (connect_to) == false) {
-                                       if (_master_out->output()->connect (p, connect_to, this)) {
-                                               error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
-                                                     << endmsg;
-                                               break;
-                                       }
-                               }
+void
+Session::auto_connect_master_bus ()
+{
+       if (!_master_out || !Config->get_auto_connect_standard_busses() || _monitor_out) {
+               return;
+       }
+               
+       /* if requested auto-connect the outputs to the first N physical ports.
+        */
+       
+       uint32_t limit = _master_out->n_outputs().n_total();
+       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]);
+       }
+       
+       for (uint32_t n = 0; n < limit; ++n) {
+               boost::shared_ptr<Port> p = _master_out->output()->nth (n);
+               string connect_to;
+               if (outputs[p->type()].size() > n) {
+                       connect_to = outputs[p->type()][n];
+               }
+               
+               if (!connect_to.empty() && p->connected_to (connect_to) == false) {
+                       if (_master_out->output()->connect (p, connect_to, this)) {
+                               error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
+                                     << endmsg;
+                               break;
                        }
                }
+       }
+}
 
-               if (_monitor_out) {
+void
+Session::remove_monitor_section ()
+{
+       if (!_monitor_out) {
+               return;
+       }
 
-                       /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
-                          are undefined, at best.
-                        */
+       /* force reversion to Solo-In-Place */
+       Config->set_solo_control_is_listen_control (false);
 
-                       /* control out listens to master bus (but ignores it
-                          under some conditions)
-                       */
+       {
+               /* Hold process lock while doing this so that we don't hear bits and
+                * pieces of audio as we work on each route.
+                */
+               
+               Glib::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
+                  routes to notice that they connect to the control out specifically.
+               */
+               
+               
+               boost::shared_ptr<RouteList> r = routes.reader ();
+               PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+               
+               for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
+                       
+                       if ((*x)->is_monitor()) {
+                               /* relax */
+                       } else if ((*x)->is_master()) {
+                               /* relax */
+                       } else {
+                               (*x)->remove_aux_or_listen (_monitor_out);
+                       }
+               }
+       }
 
-                       uint32_t limit = _monitor_out->n_inputs().n_audio();
+       remove_route (_monitor_out);
+       auto_connect_master_bus ();
+}
 
-                       if (_master_out) {
-                               for (uint32_t n = 0; n < limit; ++n) {
-                                       boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
-                                       boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n);
+void
+Session::add_monitor_section ()
+{
+       RouteList rl;
 
-                                       if (o) {
-                                               string connect_to = o->name();
-                                               if (_monitor_out->input()->connect (p, connect_to, this)) {
-                                                       error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to)
-                                                             << endmsg;
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
+       if (_monitor_out || !_master_out) {
+               return;
+       }
 
-                       /* if control out is not connected, connect control out to physical outs
-                       */
+       boost::shared_ptr<Route> r (new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO));
 
-                       if (!_monitor_out->output()->connected ()) {
+       if (r->init ()) {
+               return;
+       }
 
-                               if (!Config->get_monitor_bus_preferred_bundle().empty()) {
+#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
+       // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
+#endif
+       {
+               Glib::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);
+       }
 
-                                       boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
+       rl.push_back (r);
+       add_routes (rl, false, false, false);
+       
+       assert (_monitor_out);
 
-                                       if (b) {
-                                               _monitor_out->output()->connect_ports_to_bundle (b, this);
-                                       } else {
-                                               warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
-                                                                          Config->get_monitor_bus_preferred_bundle())
-                                                       << endmsg;
-                                       }
+       /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
+          are undefined, at best.
+       */
+       
+       uint32_t limit = _monitor_out->n_inputs().n_audio();
+       
+       if (_master_out) {
+               
+               /* connect the inputs to the master bus outputs. this
+                * represents a separate data feed from the internal sends from
+                * each route. as of jan 2011, it allows the monitor section to
+                * conditionally ignore either the internal sends or the normal
+                * input feed, but we should really find a better way to do
+                * this, i think.
+                */
+
+               _master_out->output()->disconnect (this);
+
+               for (uint32_t n = 0; n < limit; ++n) {
+                       boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
+                       boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n);
+                       
+                       if (o) {
+                               string connect_to = o->name();
+                               if (_monitor_out->input()->connect (p, connect_to, this)) {
+                                       error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to)
+                                             << endmsg;
+                                       break;
+                               }
+                       }
+               }
+       }
+       
+       /* if monitor section is not connected, connect it to physical outs
+        */
+       
+       if (Config->get_auto_connect_standard_busses() && !_monitor_out->output()->connected ()) {
+               
+               if (!Config->get_monitor_bus_preferred_bundle().empty()) {
+                       
+                       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);
+                       } else {
+                               warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
+                                                          Config->get_monitor_bus_preferred_bundle())
+                                       << endmsg;
+                       }
+                       
+               } else {
+                       
+                       /* Monitor bus is audio only */
 
-                               } else {
+                       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];
 
-                                       /* Monitor bus is audio only */
-                                       uint32_t mod = n_physical_outputs.get (DataType::AUDIO);
-                                       uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
-
-                                       if (mod != 0) {
-
-                                               for (uint32_t n = 0; n < limit; ++n) {
-
-                                                       boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
-                                                       string connect_to;
-                                                       if (outputs[DataType::AUDIO].size() > (n % mod)) {
-                                                               connect_to = outputs[DataType::AUDIO][n % mod];
-                                                       }
-
-                                                       if (!connect_to.empty()) {
-                                                               if (_monitor_out->output()->connect (p, connect_to, this)) {
-                                                                       error << string_compose (
-                                                                                       _("cannot connect control output %1 to %2"),
-                                                                                       n, connect_to)
-                                                                               << endmsg;
-                                                                       break;
-                                                               }
-                                                       }
+                       for (uint32_t i = 0; i < DataType::num_types; ++i) {
+                               _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
+                       }
+                       
+                       
+                       if (mod != 0) {
+                               
+                               for (uint32_t n = 0; n < limit; ++n) {
+                                       
+                                       boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
+                                       string connect_to;
+                                       if (outputs[DataType::AUDIO].size() > (n % mod)) {
+                                               connect_to = outputs[DataType::AUDIO][n % mod];
+                                       }
+                                       
+                                       if (!connect_to.empty()) {
+                                               if (_monitor_out->output()->connect (p, connect_to, this)) {
+                                                       error << string_compose (
+                                                               _("cannot connect control output %1 to %2"),
+                                                               n, connect_to)
+                                                             << endmsg;
+                                                       break;
                                                }
                                        }
                                }
@@ -642,16 +764,32 @@ Session::when_engine_running ()
                }
        }
 
-       _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
+       /* Hold process lock while doing this so that we don't hear bits and
+        * pieces of audio as we work on each route.
+        */
+        
+       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
-        /* update latencies */
+       /* Connect tracks to monitor section. Note that in an
+          existing session, the internal sends will already exist, but we want the
+          routes to notice that they connect to the control out specifically.
+       */
 
-        initialize_latencies ();
 
-       /* hook us up to the engine */
+       boost::shared_ptr<RouteList> rls = routes.reader ();
 
-       BootMessage (_("Connect to engine"));
-       _engine.set_session (this);
+       PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+
+       for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) {
+               
+               if ((*x)->is_monitor()) {
+                       /* relax */
+               } else if ((*x)->is_master()) {
+                       /* relax */
+               } else {
+                       (*x)->enable_monitor_send ();
+               }
+       }
 }
 
 void
@@ -692,35 +830,7 @@ Session::hookup_io ()
        /* Tell all IO objects to connect themselves together */
 
        IO::enable_connecting ();
-       MIDI::Port::MakeConnections ();
-
-       /* Now reset all panners */
-
-       Delivery::reset_panners ();
-
-       /* Connect tracks to monitor/listen bus if there is one.  Note that in an
-          existing session, the internal sends will already exist, but we want the
-          routes to notice that they connect to the control out specifically.
-       */
-
-       if (_monitor_out) {
-               boost::shared_ptr<RouteList> r = routes.reader ();
-               for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
-
-                       if ((*x)->is_monitor()) {
-
-                               /* relax */
-
-                       } else if ((*x)->is_master()) {
-
-                               /* relax */
-
-                       } else {
-
-                               (*x)->listen_via_monitor ();
-                       }
-               }
-       }
+       MIDI::JackMIDIPort::MakeConnections ();
 
        /* Anyone who cares about input state, wake up and do something */
 
@@ -787,16 +897,6 @@ Session::set_track_monitor_input_status (bool yn)
        }
 }
 
-void
-Session::reset_input_monitor_state ()
-{
-       if (transport_rolling()) {
-               set_track_monitor_input_status (Config->get_monitoring_model() == HardwareMonitoring && !config.get_auto_input());
-       } else {
-               set_track_monitor_input_status (Config->get_monitoring_model() == HardwareMonitoring);
-       }
-}
-
 void
 Session::auto_punch_start_changed (Location* location)
 {
@@ -1295,8 +1395,6 @@ Session::resort_routes ()
                /* writer goes out of scope and forces update */
        }
 
-       //_process_graph->dump(1);
-
 #ifndef NDEBUG
        boost::shared_ptr<RouteList> rl = routes.reader ();
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
@@ -1371,7 +1469,10 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
                   Note: the process graph rechain does not require a
                   topologically-sorted list, but hey ho.
                */
-               _process_graph->rechain (sorted_routes, edges);
+               if (_process_graph) {
+                       _process_graph->rechain (sorted_routes, edges);
+               }
+               
                _current_route_graph = edges;
 
                /* Complete the building of the routes' lists of what directly
@@ -1463,9 +1564,10 @@ Session::count_existing_track_channels (ChanCount& in, ChanCount& out)
 
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "MIDI".
+ *  @param instrument plugin info for the instrument to insert pre-fader, if any
  */
 list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template)
+Session::new_midi_track (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;
@@ -1474,7 +1576,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
        list<boost::shared_ptr<MidiTrack> > ret;
        uint32_t control_id;
 
-       control_id = ntracks() + nbusses();
+       control_id = next_control_id ();
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI");
 
@@ -1540,7 +1642,16 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
 
   failed:
        if (!new_routes.empty()) {
-               add_routes (new_routes, true, true);
+               add_routes (new_routes, true, true, true);
+
+               if (instrument) {
+                       for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
+                               PluginPtr plugin = instrument->load (*this);
+                               boost::shared_ptr<Processor> p (new PluginInsert (*this, plugin));
+                               (*r)->add_processor (p, PreFader);
+                               
+                       }
+               }
        }
 
        return ret;
@@ -1690,9 +1801,8 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing
  *  @param name_template string to use for the start of the name, or "" to use "Audio".
  */
 list< boost::shared_ptr<AudioTrack> >
-Session::new_audio_track (
-       int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template
-       )
+Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, 
+                         uint32_t how_many, string name_template)
 {
        char track_name[32];
        uint32_t track_id = 0;
@@ -1701,7 +1811,7 @@ Session::new_audio_track (
        list<boost::shared_ptr<AudioTrack> > ret;
        uint32_t control_id;
 
-       control_id = ntracks() + nbusses() + 1;
+       control_id = next_control_id ();
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio");
 
@@ -1775,7 +1885,7 @@ Session::new_audio_track (
 
   failed:
        if (!new_routes.empty()) {
-               add_routes (new_routes, true, true);
+               add_routes (new_routes, true, true, true);
        }
 
        return ret;
@@ -1820,7 +1930,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
        RouteList ret;
        uint32_t control_id;
 
-       control_id = ntracks() + nbusses() + 1;
+       control_id = next_control_id ();
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
        
@@ -1887,7 +1997,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
 
   failure:
        if (!ret.empty()) {
-               add_routes (ret, false, true);
+               add_routes (ret, false, true, true); // autoconnect outputs only
        }
 
        return ret;
@@ -1908,7 +2018,9 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
 
        XMLNode* node = tree.root();
 
-       control_id = ntracks() + nbusses() + 1;
+       IO::disable_connecting ();
+
+       control_id = next_control_id ();
 
        while (how_many) {
 
@@ -1984,14 +2096,15 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
 
   out:
        if (!ret.empty()) {
-               add_routes (ret, true, true);
+               add_routes (ret, true, true, true);
+               IO::enable_connecting ();
        }
 
        return ret;
 }
 
 void
-Session::add_routes (RouteList& new_routes, bool auto_connect, bool save)
+Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save)
 {
         ChanCount existing_inputs;
         ChanCount existing_outputs;
@@ -2048,20 +2161,24 @@ Session::add_routes (RouteList& new_routes, bool auto_connect, bool save)
                        }
                }
 
-               if (auto_connect) {
-                       auto_connect_route (r, existing_inputs, existing_outputs, true);
+               if (input_auto_connect || output_auto_connect) {
+                       auto_connect_route (r, existing_inputs, existing_outputs, true, input_auto_connect);
                }
        }
 
        if (_monitor_out && IO::connecting_legal) {
 
-               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)->listen_via_monitor ();
+               {
+                       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()) {
+                                       /* relax */
+                               } else {
+                                       (*x)->enable_monitor_send ();
+                               }
                        }
                }
 
@@ -2137,22 +2254,29 @@ Session::globally_add_internal_sends (boost::shared_ptr<Route> dest, Placement p
 void
 Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::shared_ptr<RouteList> senders)
 {
-       if (dest->is_monitor() || dest->is_master()) {
+       for (RouteList::iterator i = senders->begin(); i != senders->end(); ++i) {
+               add_internal_send (dest, (*i)->before_processor_for_placement (p), *i);
+       }
+}
+
+void
+Session::add_internal_send (boost::shared_ptr<Route> dest, int index, boost::shared_ptr<Route> sender)
+{
+       add_internal_send (dest, sender->before_processor_for_index (index), sender);
+}
+
+void
+Session::add_internal_send (boost::shared_ptr<Route> dest, boost::shared_ptr<Processor> before, boost::shared_ptr<Route> sender)
+{
+       if (sender->is_monitor() || sender->is_master() || sender == dest || dest->is_monitor() || dest->is_master()) {
                return;
        }
 
        if (!dest->internal_return()) {
-               dest->add_internal_return();
+               dest->add_internal_return ();
        }
 
-       for (RouteList::iterator i = senders->begin(); i != senders->end(); ++i) {
-
-               if ((*i)->is_monitor() || (*i)->is_master() || (*i) == dest) {
-                       continue;
-               }
-
-               (*i)->listen_via (dest, p);
-       }
+       sender->add_aux_send (dest, before);
 
        graph_reordered ();
 }
@@ -2160,7 +2284,7 @@ Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::
 void
 Session::remove_route (boost::shared_ptr<Route> route)
 {
-       if (((route == _master_out) || (route == _monitor_out)) && !Config->get_allow_special_bus_removal()) {
+       if (route == _master_out) {
                return;
        }
 
@@ -2182,13 +2306,6 @@ Session::remove_route (boost::shared_ptr<Route> route)
                }
 
                if (route == _monitor_out) {
-
-                       /* cancel control outs for all routes */
-
-                       for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
-                               (*r)->drop_listen (_monitor_out);
-                       }
-
                        _monitor_out.reset ();
                }
 
@@ -2229,7 +2346,9 @@ Session::remove_route (boost::shared_ptr<Route> route)
         */
 
        resort_routes ();
-       _process_graph->clear_other_chain ();
+       if (_process_graph) {
+               _process_graph->clear_other_chain ();
+       }
 
        /* get rid of it from the dead wood collection in the route list manager */
 
@@ -2831,6 +2950,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;
@@ -2867,7 +2994,7 @@ Session::remove_source (boost::weak_ptr<Source> src)
                }
        }
 
-       if (!_state_of_the_state & InCleanup) {
+       if (!(_state_of_the_state & InCleanup)) {
 
                /* save state so we don't end up with a session file
                   referring to non-existent sources.
@@ -3296,12 +3423,9 @@ Session::audition_playlist ()
 void
 Session::non_realtime_set_audition ()
 {
-       if (!pending_audition_region) {
-               auditioner->audition_current_playlist ();
-       } else {
-               auditioner->audition_region (pending_audition_region);
-               pending_audition_region.reset ();
-       }
+       assert (pending_audition_region);
+       auditioner->audition_region (pending_audition_region);
+       pending_audition_region.reset ();
        AuditionActive (true); /* EMIT SIGNAL */
 }
 
@@ -3540,6 +3664,26 @@ Session::next_send_id ()
        }
 }
 
+uint32_t
+Session::next_aux_send_id ()
+{
+       /* this doesn't really loop forever. just think about it */
+
+       while (true) {
+               for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < aux_send_bitset.size(); ++n) {
+                       if (!aux_send_bitset[n]) {
+                               aux_send_bitset[n] = true;
+                               return n;
+
+                       }
+               }
+
+               /* none available, so resize and try again */
+
+               aux_send_bitset.resize (aux_send_bitset.size() + 16, false);
+       }
+}
+
 uint32_t
 Session::next_return_id ()
 {
@@ -3572,6 +3716,18 @@ Session::mark_send_id (uint32_t id)
        send_bitset[id] = true;
 }
 
+void
+Session::mark_aux_send_id (uint32_t id)
+{
+       if (id >= aux_send_bitset.size()) {
+               aux_send_bitset.resize (id+16, false);
+       }
+       if (aux_send_bitset[id]) {
+               warning << string_compose (_("aux send ID %1 appears to be in use already"), id) << endmsg;
+       }
+       aux_send_bitset[id] = true;
+}
+
 void
 Session::mark_return_id (uint32_t id)
 {
@@ -3604,6 +3760,14 @@ Session::unmark_send_id (uint32_t id)
        }
 }
 
+void
+Session::unmark_aux_send_id (uint32_t id)
+{
+       if (id < aux_send_bitset.size()) {
+               aux_send_bitset[id] = false;
+       }
+}
+
 void
 Session::unmark_return_id (uint32_t id)
 {
@@ -3738,7 +3902,9 @@ Session::freeze_all (InterThreadInfo& itt)
 boost::shared_ptr<Region>
 Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
                          bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
-                         InterThreadInfo& itt, bool enable_processing)
+                         InterThreadInfo& itt, 
+                         boost::shared_ptr<Processor> endpoint, bool include_endpoint,
+                         bool for_export)
 {
        boost::shared_ptr<Region> result;
        boost::shared_ptr<Playlist> playlist;
@@ -3775,12 +3941,6 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
                goto out;
        }
 
-       /* external redirects will be a problem */
-
-       if (track.has_external_redirects()) {
-               goto out;
-       }
-
        ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
 
        for (uint32_t chan_n = 0; chan_n < diskstream_channels.n_audio(); ++chan_n) {
@@ -3810,13 +3970,14 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
                srcs.push_back (fsource);
        }
 
-       /* tell redirects that care that we are about to use a much larger blocksize */
+       /* tell redirects that care that we are about to use a much larger
+        * blocksize. this will flush all plugins too, so that they are ready
+        * to be used for this process.
+        */
 
        need_block_size_reset = true;
        track.set_block_size (chunk_size);
 
-       /* XXX need to flush all redirects */
-
        position = start;
        to_do = len;
 
@@ -3834,7 +3995,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
 
                this_chunk = min (to_do, chunk_size);
 
-               if (track.export_stuff (buffers, start, this_chunk, enable_processing)) {
+               if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export)) {
                        goto out;
                }
 
@@ -4204,7 +4365,7 @@ Session::start_time_changed (framepos_t old)
 
        Location* l = _locations->auto_loop_location ();
 
-       if (l->start() == old) {
+       if (l && l->start() == old) {
                l->set_start (s->start(), true);
        }
 }
@@ -4315,11 +4476,17 @@ 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) {
-               if (*i == path) {
+               /* 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.
+
+                  On Windows, I think we could just do if (*i == path) here.
+               */
+               if (PBD::sys::inodes_same (*i, path)) {
                        return;
                }
        }
@@ -4571,3 +4738,9 @@ Session::session_name_is_legal (const string& path)
 
        return 0;
 }
+
+uint32_t 
+Session::next_control_id () const
+{
+       return ntracks() + nbusses() + 1;
+}