perhaps, just possibly, a working solo model. needs to be fixed so that connections...
[ardour.git] / libs / ardour / session.cc
index 8034f7403369abac130854b48f7ab0cf53c699ba..2da383b810ae3248bbc6b5dd183e6cddd1a7fb44 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 1999-2004 Paul Davis
+    Copyright (C) 1999-2010 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
 
 */
 
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
 #include <algorithm>
 #include <string>
 #include <vector>
 #include <unistd.h>
 #include <limits.h>
 
-
 #include <glibmm/thread.h>
 #include <glibmm/miscutils.h>
 #include <glibmm/fileutils.h>
-#include <glibmm/thread.h>
 
 #include "pbd/error.h"
 #include "pbd/boost_debug.h"
@@ -54,6 +55,7 @@
 #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"
@@ -72,6 +74,7 @@
 #include "ardour/midi_track.h"
 #include "ardour/midi_ui.h"
 #include "ardour/named_selection.h"
+#include "ardour/process_thread.h"
 #include "ardour/playlist.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port_insert.h"
@@ -125,14 +128,12 @@ const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event)
 Session::Session (AudioEngine &eng,
                  const string& fullpath,
                  const string& snapshot_name,
+                  BusProfile* bus_profile,
                  string mix_template)
 
        : _engine (eng),
          _target_transport_speed (0.0),
          _requested_return_frame (-1),
-         _scratch_buffers(new BufferSet()),
-         _silent_buffers(new BufferSet()),
-         _mix_buffers(new BufferSet()),
          mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
@@ -143,7 +144,6 @@ Session::Session (AudioEngine &eng,
          _butler (new Butler (*this)),
          _post_transport_work (0),
          _send_timecode_update (false),
-         diskstreams (new DiskstreamList),
          routes (new RouteList),
          _total_free_4k_blocks (0),
          _bundles (new BundleList),
@@ -153,36 +153,32 @@ Session::Session (AudioEngine &eng,
          click_emphasis_data (0),
          main_outs (0),
          _metadata (new SessionMetadata()),
-         _have_rec_enabled_diskstream (false)
+         _have_rec_enabled_track (false)
 
 {
        playlists.reset (new SessionPlaylists);
        
-       bool new_session;
-
        interpolation.add_channel_to (0, 0);
 
        if (!eng.connected()) {
                throw failed_constructor();
        }
 
-       info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
-
        n_physical_outputs = _engine.n_physical_outputs(DataType::AUDIO);
        n_physical_inputs =  _engine.n_physical_inputs(DataType::AUDIO);
 
        first_stage_init (fullpath, snapshot_name);
 
-       new_session = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+        _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
 
-       if (new_session) {
-               if (create (new_session, mix_template, compute_initial_length())) {
+       if (_is_new) {
+               if (create (mix_template, compute_initial_length(), bus_profile)) {
                        destroy ();
                        throw failed_constructor ();
                }
-       }
+        }
 
-       if (second_stage_init (new_session)) {
+       if (second_stage_init ()) {
                destroy ();
                throw failed_constructor ();
        }
@@ -199,138 +195,8 @@ Session::Session (AudioEngine &eng,
        if (was_dirty) {
                DirtyChanged (); /* EMIT SIGNAL */
        }
-}
-
-Session::Session (AudioEngine &eng,
-                 string fullpath,
-                 string snapshot_name,
-                 AutoConnectOption input_ac,
-                 AutoConnectOption output_ac,
-                 uint32_t control_out_channels,
-                 uint32_t master_out_channels,
-                 uint32_t requested_physical_in,
-                 uint32_t requested_physical_out,
-                 nframes_t initial_length)
-
-       : _engine (eng),
-         _target_transport_speed (0.0),
-         _requested_return_frame (-1),
-         _scratch_buffers(new BufferSet()),
-         _silent_buffers(new BufferSet()),
-         _mix_buffers(new BufferSet()),
-         mmc (0),
-         _mmc_port (default_mmc_port),
-         _mtc_port (default_mtc_port),
-         _midi_port (default_midi_port),
-         _midi_clock_port (default_midi_clock_port),
-         _session_dir ( new SessionDirectory(fullpath)),
-         state_tree (0),
-         _butler (new Butler (*this)),
-         _post_transport_work (0),
-         _send_timecode_update (false),
-         diskstreams (new DiskstreamList),
-         routes (new RouteList),
-         _total_free_4k_blocks (0),
-         _bundles (new BundleList),
-         _bundle_xml_node (0),
-         _click_io ((IO *) 0),
-         click_data (0),
-         click_emphasis_data (0),
-         main_outs (0),
-         _metadata (new SessionMetadata()),
-         _have_rec_enabled_diskstream (false)
-{
-       playlists.reset (new SessionPlaylists);
-
-       bool new_session;
-
-       interpolation.add_channel_to (0, 0);
-
-       if (!eng.connected()) {
-               throw failed_constructor();
-       }
-
-       info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
-
-       n_physical_outputs = _engine.n_physical_outputs (DataType::AUDIO);
-       n_physical_inputs = _engine.n_physical_inputs (DataType::AUDIO);
-
-       if (n_physical_inputs) {
-               n_physical_inputs = max (requested_physical_in, n_physical_inputs);
-       }
-
-       if (n_physical_outputs) {
-               n_physical_outputs = max (requested_physical_out, n_physical_outputs);
-       }
-
-       first_stage_init (fullpath, snapshot_name);
-
-       new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
-
-       if (new_session) {
-               if (create (new_session, string(), initial_length)) {
-                       destroy ();
-                       throw failed_constructor ();
-               }
-       }
-
-       {
-               /* set up Master Out and Control Out if necessary */
-
-               RouteList rl;
-               int control_id = 1;
-
-               if (master_out_channels) {
-                       ChanCount count(DataType::AUDIO, master_out_channels);
-                       Route* rt = new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO);
-                       boost_debug_shared_ptr_mark_interesting (rt, "Route");
-                       boost::shared_ptr<Route> r (rt);
-                       r->input()->ensure_io (count, false, this);
-                       r->output()->ensure_io (count, false, this);
-                       r->set_remote_control_id (control_id);
-
-                       rl.push_back (r);
-               } else {
-                       /* prohibit auto-connect to master, because there isn't one */
-                       output_ac = AutoConnectOption (output_ac & ~AutoConnectMaster);
-               }
-
-               if (control_out_channels) {
-                       ChanCount count(DataType::AUDIO, control_out_channels);
-                       Route* rt = new Route (*this, _("monitor"), Route::ControlOut, DataType::AUDIO);
-                       boost_debug_shared_ptr_mark_interesting (rt, "Route");
-                       shared_ptr<Route> r (rt);
-                       r->input()->ensure_io (count, false, this);
-                       r->output()->ensure_io (count, false, this);
-                       r->set_remote_control_id (control_id++);
-
-                       rl.push_back (r);
-               }
-
-               if (!rl.empty()) {
-                       add_routes (rl, false);
-               }
-
-       }
-
-       if (no_auto_connect()) {
-               input_ac = AutoConnectOption (0);
-               output_ac = AutoConnectOption (0);
-       }
-
-       Config->set_input_auto_connect (input_ac);
-       Config->set_output_auto_connect (output_ac);
-
-       if (second_stage_init (new_session)) {
-               destroy ();
-               throw failed_constructor ();
-       }
 
-       store_recent_sessions (_name, _path);
-
-       _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
-
-       Config->ParameterChanged.connect_same_thread (*this, boost::bind (&Session::config_changed, this, _1, false));
+        _is_new = false;
 }
 
 Session::~Session ()
@@ -353,10 +219,6 @@ Session::destroy ()
 
        _engine.remove_session ();
 
-       /* clear region map. it doesn't hold references, but lets just be sensible here */
-
-       RegionFactory::clear_map ();
-
        /* clear history so that no references to objects are held any more */
 
        _history.clear ();
@@ -369,6 +231,7 @@ Session::destroy ()
 
        Stateful::loading_state_version = 0;
 
+       _butler->drop_references ();
        delete _butler;
        delete midi_control_ui;
 
@@ -382,14 +245,9 @@ Session::destroy ()
 
        clear_clicks ();
 
-       delete _scratch_buffers;
-       delete _silent_buffers;
-       delete _mix_buffers;
-
        /* clear out any pending dead wood from RCU managed objects */
 
        routes.flush ();
-       diskstreams.flush ();
        _bundles.flush ();
        
        AudioDiskstream::free_working_buffers();
@@ -403,11 +261,7 @@ Session::destroy ()
        named_selections.clear ();
 
        DEBUG_TRACE (DEBUG::Destruction, "delete regions\n");
-       for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-               DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for region %1 ; pre-ref = %2\n", i->second->name(), i->second.use_count()));
-               i->second->drop_references ();
-       }
-       regions.clear ();
+       RegionFactory::delete_all_regions ();
 
        DEBUG_TRACE (DEBUG::Destruction, "delete routes\n");
        
@@ -415,7 +269,7 @@ Session::destroy ()
 
        auditioner.reset ();
        _master_out.reset ();
-       _control_out.reset ();
+       _monitor_out.reset ();
 
        {
                RCUWriter<RouteList> writer (routes);
@@ -433,19 +287,6 @@ Session::destroy ()
 
        boost::shared_ptr<RouteList> r = routes.reader ();
 
-       DEBUG_TRACE (DEBUG::Destruction, "delete diskstreams\n");
-       {
-               RCUWriter<DiskstreamList> dwriter (diskstreams);
-               boost::shared_ptr<DiskstreamList> dsl = dwriter.get_copy();
-               for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                       DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for diskstream %1 ; pre-ref = %2\n", (*i)->name(), (*i).use_count()));
-                       (*i)->drop_references ();
-               }
-
-               dsl->clear ();
-       }
-       diskstreams.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->path(), i->second.use_count()));
@@ -654,9 +495,11 @@ Session::when_engine_running ()
 
        hookup_io ();
 
-       if (!no_auto_connect()) {
+       if (_is_new && !no_auto_connect()) {
+
+                /* don't connect the master bus outputs if there is a monitor bus */
 
-               if (_master_out && Config->get_auto_connect_standard_busses()) {
+               if (_master_out && Config->get_auto_connect_standard_busses() && !_monitor_out) {
 
                        /* if requested auto-connect the outputs to the first N physical ports.
                         */
@@ -677,7 +520,7 @@ Session::when_engine_running ()
                        }
                }
 
-               if (_control_out) {
+               if (_monitor_out) {
 
                        /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
                           are undefined, at best.
@@ -687,16 +530,16 @@ Session::when_engine_running ()
                           under some conditions)
                        */
 
-                       uint32_t limit = _control_out->n_inputs().n_audio();
+                       uint32_t limit = _monitor_out->n_inputs().n_audio();
 
                        if (_master_out) {
                                for (uint32_t n = 0; n < limit; ++n) {
-                                       AudioPort* p = _control_out->input()->ports().nth_audio_port (n);
+                                       AudioPort* p = _monitor_out->input()->ports().nth_audio_port (n);
                                        AudioPort* o = _master_out->output()->ports().nth_audio_port (n);
 
                                        if (o) {
                                                string connect_to = o->name();
-                                               if (_control_out->input()->connect (p, connect_to, this)) {
+                                               if (_monitor_out->input()->connect (p, connect_to, this)) {
                                                        error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to)
                                                              << endmsg;
                                                        break;
@@ -705,18 +548,17 @@ Session::when_engine_running ()
                                }
                        }
 
-                       /* if control out is not connected,
-                          connect control out to physical outs, but use ones after the master if possible
+                       /* if control out is not connected, connect control out to physical outs
                        */
 
-                       if (!_control_out->output()->connected_to (boost::shared_ptr<IO>())) {
+                       if (!_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) {
-                                               _control_out->output()->connect_ports_to_bundle (b, this);
+                                               _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())
@@ -724,25 +566,24 @@ Session::when_engine_running ()
                                        }
 
                                } else {
-
-                                       /* XXX this logic is wrong for mixed port types */
-
-                                       uint32_t shift = _master_out->n_outputs().n_audio();
-                                       uint32_t mod = _engine.n_physical_outputs (DataType::AUDIO);
-                                       limit = _control_out->n_outputs().n_audio();
-
-                                       cerr << "Connecting " << limit << " control out ports, shift is " << shift << " mod is " << mod << endl;
-
-                                       for (uint32_t n = 0; n < limit; ++n) {
-
-                                               Port* p = _control_out->output()->nth (n);
-                                               string connect_to = _engine.get_nth_physical_output (DataType (p->type()), (n+shift) % mod);
-
-                                               if (!connect_to.empty()) {
-                                                       if (_control_out->output()->connect (p, connect_to, this)) {
-                                                               error << string_compose (_("cannot connect control output %1 to %2"), n, connect_to)
-                                                                     << endmsg;
-                                                               break;
+                                        
+                                       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+                                               uint32_t mod = _engine.n_physical_outputs (*t);
+                                               uint32_t limit = _monitor_out->n_outputs().get(*t);
+
+                                               for (uint32_t n = 0; n < limit; ++n) {
+
+                                                       Port* p = _monitor_out->output()->ports().port(*t, n);
+                                                       string connect_to = _engine.get_nth_physical_output (*t, (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;
+                                                               }
                                                        }
                                                }
                                        }
@@ -776,11 +617,16 @@ Session::hookup_io ()
 
                /* we delay creating the auditioner till now because
                   it makes its own connections to ports.
-                  the engine has to be running for this to work.
                */
 
                try {
-                       auditioner.reset (new Auditioner (*this));
+                        Auditioner* a = new Auditioner (*this);
+                        if (a->init()) {
+                                delete a;
+                                throw failed_constructor();
+                        }
+                        a->use_new_diskstream ();
+                       auditioner.reset (a);
                }
 
                catch (failed_constructor& err) {
@@ -803,23 +649,32 @@ Session::hookup_io ()
 
        Delivery::reset_panners ();
 
-       /* Connect tracks to listen/solo etc. busses XXX generalize this beyond control_out */
-
-       if (_control_out) {
+       /* 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_control() || (*x)->is_master()) {
-                               continue;
-                       }
-
-                       (*x)->listen_via (_control_out,
-                                         (Config->get_listen_position() == AfterFaderListen ? PostFader : PreFader),
-                                         false, false);
-               }
-       }
+                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_out,
+                                                  (Config->get_listen_position() == AfterFaderListen ? PostFader : PreFader),
+                                                  false, false);
+                        }
+                }
+        }
 
        /* Anyone who cares about input state, wake up and do something */
 
@@ -845,9 +700,9 @@ Session::hookup_io ()
 void
 Session::playlist_length_changed ()
 {
-       /* we can't just increase end_location->end() if pl->get_maximum_extent()
+       /* we can't just increase session_range_location->end() if pl->get_maximum_extent()
           if larger. if the playlist used to be the longest playlist,
-          and its now shorter, we have to decrease end_location->end(). hence,
+          and its now shorter, we have to decrease session_range_location->end(). hence,
           we have to iterate over all diskstreams and check the
           playlists currently in use.
        */
@@ -855,16 +710,16 @@ Session::playlist_length_changed ()
 }
 
 void
-Session::diskstream_playlist_changed (boost::weak_ptr<Diskstream> wp)
+Session::track_playlist_changed (boost::weak_ptr<Track> wp)
 {
-       boost::shared_ptr<Diskstream> dstream = wp.lock ();
-       if (!dstream) {
+       boost::shared_ptr<Track> track = wp.lock ();
+       if (!track) {
                return;
        }
        
        boost::shared_ptr<Playlist> playlist;
 
-       if ((playlist = dstream->playlist()) != 0) {
+       if ((playlist = track->playlist()) != 0) {
                playlist->LengthChanged.connect_same_thread (*this, boost::bind (&Session::playlist_length_changed, this));
        }
 
@@ -891,21 +746,23 @@ Session::reset_input_monitor_state ()
 {
        if (transport_rolling()) {
 
-               boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-               for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                       if ((*i)->record_enabled ()) {
+               boost::shared_ptr<RouteList> rl = routes.reader ();
+               for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                       boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                       if (tr && tr->record_enabled ()) {
                                //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
-                               (*i)->monitor_input (Config->get_monitoring_model() == HardwareMonitoring && !config.get_auto_input());
+                               tr->monitor_input (Config->get_monitoring_model() == HardwareMonitoring && !config.get_auto_input());
                        }
                }
+               
        } else {
-               boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-               for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                       if ((*i)->record_enabled ()) {
+               
+               boost::shared_ptr<RouteList> rl = routes.reader ();
+               for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                       boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                       if (tr && tr->record_enabled ()) {
                                //cerr << "switching to input = " << !Config->get_auto_input() << __FILE__ << __LINE__ << endl << endl;
-                               (*i)->monitor_input (Config->get_monitoring_model() == HardwareMonitoring);
+                               tr->monitor_input (Config->get_monitoring_model() == HardwareMonitoring);
                        }
                }
        }
@@ -1087,11 +944,8 @@ Session::handle_locations_changed (Locations::LocationList& locations)
                        set_loop = true;
                }
 
-               if (location->is_start()) {
-                       start_location = location;
-               }
-               if (location->is_end()) {
-                       end_location = location;
+               if (location->is_session_range()) {
+                       _session_range_location = location;
                }
        }
 
@@ -1115,10 +969,12 @@ Session::enable_record ()
                deliver_mmc(MIDI::MachineControl::cmdRecordStrobe, _last_record_location);
 
                if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
-                       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-                       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                               if ((*i)->record_enabled ()) {
-                                       (*i)->monitor_input (true);
+                       
+                       boost::shared_ptr<RouteList> rl = routes.reader ();
+                       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                               if (tr && tr->record_enabled ()) {
+                                       tr->monitor_input (true);
                                }
                        }
                }
@@ -1150,11 +1006,12 @@ Session::disable_record (bool rt_context, bool force)
                }
 
                if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
-                       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
 
-                       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                               if ((*i)->record_enabled ()) {
-                                       (*i)->monitor_input (false);
+                       boost::shared_ptr<RouteList> rl = routes.reader ();
+                       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                               if (tr && tr->record_enabled ()) {
+                                       tr->monitor_input (false);
                                }
                        }
                }
@@ -1170,17 +1027,15 @@ Session::disable_record (bool rt_context, bool force)
 void
 Session::step_back_from_record ()
 {
-       /* XXX really atomic compare+swap here */
-       if (g_atomic_int_get (&_record_status) == Recording) {
-               g_atomic_int_set (&_record_status, Enabled);
+       if (g_atomic_int_compare_and_exchange (&_record_status, Recording, Enabled)) {
 
                if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
-                       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-                       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                               if ((*i)->record_enabled ()) {
+                       boost::shared_ptr<RouteList> rl = routes.reader ();
+                       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                               if (tr && tr->record_enabled ()) {
                                        //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
-                                       (*i)->monitor_input (false);
+                                       tr->monitor_input (false);
                                }
                        }
                }
@@ -1252,17 +1107,20 @@ Session::audible_frame () const
 
                /* MOVING */
 
-               /* check to see if we have passed the first guaranteed
+               /* Check to see if we have passed the first guaranteed
                   audible frame past our last start position. if not,
                   return that last start point because in terms
                   of audible frames, we have not moved yet.
+
+                  `Start position' in this context means the time we last
+                  either started or changed transport direction.
                */
 
                if (_transport_speed > 0.0f) {
 
                        if (!play_loop || !have_looped) {
-                               if (tf < _last_roll_location + offset) {
-                                       return _last_roll_location;
+                               if (tf < _last_roll_or_reversal_location + offset) {
+                                       return _last_roll_or_reversal_location;
                                }
                        }
 
@@ -1274,8 +1132,8 @@ Session::audible_frame () const
 
                        /* XXX wot? no backward looping? */
 
-                       if (tf > _last_roll_location - offset) {
-                               return _last_roll_location;
+                       if (tf > _last_roll_or_reversal_location - offset) {
+                               return _last_roll_or_reversal_location;
                        } else {
                                /* backwards */
                                ret += offset;
@@ -1324,12 +1182,7 @@ Session::set_block_size (nframes_t nframes)
        {
                current_block_size = nframes;
 
-               ensure_buffers(_scratch_buffers->available());
-
-               delete [] _gain_automation_buffer;
-               _gain_automation_buffer = new gain_t[nframes];
-
-               allocate_pan_automation_buffers (nframes, _npan_buffers, true);
+               ensure_buffers ();
 
                boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -1337,9 +1190,12 @@ Session::set_block_size (nframes_t nframes)
                        (*i)->set_block_size (nframes);
                }
 
-               boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-               for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                       (*i)->set_block_size (nframes);
+               boost::shared_ptr<RouteList> rl = routes.reader ();
+               for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                       boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                       if (tr) {
+                               tr->set_block_size (nframes);
+                       }
                }
 
                set_worst_io_latencies ();
@@ -1385,13 +1241,13 @@ Session::set_default_fade (float /*steepness*/, float /*fade_msecs*/)
 
 struct RouteSorter {
     bool operator() (boost::shared_ptr<Route> r1, boost::shared_ptr<Route> r2) {
-           if (r1->fed_by.find (r2) != r1->fed_by.end()) {
+           if (r2->feeds (r1)) {
                    return false;
-           } else if (r2->fed_by.find (r1) != r2->fed_by.end()) {
+           } else if (r1->feeds (r2)) {
                    return true;
            } else {
-                   if (r1->fed_by.empty()) {
-                           if (r2->fed_by.empty()) {
+                   if (r1->not_fed ()) {
+                           if (r2->not_fed ()) {
                                    /* no ardour-based connections inbound to either route. just use signal order */
                                    return r1->order_key(N_("signal")) < r2->order_key(N_("signal"));
                            } else {
@@ -1410,21 +1266,21 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase)
 {
        shared_ptr<Route> r2;
 
-       if ((r1->fed_by.find (rbase) != r1->fed_by.end()) && (rbase->fed_by.find (r1) != rbase->fed_by.end())) {
+       if (r1->feeds (rbase) && rbase->feeds (r1)) {
                info << string_compose(_("feedback loop setup between %1 and %2"), r1->name(), rbase->name()) << endmsg;
                return;
        }
 
        /* make a copy of the existing list of routes that feed r1 */
 
-       set<weak_ptr<Route> > existing = r1->fed_by;
-
+        Route::FedBy existing (r1->fed_by());
+                        
        /* for each route that feeds r1, recurse, marking it as feeding
           rbase as well.
        */
 
-       for (set<weak_ptr<Route> >::iterator i = existing.begin(); i != existing.end(); ++i) {
-               if (!(r2 = (*i).lock ())) {
+       for (Route::FedBy::iterator i = existing.begin(); i != existing.end(); ++i) {
+               if (!(r2 = i->r.lock ())) {
                        /* (*i) went away, ignore it */
                        continue;
                }
@@ -1433,7 +1289,7 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase)
                   base as being fed by r2
                */
 
-               rbase->fed_by.insert (r2);
+               rbase->add_fed_by (r2, i->sends_only);
 
                if (r2 != rbase) {
 
@@ -1441,7 +1297,7 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase)
                           stop here.
                        */
 
-                       if ((r1->fed_by.find (r2) != r1->fed_by.end()) && (r2->fed_by.find (r1) != r2->fed_by.end())) {
+                       if (r1->feeds (r2) && r2->feeds (r1)) {
                                continue;
                        }
 
@@ -1475,15 +1331,35 @@ Session::resort_routes ()
                /* writer goes out of scope and forces update */
        }
 
+#ifndef NDEBUG
+        boost::shared_ptr<RouteList> rl = routes.reader ();
+        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                DEBUG_TRACE (DEBUG::Graph, string_compose ("%1 fed by ...\n", (*i)->name()));
+                
+                const Route::FedBy& fb ((*i)->fed_by());
+
+                for (Route::FedBy::const_iterator f = fb.begin(); f != fb.end(); ++f) {
+                        boost::shared_ptr<Route> sf = f->r.lock();
+                        if (sf) {
+                                DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 (sends only ? %2)\n", sf->name(), f->sends_only));
+                        }
+                }
+        }
+#endif
+
 }
 void
 Session::resort_routes_using (shared_ptr<RouteList> r)
 {
        RouteList::iterator i, j;
 
+       for (i = r->begin(); i != r->end(); ++i) {
+                (*i)->check_physical_connections ();
+        }
+
        for (i = r->begin(); i != r->end(); ++i) {
 
-               (*i)->fed_by.clear ();
+               (*i)->clear_fed_by ();
 
                for (j = r->begin(); j != r->end(); ++j) {
 
@@ -1497,8 +1373,10 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
                                continue;
                        }
 
-                       if ((*j)->feeds (*i)) {
-                               (*i)->fed_by.insert (*j);
+                        bool via_sends_only;
+
+                       if ((*j)->direct_feeds (*i, &via_sends_only)) {
+                               (*i)->add_fed_by (*j, via_sends_only);
                        }
                }
        }
@@ -1510,77 +1388,178 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
        RouteSorter cmp;
        r->sort (cmp);
 
-#if 0
-       cerr << "finished route resort\n";
+        find_route_levels (r);
 
+#ifndef NDEBUG
+        DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               cerr << " " << (*i)->name() << " signal order = " << (*i)->order_key ("signal") << endl;
+               DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2 level %3\n", 
+                                                           (*i)->name(), (*i)->order_key ("signal"),
+                                                           (*i)->graph_level()));
        }
-       cerr << endl;
 #endif
 
 }
 
-list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_many)
+void
+Session::find_route_levels (shared_ptr<RouteList> rl)
+{
+        uint32_t setcnt = 0;
+        uint32_t limit = rl->size();
+        RouteList last_level;
+        RouteList this_level;
+
+        for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
+                
+                /* find routes with direct physical connections,
+                   or routes with no connections at all. Mark them
+                   with "special" level values, and push them into
+                   the "last_level" set.
+                
+                   All other routes get marked with a graph level
+                   of -1, which indicates that it needs to be set.
+
+                */
+                
+                if ((*r)->physically_connected()) {
+                        last_level.push_back (*r);
+                        (*r)->set_graph_level (0);
+                        setcnt++;
+                } else if (!(*r)->output()->connected()) {
+                        last_level.push_back (*r);
+                        (*r)->set_graph_level (INT32_MAX/2);
+                        setcnt++;
+                } else {
+                        (*r)->set_graph_level (-1);
+                }
+        }
+
+        // until we've set the graph level for every route ... 
+
+        while (setcnt < limit) {
+
+                for (RouteList::reverse_iterator r = rl->rbegin(); r != rl->rend(); ++r) {
+
+                        int32_t l = INT32_MAX;
+                        bool found = false;
+
+                        if ((*r)->graph_level() != -1) {
+                                // we already have the graph level for this route
+                                continue;
+                        }
+
+                        /* check if this route (r) has a direction connection to anything in
+                           the set of routes we processed last time. On the first pass
+                           through this, last_level will contain routes with either
+                           no connections or direct "physical" connections. If there is
+                           at least 1 connection, store the lowest graph level of whatever
+                           r is connected to.
+                        */
+
+                        for (RouteList::iterator o = last_level.begin(); o != last_level.end(); ++o) {
+                                bool sends_only;
+                                if ((*r)->direct_feeds (*o, &sends_only)) {
+                                        if (!sends_only) {
+                                                l = min (l, (*o)->graph_level());
+                                                found = true;
+                                        }
+                                }
+                        }
+
+                        /* if we found any connections, then mark the graph level of r, and push
+                           it into the "this_level" set that will become "last_level" next time
+                           around the while() loop.
+                        */
+
+                        if (found) {
+                                (*r)->set_graph_level (l + 1);
+                                this_level.push_back (*r);
+                                setcnt++;
+                        }
+                }
+
+                last_level = this_level;
+                this_level.clear ();
+        }
+}
+
+
+/** Find the route name starting with \a base with the lowest \a id.
+ *
+ * Names are constructed like e.g. "Audio 3" for base="Audio" and id=3.
+ * The available route name with the lowest ID will be used, and \a id
+ * will be set to the ID.
+ *
+ * \return false if a route name could not be found, and \a track_name
+ * and \a id do not reflect a free route name.
+ */
+bool
+Session::find_route_name (const char* base, uint32_t& id, char* name, size_t name_len)
 {
-       char track_name[32];
-       uint32_t track_id = 0;
-       uint32_t n = 0;
-       string port;
-       RouteList new_routes;
-       list<boost::shared_ptr<MidiTrack> > ret;
-       //uint32_t control_id;
+       do {
+               snprintf (name, name_len, "%s %" PRIu32, base, id);
 
-       // FIXME: need physical I/O and autoconnect stuff for MIDI
+               if (route_by_name (name) == 0) {
+                       return true;
+               }
 
-       /* count existing midi tracks */
+               ++id;
 
-       {
-               shared_ptr<RouteList> r = routes.reader ();
+       } while (id < (UINT_MAX-1));
 
-               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       if (boost::dynamic_pointer_cast<MidiTrack>(*i) != 0) {
-                               if (!(*i)->is_hidden()) {
-                                       n++;
-                                       //channels_used += (*i)->n_inputs().n_midi();
-                               }
-                       }
+       return false;
+}
+
+void
+Session::count_existing_route_channels (ChanCount& in, ChanCount& out)
+{
+       in  = ChanCount::ZERO;
+       out = ChanCount::ZERO;
+       shared_ptr<RouteList> r = routes.reader ();
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if (!(*i)->is_hidden()) {
+                       in += (*i)->n_inputs();
+                       out     += (*i)->n_outputs();
                }
        }
+}
 
-       vector<string> physinputs;
-       vector<string> physoutputs;
+list<boost::shared_ptr<MidiTrack> >
+Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_many)
+{
+       char track_name[32];
+       uint32_t track_id = 0;
+       ChanCount existing_inputs;
+       ChanCount existing_outputs;
+       string port;
+       RouteList new_routes;
+       list<boost::shared_ptr<MidiTrack> > ret;
+       uint32_t control_id;
 
-       _engine.get_physical_outputs (DataType::MIDI, physoutputs);
-       _engine.get_physical_inputs (DataType::MIDI, physinputs);
+       count_existing_route_channels (existing_inputs, existing_outputs);
 
-       // control_id = ntracks() + nbusses();
+       control_id = ntracks() + nbusses();
 
        while (how_many) {
+               if (!find_route_name ("Midi", ++track_id, track_name, sizeof(track_name))) {
+                       error << "cannot find name for new midi track" << endmsg;
+                       goto failed;
+               }
 
-               /* check for duplicate route names, since we might have pre-existing
-                  routes with this name (e.g. create Audio1, Audio2, delete Audio1,
-                  save, close,restart,add new route - first named route is now
-                  Audio2)
-               */
-
-
-               do {
-                       ++track_id;
-
-                       snprintf (track_name, sizeof(track_name), "Midi %" PRIu32, track_id);
+               shared_ptr<MidiTrack> track;
 
-                       if (route_by_name (track_name) == 0) {
-                               break;
-                       }
+               try {
+                       MidiTrack* mt = new MidiTrack (*this, track_name, Route::Flag (0), mode);
 
-               } while (track_id < (UINT_MAX-1));
+                        if (mt->init ()) {
+                                delete mt;
+                                goto failed;
+                        }
 
-               shared_ptr<MidiTrack> track;
+                        mt->use_new_diskstream();
 
-               try {
-                       track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode)));
+                       boost_debug_shared_ptr_mark_interesting (mt, "Track");
+                       track = boost::shared_ptr<MidiTrack>(mt);
 
                        if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
                                error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
@@ -1593,50 +1572,15 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
                                goto failed;
                        }
 
-                       /*
-                       if (nphysical_in) {
-                               for (uint32_t x = 0; x < track->n_inputs().n_midi() && x < nphysical_in; ++x) {
-
-                                       port = "";
-
-                                       if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                               port = physinputs[(channels_used+x)%nphysical_in];
-                                       }
-
-                                       if (port.length() && track->connect_input (track->input (x), port, this)) {
-                                               break;
-                                       }
-                               }
-                       }
-
-                       for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) {
-
-                               port = "";
-
-                               if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
-                                       port = physoutputs[(channels_used+x)%nphysical_out];
-                               } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                       if (_master_out) {
-                                               port = _master_out->input (x%_master_out->n_inputs().n_midi())->name();
-                                       }
-                               }
-
-                               if (port.length() && track->connect_output (track->output (x), port, this)) {
-                                       break;
-                               }
-                       }
-
-                       channels_used += track->n_inputs ().n_midi();
-
-                       */
+                       auto_connect_route (track, existing_inputs, existing_outputs);
 
-                       track->midi_diskstream()->non_realtime_input_change();
+                       track->non_realtime_input_change();
                        if (route_group) {
                                route_group->add (track);
                        }
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
-                       //track->set_remote_control_id (control_id);
+                       track->set_remote_control_id (control_id);
 
                        new_routes.push_back (track);
                        ret.push_back (track);
@@ -1644,36 +1588,12 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
 
                catch (failed_constructor &err) {
                        error << _("Session: could not create new midi track.") << endmsg;
-
-                       if (track) {
-                               /* we need to get rid of this, since the track failed to be created */
-                               /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
-
-                               {
-                                       RCUWriter<DiskstreamList> writer (diskstreams);
-                                       boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
-                                       ds->remove (track->midi_diskstream());
-                               }
-                       }
-
                        goto failed;
                }
 
                catch (AudioEngine::PortRegistrationFailure& pfe) {
 
-                       error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg;
-
-                       if (track) {
-                               /* we need to get rid of this, since the track failed to be created */
-                               /* XXX arguably, MidiTrack::MidiTrack should not do the Session::add_diskstream() */
-
-                               {
-                                       RCUWriter<DiskstreamList> writer (diskstreams);
-                                       boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
-                                       ds->remove (track->midi_diskstream());
-                               }
-                       }
-
+                       error << string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with ports if you need this many tracks."), PROGRAM_NAME) << endmsg;
                        goto failed;
                }
 
@@ -1689,126 +1609,141 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
        return ret;
 }
 
-list<boost::shared_ptr<AudioTrack> >
-Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group,  uint32_t how_many)
+void
+Session::auto_connect_route (boost::shared_ptr<Route> route,
+               ChanCount& existing_inputs, ChanCount& existing_outputs)
 {
-       char track_name[32];
-       uint32_t track_id = 0;
-       uint32_t n = 0;
-       uint32_t channels_used = 0;
-       string port;
-       RouteList new_routes;
-       list<boost::shared_ptr<AudioTrack> > ret;
-       uint32_t control_id;
+       /* If both inputs and outputs are auto-connected to physical ports,
+          use the max of input and output offsets to ensure auto-connected
+          port numbers always match up (e.g. the first audio input and the
+          first audio output of the route will have the same physical
+          port number).  Otherwise just use the lowest input or output
+          offset possible.
+       */
+       const bool in_out_physical =
+                  (Config->get_input_auto_connect() & AutoConnectPhysical)
+               && (Config->get_output_auto_connect() & AutoConnectPhysical);
 
-       /* count existing audio tracks */
+       const ChanCount in_offset = in_out_physical
+               ? ChanCount::max(existing_inputs, existing_outputs)
+               : existing_inputs;
 
-       {
-               shared_ptr<RouteList> r = routes.reader ();
+       const ChanCount out_offset = in_out_physical
+               ? ChanCount::max(existing_inputs, existing_outputs)
+               : existing_outputs;
 
-               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       if (boost::dynamic_pointer_cast<AudioTrack>(*i) != 0) {
-                               if (!(*i)->is_hidden()) {
-                                       n++;
-                                       channels_used += (*i)->n_inputs().n_audio();
+       static string empty_string;
+       string& port = empty_string;
+
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               vector<string> physinputs;
+               vector<string> physoutputs;
+
+               _engine.get_physical_outputs (*t, physoutputs);
+               _engine.get_physical_inputs (*t, physinputs);
+
+               if (!physinputs.empty()) {
+                       uint32_t nphysical_in = physinputs.size();
+                       for (uint32_t i = 0; i < route->n_inputs().get(*t) && i < nphysical_in; ++i) {
+                               port = empty_string;
+
+                               if (Config->get_input_auto_connect() & AutoConnectPhysical) {
+                                       port = physinputs[(in_offset.get(*t) + i) % nphysical_in];
+                               }
+
+                               if (!port.empty() && route->input()->connect (
+                                               route->input()->ports().port(*t, i), port, this)) {
+                                       break;
                                }
                        }
                }
-       }
-
-       vector<string> physinputs;
-       vector<string> physoutputs;
 
-       _engine.get_physical_outputs (DataType::AUDIO, physoutputs);
-       _engine.get_physical_inputs (DataType::AUDIO, physinputs);
+               if (!physoutputs.empty()) {
+                       uint32_t nphysical_out = physoutputs.size();
+                       for (uint32_t i = 0; i < route->n_outputs().get(*t); ++i) {
+                               port = empty_string;
 
-       control_id = ntracks() + nbusses() + 1;
-
-       while (how_many) {
+                               if (Config->get_output_auto_connect() & AutoConnectPhysical) {
+                                       port = physoutputs[(out_offset.get(*t) + i) % nphysical_out];
+                               } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
+                                       if (_master_out && _master_out->n_inputs().get(*t) > 0) {
+                                               port = _master_out->input()->ports().port(*t,
+                                                               i % _master_out->input()->n_ports().get(*t))->name();
+                                       }
+                               }
 
-               /* check for duplicate route names, since we might have pre-existing
-                  routes with this name (e.g. create Audio1, Audio2, delete Audio1,
-                  save, close,restart,add new route - first named route is now
-                  Audio2)
-               */
+                               if (!port.empty() && route->output()->connect (
+                                               route->output()->ports().port(*t, i), port, this)) {
+                                       break;
+                               }
+                       }
+               }
+       }
 
+       existing_inputs += route->n_inputs();
+       existing_outputs += route->n_outputs();
+}
 
-               do {
-                       ++track_id;
+list< boost::shared_ptr<AudioTrack> >
+Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, uint32_t how_many)
+{
+       char track_name[32];
+       uint32_t track_id = 0;
+       ChanCount existing_inputs;
+       ChanCount existing_outputs;
+       string port;
+       RouteList new_routes;
+       list<boost::shared_ptr<AudioTrack> > ret;
+       uint32_t control_id;
 
-                       snprintf (track_name, sizeof(track_name), "Audio %" PRIu32, track_id);
+       count_existing_route_channels (existing_inputs, existing_outputs);
 
-                       if (route_by_name (track_name) == 0) {
-                               break;
-                       }
+       control_id = ntracks() + nbusses() + 1;
 
-               } while (track_id < (UINT_MAX-1));
+       while (how_many) {
+               if (!find_route_name ("Audio", ++track_id, track_name, sizeof(track_name))) {
+                       error << "cannot find name for new audio track" << endmsg;
+                       goto failed;
+               }
 
                shared_ptr<AudioTrack> track;
 
                try {
                        AudioTrack* at = new AudioTrack (*this, track_name, Route::Flag (0), mode);
+
+                        if (at->init ()) {
+                                delete at;
+                                goto failed;
+                        }
+
+                        at->use_new_diskstream();
+
                        boost_debug_shared_ptr_mark_interesting (at, "Track");
                        track = boost::shared_ptr<AudioTrack>(at);
 
                        if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
-                               error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
+                               error << string_compose (
+                                                       _("cannot configure %1 in/%2 out configuration for new audio track"),
                                                         input_channels, output_channels)
                                      << endmsg;
                                goto failed;
                        }
 
                        if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
-                               error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
+                               error << string_compose (
+                                                       _("cannot configure %1 in/%2 out configuration for new audio track"),
                                                         input_channels, output_channels)
                                      << endmsg;
                                goto failed;
                        }
 
-                       if (!physinputs.empty()) {
-                               uint32_t nphysical_in = physinputs.size();
-
-                               for (uint32_t x = 0; x < track->n_inputs().n_audio() && x < nphysical_in; ++x) {
-
-                                       port = "";
-
-                                       if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                               port = physinputs[(channels_used+x)%nphysical_in];
-                                       }
-
-                                       if (port.length() && track->input()->connect (track->input()->nth(x), port, this)) {
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if (!physoutputs.empty()) {
-                               uint32_t nphysical_out = physoutputs.size();
-
-                               for (uint32_t x = 0; x < track->n_outputs().n_audio(); ++x) {
-                                       port = "";
-
-                                       if (Config->get_output_auto_connect() & AutoConnectPhysical) {
-                                               port = physoutputs[(channels_used+x)%nphysical_out];
-                                       } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                               if (_master_out && _master_out->n_inputs().n_audio() > 0) {
-                                                       port = _master_out->input()->nth (x % _master_out->input()->n_ports().n_audio())->name();
-                                               }
-                                       }
-
-                                       if (port.length() && track->output()->connect (track->output()->nth(x), port, this)) {
-                                               break;
-                                       }
-                               }
-                       }
-
-                       channels_used += track->n_inputs ().n_audio();
+                       auto_connect_route (track, existing_inputs, existing_outputs);
 
                        if (route_group) {
                                route_group->add (track);
                        }
 
-                       track->audio_diskstream()->non_realtime_input_change();
+                       track->non_realtime_input_change();
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
                        track->set_remote_control_id (control_id);
@@ -1820,36 +1755,12 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
                catch (failed_constructor &err) {
                        error << _("Session: could not create new audio track.") << endmsg;
-
-                       if (track) {
-                               /* we need to get rid of this, since the track failed to be created */
-                               /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
-
-                               {
-                                       RCUWriter<DiskstreamList> writer (diskstreams);
-                                       boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
-                                       ds->remove (track->audio_diskstream());
-                               }
-                       }
-
                        goto failed;
                }
 
                catch (AudioEngine::PortRegistrationFailure& pfe) {
 
                        error << pfe.what() << endmsg;
-
-                       if (track) {
-                               /* we need to get rid of this, since the track failed to be created */
-                               /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
-
-                               {
-                                       RCUWriter<DiskstreamList> writer (diskstreams);
-                                       boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
-                                       ds->remove (track->audio_diskstream());
-                               }
-                       }
-
                        goto failed;
                }
 
@@ -1896,56 +1807,31 @@ RouteList
 Session::new_audio_route (bool aux, int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many)
 {
        char bus_name[32];
-       uint32_t bus_id = 1;
-       uint32_t n = 0;
-       uint32_t channels_used = 0;
+       uint32_t bus_id = 0;
+       ChanCount existing_inputs;
+       ChanCount existing_outputs;
        string port;
        RouteList ret;
        uint32_t control_id;
 
-       /* count existing audio busses */
-
-       {
-               shared_ptr<RouteList> r = routes.reader ();
-
-               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       if (boost::dynamic_pointer_cast<Track>(*i) == 0) {
-                               /* its a bus ? */
-                               if (!(*i)->is_hidden() && (*i)->name() != _("master")) {
-                                       bus_id++;
-                                       n++;
-                                       channels_used += (*i)->n_inputs().n_audio();
-                               }
-                       }
-               }
-       }
-
-       vector<string> physinputs;
-       vector<string> physoutputs;
-
-       _engine.get_physical_outputs (DataType::AUDIO, physoutputs);
-       _engine.get_physical_inputs (DataType::AUDIO, physinputs);
-
-       n_physical_audio_outputs = physoutputs.size();
-       n_physical_audio_inputs = physinputs.size();
+       count_existing_route_channels (existing_inputs, existing_outputs);
 
        control_id = ntracks() + nbusses() + 1;
 
        while (how_many) {
-
-               do {
-                       snprintf (bus_name, sizeof(bus_name), "Bus %" PRIu32, bus_id);
-
-                       bus_id++;
-
-                       if (route_by_name (bus_name) == 0) {
-                               break;
-                       }
-
-               } while (bus_id < (UINT_MAX-1));
+               if (!find_route_name ("Bus", ++bus_id, bus_name, sizeof(bus_name))) {
+                       error << "cannot find name for new audio bus" << endmsg;
+                       goto failure;
+               }
 
                try {
                        Route* rt = new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO);
+
+                        if (rt->init ()) {
+                                delete rt;
+                                goto failure;
+                        }
+
                        boost_debug_shared_ptr_mark_interesting (rt, "Route");
                        shared_ptr<Route> bus (rt);
 
@@ -1964,35 +1850,7 @@ Session::new_audio_route (bool aux, int input_channels, int output_channels, Rou
                                goto failure;
                        }
 
-                       for (uint32_t x = 0; n_physical_audio_inputs && x < bus->input()->n_ports().n_audio(); ++x) {
-                               port = "";
-
-                               if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                       port = physinputs[((n+x)%n_physical_audio_inputs)];
-                               }
-
-                               if (port.length() && bus->input()->connect (bus->input()->nth (x), port, this)) {
-                                       break;
-                               }
-                       }
-
-                       for (uint32_t x = 0; n_physical_audio_outputs && x < bus->n_outputs().n_audio(); ++x) {
-                               port = "";
-
-                               if (Config->get_output_auto_connect() & AutoConnectPhysical) {
-                                       port = physoutputs[((n+x)%n_physical_outputs)];
-                               } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                       if (_master_out) {
-                                               port = _master_out->input()->nth (x%_master_out->input()->n_ports().n_audio())->name();
-                                       }
-                               }
-
-                               if (port.length() && bus->output()->connect (bus->output()->nth(x), port, this)) {
-                                       break;
-                               }
-                       }
-
-                       channels_used += bus->n_inputs ().n_audio();
+                       auto_connect_route (bus, existing_inputs, existing_outputs);
 
                        if (route_group) {
                                route_group->add (bus);
@@ -2038,7 +1896,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
        RouteList ret;
        uint32_t control_id;
        XMLTree tree;
-       uint32_t number = 1;
+       uint32_t number = 0;
 
        if (!tree.read (template_path.c_str())) {
                return ret;
@@ -2055,19 +1913,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                std::string node_name = IO::name_from_state (*node_copy.children().front());
 
                /* generate a new name by adding a number to the end of the template name */
-
-               do {
-                       snprintf (name, sizeof (name), "%s %" PRIu32, node_name.c_str(), number);
-
-                       number++;
-
-                       if (route_by_name (name) == 0) {
-                               break;
-                       }
-
-               } while (number < UINT_MAX);
-
-               if (number == UINT_MAX) {
+               if (!find_route_name (node_name.c_str(), ++number, name, sizeof(name))) {
                        fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
                        /*NOTREACHED*/
                }
@@ -2135,7 +1981,7 @@ Session::add_routes (RouteList& new_routes, bool save)
                   we will resort when done.
                */
 
-               if (!_control_out && IO::connecting_legal) {
+               if (!_monitor_out && IO::connecting_legal) {
                        resort_routes_using (r);
                }
        }
@@ -2146,7 +1992,7 @@ Session::add_routes (RouteList& new_routes, bool save)
                boost::shared_ptr<Route> r (*x);
 
                r->listen_changed.connect_same_thread (*this, boost::bind (&Session::route_listen_changed, this, _1, wpr));
-               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, wpr));
+               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2, wpr));
                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));
@@ -2156,20 +2002,30 @@ Session::add_routes (RouteList& new_routes, bool save)
                        _master_out = r;
                }
 
-               if (r->is_control()) {
-                       _control_out = r;
+               if (r->is_monitor()) {
+                       _monitor_out = r;
+               }
+
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (r);
+               if (tr) {
+                       tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
+                       track_playlist_changed (boost::weak_ptr<Track> (tr));
+                       tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_have_rec_enabled_track, this));
                }
        }
 
-       if (_control_out && IO::connecting_legal) {
+       if (_monitor_out && IO::connecting_legal) {
 
                for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
-                       if ((*x)->is_control() || (*x)->is_master()) {
-                               continue;
-                       }
-                       (*x)->listen_via (_control_out,
-                                         (Config->get_listen_position() == AfterFaderListen ? PostFader : PreFader),
-                                         false, false);
+                       if ((*x)->is_monitor()) {
+                                /* relax */
+                        } else if ((*x)->is_master()) {
+                                /* relax */
+                       } else {
+                                (*x)->listen_via (_monitor_out,
+                                                  (Config->get_listen_position() == AfterFaderListen ? PostFader : PreFader),
+                                                  false, false);
+                        }
                }
 
                resort_routes ();
@@ -2256,7 +2112,7 @@ 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_control() || dest->is_master()) {
+       if (dest->is_monitor() || dest->is_master()) {
                return;
        }
 
@@ -2266,7 +2122,7 @@ Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::
 
        for (RouteList::iterator i = senders->begin(); i != senders->end(); ++i) {
 
-               if ((*i)->is_control() || (*i)->is_master() || (*i) == dest) {
+               if ((*i)->is_monitor() || (*i)->is_master() || (*i) == dest) {
                        continue;
                }
 
@@ -2276,31 +2132,6 @@ Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::
        graph_reordered ();
 }
 
-void
-Session::add_diskstream (boost::shared_ptr<Diskstream> dstream)
-{
-       /* need to do this in case we're rolling at the time, to prevent false underruns */
-       dstream->do_refill_with_alloc ();
-
-       dstream->set_block_size (current_block_size);
-
-       {
-               RCUWriter<DiskstreamList> writer (diskstreams);
-               boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
-               ds->push_back (dstream);
-               /* writer goes out of scope, copies ds back to main */
-       }
-
-       dstream->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::diskstream_playlist_changed, this, boost::weak_ptr<Diskstream> (dstream)));
-       /* this will connect to future changes, and check the current length */
-       diskstream_playlist_changed (boost::weak_ptr<Diskstream> (dstream));
-
-       dstream->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_have_rec_enabled_diskstream, this));
-
-       dstream->prepare ();
-
-}
-
 void
 Session::remove_route (shared_ptr<Route> route)
 {
@@ -2319,15 +2150,15 @@ Session::remove_route (shared_ptr<Route> route)
                        _master_out = shared_ptr<Route> ();
                }
 
-               if (route == _control_out) {
+               if (route == _monitor_out) {
 
                        /* cancel control outs for all routes */
 
                        for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
-                               (*r)->drop_listen (_control_out);
+                               (*r)->drop_listen (_monitor_out);
                        }
 
-                       _control_out.reset ();
+                       _monitor_out.reset ();
                }
 
                update_route_solo_state ();
@@ -2335,22 +2166,6 @@ Session::remove_route (shared_ptr<Route> route)
                /* writer goes out of scope, forces route list update */
        }
 
-       boost::shared_ptr<Track> t;
-       boost::shared_ptr<Diskstream> ds;
-
-       if ((t = boost::dynamic_pointer_cast<Track>(route)) != 0) {
-               ds = t->diskstream();
-       }
-
-       if (ds) {
-
-               {
-                       RCUWriter<DiskstreamList> dsl (diskstreams);
-                       boost::shared_ptr<DiskstreamList> d = dsl.get_copy();
-                       d->remove (ds);
-               }
-       }
-
        find_current_end ();
 
        // We need to disconnect the routes inputs and outputs
@@ -2396,504 +2211,274 @@ Session::remove_route (shared_ptr<Route> route)
 
 void
 Session::route_mute_changed (void* /*src*/)
-{
-       set_dirty ();
-}
-
-void
-Session::route_listen_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
-{
-       boost::shared_ptr<Route> route = wpr.lock();
-       if (!route) {
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
-               return;
-       }
-
-       if (route->listening()) {
-               _listen_cnt++;
-       } else if (_listen_cnt > 0) {
-               _listen_cnt--;
-       }
-}
-
-void
-Session::route_solo_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
-{
-       if (solo_update_disabled) {
-               // We know already
-               return;
-       }
-
-       boost::shared_ptr<Route> route = wpr.lock ();
-
-       if (!route) {
-               /* should not happen */
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
-               return;
-       }
-
-       shared_ptr<RouteList> r = routes.reader ();
-       int32_t delta;
-
-       if (route->self_soloed()) {
-               delta = 1;
-       } else {
-               delta = -1;
-       }
-
-       /* now mod the solo level of all other routes except master & control outs
-          so that they will be silent if appropriate.
-       */
-
-       solo_update_disabled = true;
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               bool via_sends_only;
-
-               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_control() || (*i)->is_hidden()) {
-                       continue;
-               } else if ((*i)->feeds (route, &via_sends_only)) {
-                       if (!via_sends_only) {
-                               (*i)->mod_solo_by_others (delta);
-                       }
-               } 
-       }
-
-       /* make sure master is never muted by solo */
-
-       if (_master_out && route != _master_out && _master_out->soloed_by_others() == 0 && !_master_out->soloed()) {
-               _master_out->mod_solo_by_others (1);
-       }
-       /* ditto for control outs make sure master is never muted by solo */
-
-       if (_control_out && route != _control_out && _control_out && _control_out->soloed_by_others() == 0) {
-               _control_out->mod_solo_by_others (1);
-       }
-
-       solo_update_disabled = false;
-       update_route_solo_state (r);
-       SoloChanged (); /* EMIT SIGNAL */
-       set_dirty();
-}
-
-void
-Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
-{
-       /* now figure out if anything that matters is soloed */
-
-       bool something_soloed = false;
-
-       if (!r) {
-               r = routes.reader();
-       }
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->is_master() && !(*i)->is_control() && !(*i)->is_hidden() && (*i)->self_soloed()) {
-                       something_soloed = true;
-                       break;
-               }
-       }
-
-       if (something_soloed != _non_soloed_outs_muted) {
-               _non_soloed_outs_muted = something_soloed;
-               SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
-       }
-}
-
-boost::shared_ptr<RouteList> 
-Session::get_routes_with_internal_returns() const
-{
-       shared_ptr<RouteList> r = routes.reader ();
-       boost::shared_ptr<RouteList> rl (new RouteList);
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->internal_return ()) {
-                       rl->push_back (*i);
-               }
-       }
-       return rl;
-}
-
-shared_ptr<Route>
-Session::route_by_name (string name)
-{
-       shared_ptr<RouteList> r = routes.reader ();
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->name() == name) {
-                       return *i;
-               }
-       }
-
-       return shared_ptr<Route> ((Route*) 0);
-}
-
-shared_ptr<Route>
-Session::route_by_id (PBD::ID id)
-{
-       shared_ptr<RouteList> r = routes.reader ();
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->id() == id) {
-                       return *i;
-               }
-       }
-
-       return shared_ptr<Route> ((Route*) 0);
-}
-
-shared_ptr<Route>
-Session::route_by_remote_id (uint32_t id)
-{
-       shared_ptr<RouteList> r = routes.reader ();
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->remote_control_id() == id) {
-                       return *i;
-               }
-       }
-
-       return shared_ptr<Route> ((Route*) 0);
-}
-
-void
-Session::find_current_end ()
-{
-       if (_state_of_the_state & Loading) {
-               return;
-       }
-
-       nframes_t max = get_maximum_extent ();
-
-       if (max > end_location->end()) {
-               end_location->set_end (max);
-               set_dirty();
-               DurationChanged(); /* EMIT SIGNAL */
-       }
-}
-
-nframes_t
-Session::get_maximum_extent () const
-{
-       nframes_t max = 0;
-       nframes_t me;
-
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-       for (DiskstreamList::const_iterator i = dsl->begin(); i != dsl->end(); ++i) {
-               if ((*i)->destructive())  //ignore tape tracks when getting max extents
-                       continue;
-               boost::shared_ptr<Playlist> pl = (*i)->playlist();
-               if ((me = pl->get_maximum_extent()) > max) {
-                       max = me;
-               }
-       }
-
-       return max;
-}
-
-boost::shared_ptr<Diskstream>
-Session::diskstream_by_name (string name)
-{
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-               if ((*i)->name() == name) {
-                       return *i;
-               }
-       }
-
-       return boost::shared_ptr<Diskstream>((Diskstream*) 0);
-}
-
-boost::shared_ptr<Diskstream>
-Session::diskstream_by_id (const PBD::ID& id)
-{
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-               if ((*i)->id() == id) {
-                       return *i;
-               }
-       }
-
-       return boost::shared_ptr<Diskstream>((Diskstream*) 0);
-}
-
-/* Region management */
-
-string
-Session::new_region_name (string old)
-{
-       string::size_type last_period;
-       uint32_t number;
-       string::size_type len = old.length() + 64;
-       char buf[len];
-
-       if ((last_period = old.find_last_of ('.')) == string::npos) {
-
-               /* no period present - add one explicitly */
-
-               old += '.';
-               last_period = old.length() - 1;
-               number = 0;
-
-       } else {
-
-               number = atoi (old.substr (last_period+1).c_str());
-
-       }
-
-       while (number < (UINT_MAX-1)) {
-
-               RegionList::const_iterator i;
-               string sbuf;
-
-               number++;
-
-               snprintf (buf, len, "%s%" PRIu32, old.substr (0, last_period + 1).c_str(), number);
-               sbuf = buf;
-
-               for (i = regions.begin(); i != regions.end(); ++i) {
-                       if (i->second->name() == sbuf) {
-                               break;
-                       }
-               }
-
-               if (i == regions.end()) {
-                       break;
-               }
-       }
-
-       if (number != (UINT_MAX-1)) {
-               return buf;
-       }
-
-       error << string_compose (_("cannot create new name for region \"%1\""), old) << endmsg;
-       return old;
-}
-
-int
-Session::region_name (string& result, string base, bool newlevel)
-{
-       char buf[16];
-       string subbase;
-
-       if (base.find("/") != string::npos) {
-               base = base.substr(base.find_last_of("/") + 1);
-       }
-
-       if (base == "") {
-
-               Glib::Mutex::Lock lm (region_lock);
-
-               snprintf (buf, sizeof (buf), "%d", (int)regions.size() + 1);
-               result = "region.";
-               result += buf;
-
-       } else {
-
-               if (newlevel) {
-                       subbase = base;
-               } else {
-                       string::size_type pos;
-
-                       pos = base.find_last_of ('.');
-
-                       /* pos may be npos, but then we just use entire base */
-
-                       subbase = base.substr (0, pos);
-
-               }
-
-               {
-                       Glib::Mutex::Lock lm (region_lock);
-
-                       map<string,uint32_t>::iterator x;
-
-                       result = subbase;
-
-                       if ((x = region_name_map.find (subbase)) == region_name_map.end()) {
-                               result += ".1";
-                               region_name_map[subbase] = 1;
-                       } else {
-                               x->second++;
-                               snprintf (buf, sizeof (buf), ".%d", x->second);
-
-                               result += buf;
-                       }
-               }
-       }
-
-       return 0;
+{
+       set_dirty ();
 }
 
 void
-Session::add_region (boost::shared_ptr<Region> region)
+Session::route_listen_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
 {
-       vector<boost::shared_ptr<Region> > v;
-       v.push_back (region);
-       add_regions (v);
+       boost::shared_ptr<Route> route = wpr.lock();
+       if (!route) {
+               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
+               return;
+       }
+
+       if (route->listening()) {
+               _listen_cnt++;
+       } else if (_listen_cnt > 0) {
+               _listen_cnt--;
+       }
 }
 
 void
-Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
+Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_ptr<Route> wpr)
 {
-       bool added = false;
+        if (!self_solo_change) {
+                // session doesn't care about changes to soloed-by-others
+                return;
+        }
 
-       {
-               Glib::Mutex::Lock lm (region_lock);
+       if (solo_update_disabled) {
+               // We know already
+               return;
+       }
+
+       boost::shared_ptr<Route> route = wpr.lock ();
+
+       if (!route) {
+               /* should not happen */
+               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
+               return;
+       }
 
-               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+       shared_ptr<RouteList> r = routes.reader ();
+       int32_t delta;
 
-                       boost::shared_ptr<Region> region = *ii;
+       if (route->self_soloed()) {
+               delta = 1;
+       } else {
+               delta = -1;
+       }
 
-                       if (region == 0) {
+       solo_update_disabled = true;
 
-                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
+        /*
 
-                       } else {
+           solo a route:
+              for anything in the signal path for this route, increment its soloed-by-other count
+              for anything not in the signal path for this route, increment its muted-by-other count
 
-                               RegionList::iterator x;
+           unsolo a route:
+              for anything in the signal path for this route, decrement its soloed-by-other count
+              for anything not in the signal path for this route, decrement its muted-by-other count
 
-                               for (x = regions.begin(); x != regions.end(); ++x) {
+        */
 
-                                       if (region->region_list_equivalent (x->second)) {
-                                               break;
-                                       }
-                               }
+        RouteList uninvolved;
 
-                               if (x == regions.end()) {
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               bool via_sends_only;
 
-                                       pair<RegionList::key_type,RegionList::mapped_type> entry;
+               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
+                       continue;
+               } 
 
-                                       entry.first = region->id();
-                                       entry.second = region;
+                if ((*i)->graph_level () == route->graph_level()) {
+                        (*i)->mod_muted_by_others (delta);                        
+                }
 
-                                       pair<RegionList::iterator,bool> x = regions.insert (entry);
+                /* feed-backwards (other route to solo change route):
 
-                                       if (!x.second) {
-                                               return;
-                                       }
+                        if (*i) feeds the one whose solo status changed 
+                             it should be soloed by other if the change was -> solo OR de-soloed by other if change was -> !solo
+                        else 
+                             do nothing
+                            
+                 */
 
-                                       added = true;
-                               }
+                if ((*i)->feeds (route, &via_sends_only)) {
+                       if (!via_sends_only) {
+                               (*i)->mod_solo_by_others_upstream (delta);
                        }
-               }
-       }
-
-       /* mark dirty because something has changed even if we didn't
-          add the region to the region list.
-       */
+               } 
+                
+                /* feed-forward (solo change route to other routes):
+                    
+                      if the route whose solo status changed feeds (*i)
+                             do nothing
+                      else 
+                             mute if the change was -> solo OR demute if change was -> !solo
+                 */
 
-       set_dirty ();
+                if (route->feeds (*i, &via_sends_only)) {
+                        (*i)->mod_solo_by_others_downstream (delta);
+                }
+       }
 
-       if (added) {
+       solo_update_disabled = false;
+       update_route_solo_state (r);
+       SoloChanged (); /* EMIT SIGNAL */
+       set_dirty();
+}
 
-               vector<boost::weak_ptr<Region> > v;
-               boost::shared_ptr<Region> first_r;
+void
+Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
+{
+       /* now figure out if anything that matters is soloed (or is "listening")*/
 
-               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+       bool something_soloed = false;
+        uint32_t listeners = 0;
 
-                       boost::shared_ptr<Region> region = *ii;
+       if (!r) {
+               r = routes.reader();
+       }
 
-                       if (region == 0) {
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_hidden() && (*i)->self_soloed()) {
+                       something_soloed = true;
+                       break;
+               }
 
-                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
+                if (!(*i)->is_hidden() && (*i)->listening()) {
+                        if (Config->get_solo_control_is_listen_control()) {
+                                listeners++;
+                        } else {
+                                (*i)->set_listen (false, this);
+                        }
+                }
+       }
 
-                       } else {
-                               v.push_back (region);
+        if (something_soloed != _non_soloed_outs_muted) {
+                _non_soloed_outs_muted = something_soloed;
+                SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
+        }
 
-                               if (!first_r) {
-                                       first_r = region;
-                               }
-                       }
+        if (listeners) {
+                 _listen_cnt = listeners;
+        }
+}
 
-                       region->StateChanged.connect_same_thread (*this, boost::bind (&Session::region_changed, this, _1, boost::weak_ptr<Region>(region)));
-                       update_region_name_map (region);
-               }
+boost::shared_ptr<RouteList> 
+Session::get_routes_with_internal_returns() const
+{
+       shared_ptr<RouteList> r = routes.reader ();
+       boost::shared_ptr<RouteList> rl (new RouteList);
 
-               if (!v.empty()) {
-                       RegionsAdded (v); /* EMIT SIGNAL */
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if ((*i)->internal_return ()) {
+                       rl->push_back (*i);
                }
        }
+       return rl;
 }
 
-void
-Session::update_region_name_map (boost::shared_ptr<Region> region)
+bool
+Session::io_name_is_legal (const std::string& name)
+{
+        shared_ptr<RouteList> r = routes.reader ();
+        
+        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                if ((*i)->name() == name) {
+                        return false;
+                }
+                
+                if ((*i)->has_io_processor_named (name)) {
+                        return false;
+                }
+        }
+        
+        return true;
+}
+
+shared_ptr<Route>
+Session::route_by_name (string name)
 {
-       string::size_type last_period = region->name().find_last_of ('.');
+       shared_ptr<RouteList> r = routes.reader ();
 
-       if (last_period != string::npos && last_period < region->name().length() - 1) {
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if ((*i)->name() == name) {
+                       return *i;
+               }
+       }
 
-               string base = region->name().substr (0, last_period);
-               string number = region->name().substr (last_period+1);
-               map<string,uint32_t>::iterator x;
+       return shared_ptr<Route> ((Route*) 0);
+}
 
-               /* note that if there is no number, we get zero from atoi,
-                  which is just fine
-               */
+shared_ptr<Route>
+Session::route_by_id (PBD::ID id)
+{
+       shared_ptr<RouteList> r = routes.reader ();
 
-               region_name_map[base] = atoi (number);
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if ((*i)->id() == id) {
+                       return *i;
+               }
        }
+
+       return shared_ptr<Route> ((Route*) 0);
 }
 
-void
-Session::region_changed (Change what_changed, boost::weak_ptr<Region> weak_region)
+shared_ptr<Route>
+Session::route_by_remote_id (uint32_t id)
 {
-       boost::shared_ptr<Region> region (weak_region.lock ());
-
-       if (!region) {
-               return;
-       }
+       shared_ptr<RouteList> r = routes.reader ();
 
-       if (what_changed & Region::HiddenChanged) {
-               /* relay hidden changes */
-               RegionHiddenChange (region);
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if ((*i)->remote_control_id() == id) {
+                       return *i;
+               }
        }
 
-       if (what_changed & NameChanged) {
-               update_region_name_map (region);
-       }
+       return shared_ptr<Route> ((Route*) 0);
 }
 
 void
-Session::remove_region (boost::weak_ptr<Region> weak_region)
+Session::find_current_end ()
 {
-       RegionList::iterator i;
-       boost::shared_ptr<Region> region (weak_region.lock ());
-
-       if (!region) {
+       if (_state_of_the_state & Loading) {
                return;
        }
 
-       bool removed = false;
+       nframes_t max = get_maximum_extent ();
 
-       {
-               Glib::Mutex::Lock lm (region_lock);
+       if (max > _session_range_location->end()) {
+               _session_range_location->set_end (max);
+               set_dirty();
+               DurationChanged(); /* EMIT SIGNAL */
+       }
+}
 
-               if ((i = regions.find (region->id())) != regions.end()) {
-                       regions.erase (i);
-                       removed = true;
+nframes_t
+Session::get_maximum_extent () const
+{
+       nframes_t max = 0;
+       nframes_t me;
+       
+       boost::shared_ptr<RouteList> rl = routes.reader ();
+       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (!tr || tr->destructive()) {
+                       //ignore tape tracks when getting max extents
+                       continue;
+               }
+               
+               boost::shared_ptr<Playlist> pl = tr->playlist();
+               if ((me = pl->get_maximum_extent()) > max) {
+                       max = me;
                }
        }
 
-       /* mark dirty because something has changed even if we didn't
-          remove the region from the region list.
-       */
-
-       set_dirty();
-
-       if (removed) {
-                RegionRemoved(region); /* EMIT SIGNAL */
-       }
+       return max;
 }
 
+/* Region management */
+
 boost::shared_ptr<Region>
-Session::find_whole_file_parent (boost::shared_ptr<Region const> child)
+Session::find_whole_file_parent (boost::shared_ptr<Region const> child) const
 {
-       RegionList::iterator i;
+        const RegionFactory::RegionMap& regions (RegionFactory::regions());
+       RegionFactory::RegionMap::const_iterator i;
        boost::shared_ptr<Region> region;
 
        Glib::Mutex::Lock lm (region_lock);
@@ -2932,10 +2517,10 @@ Session::destroy_region (boost::shared_ptr<Region> region)
 
        for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
 
-                       (*i)->mark_for_remove ();
-                       (*i)->drop_references ();
-
-                       cerr << "source was not used by any playlist\n";
+                (*i)->mark_for_remove ();
+                (*i)->drop_references ();
+                
+                cerr << "source was not used by any playlist\n";
        }
 
        return 0;
@@ -2955,10 +2540,14 @@ Session::remove_last_capture ()
 {
        list<boost::shared_ptr<Region> > r;
 
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-               list<boost::shared_ptr<Region> >& l = (*i)->last_capture_regions();
+       boost::shared_ptr<RouteList> rl = routes.reader ();
+       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (!tr) {
+                       continue;
+               }
+               
+               list<boost::shared_ptr<Region> >& l = tr->last_capture_regions();
 
                if (!l.empty()) {
                        r.insert (r.end(), l.begin(), l.end());
@@ -2966,10 +2555,6 @@ Session::remove_last_capture ()
                }
        }
 
-       for (list<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
-               remove_region (*i);
-       }
-       
        destroy_regions (r);
 
        save_state (_current_snapshot_name);
@@ -2977,13 +2562,6 @@ Session::remove_last_capture ()
        return 0;
 }
 
-int
-Session::remove_region_from_region_list (boost::shared_ptr<Region> r)
-{
-       remove_region (r);
-       return 0;
-}
-
 /* Source Management */
 
 void
@@ -3310,10 +2888,9 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
 
 /** Create a new within-session audio source */
 boost::shared_ptr<AudioFileSource>
-Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bool destructive)
+Session::create_audio_source_for_session (size_t n_chans, string const & n, uint32_t chan, bool destructive)
 {
-       const size_t n_chans = ds.n_channels().n_audio();
-       const string name    = new_audio_source_name (ds.name(), n_chans, chan, destructive);
+       const string name    = new_audio_source_name (n, n_chans, chan, destructive);
        const string path    = new_source_path_from_name(DataType::AUDIO, name);
 
        return boost::dynamic_pointer_cast<AudioFileSource> (
@@ -3371,9 +2948,9 @@ Session::new_midi_source_name (const string& base)
 
 /** Create a new within-session MIDI source */
 boost::shared_ptr<MidiSource>
-Session::create_midi_source_for_session (MidiDiskstream& ds)
+Session::create_midi_source_for_session (string const & n)
 {
-       const string name = new_midi_source_name (ds.name());
+       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> (
@@ -3455,7 +3032,7 @@ Session::audition_region (boost::shared_ptr<Region> r)
 void
 Session::cancel_audition ()
 {
-       if (auditioner->active()) {
+       if (auditioner->auditioning()) {
                auditioner->cancel_audition ();
                AuditionActive (false); /* EMIT SIGNAL */
        }
@@ -3464,6 +3041,12 @@ Session::cancel_audition ()
 bool
 Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b)
 {
+        if (a->is_monitor()) { 
+                return true;
+        }
+        if (b->is_monitor()) {
+                return false;
+        }
        return a->order_key(N_("signal")) < b->order_key(N_("signal"));
 }
 
@@ -3508,27 +3091,12 @@ Session::is_auditioning () const
 {
        /* can be called before we have an auditioner object */
        if (auditioner) {
-               return auditioner->active();
+               return auditioner->auditioning();
        } else {
                return false;
        }
 }
 
-uint32_t
-Session::n_diskstreams () const
-{
-       uint32_t n = 0;
-
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-       for (DiskstreamList::const_iterator i = dsl->begin(); i != dsl->end(); ++i) {
-               if (!(*i)->hidden()) {
-                       n++;
-               }
-       }
-       return n;
-}
-
 void
 Session::graph_reordered ()
 {
@@ -3552,40 +3120,13 @@ Session::graph_reordered ()
           reflect any changes in latencies within the graph.
        */
 
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-               (*i)->set_capture_offset ();
-       }
-}
-
-void
-Session::add_processor (Processor* processor)
-{
-       /* Session does not own Processors (they belong to a Route) but we do want to track
-          the arrival and departure of port inserts, sends and returns for naming
-          purposes.
-       */
-       processor->DropReferences.connect_same_thread (*this, boost::bind (&Session::remove_processor, this, processor));
-       set_dirty();
-}
-
-void
-Session::remove_processor (Processor* processor)
-{
-       Send* send;
-       Return* retrn;
-       PortInsert* port_insert;
-
-       if ((port_insert = dynamic_cast<PortInsert *> (processor)) != 0) {
-               insert_bitset[port_insert->bit_slot()] = false;
-       } else if ((send = dynamic_cast<Send *> (processor)) != 0) {
-               send_bitset[send->bit_slot()] = false;
-       } else if ((retrn = dynamic_cast<Return *> (processor)) != 0) {
-               return_bitset[retrn->bit_slot()] = false;
+       boost::shared_ptr<RouteList> rl = routes.reader ();
+       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (tr) {
+                       tr->set_capture_offset ();
+               }
        }
-
-       set_dirty();
 }
 
 nframes_t
@@ -3675,7 +3216,7 @@ Session::bundle_by_name (string name) const
 }
 
 void
-Session::tempo_map_changed (Change)
+Session::tempo_map_changed (const PropertyChange&)
 {
        clear_clicks ();
 
@@ -3690,18 +3231,7 @@ Session::tempo_map_changed (Change)
 void
 Session::ensure_buffers (ChanCount howmany)
 {
-       if (current_block_size == 0) {
-               return; // too early? (is this ok?)
-       }
-
-       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-               size_t count = std::max(_scratch_buffers->available().get(*t), howmany.get(*t));
-               _scratch_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
-               _mix_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
-               _silent_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
-       }
-
-       allocate_pan_automation_buffers (current_block_size, howmany.n_audio(), false);
+        BufferManager::ensure_buffers (howmany);
 }
 
 void
@@ -3808,6 +3338,31 @@ Session::mark_insert_id (uint32_t id)
        insert_bitset[id] = true;
 }
 
+void
+Session::unmark_send_id (uint32_t id)
+{
+       if (id < send_bitset.size()) {
+                send_bitset[id] = false;
+        }
+}
+
+void
+Session::unmark_return_id (uint32_t id)
+{
+       if (id < return_bitset.size()) {
+                return_bitset[id] = false;
+        }
+}
+
+void
+Session::unmark_insert_id (uint32_t id)
+{
+       if (id < insert_bitset.size()) {
+                insert_bitset[id] = false;
+        }
+}
+
+
 /* Named Selection management */
 
 boost::shared_ptr<NamedSelection>
@@ -3860,10 +3415,12 @@ Session::remove_named_selection (boost::shared_ptr<NamedSelection> named_selecti
 void
 Session::reset_native_file_format ()
 {
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
-       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-               (*i)->reset_write_sources (false);
+       boost::shared_ptr<RouteList> rl = routes.reader ();
+       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (tr) {
+                       tr->reset_write_sources (false);
+               }
        }
 }
 
@@ -3895,33 +3452,8 @@ Session::route_name_internal (string n) const
        return false;
 }
 
-void
-Session::allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force)
-{
-       if (!force && howmany <= _npan_buffers) {
-               return;
-       }
-
-       if (_pan_automation_buffer) {
-
-               for (uint32_t i = 0; i < _npan_buffers; ++i) {
-                       delete [] _pan_automation_buffer[i];
-               }
-
-               delete [] _pan_automation_buffer;
-       }
-
-       _pan_automation_buffer = new pan_t*[howmany];
-
-       for (uint32_t i = 0; i < howmany; ++i) {
-               _pan_automation_buffer[i] = new pan_t[nframes];
-       }
-
-       _npan_buffers = howmany;
-}
-
 int
-Session::freeze (InterThreadInfo& itt)
+Session::freeze_all (InterThreadInfo& itt)
 {
        shared_ptr<RouteList> r = routes.reader ();
 
@@ -3933,7 +3465,7 @@ Session::freeze (InterThreadInfo& itt)
                        /* XXX this is wrong because itt.progress will keep returning to zero at the start
                           of every track.
                        */
-                       t->freeze (itt);
+                       t->freeze_me (itt);
                }
        }
 
@@ -3950,7 +3482,7 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
        boost::shared_ptr<AudioFileSource> fsource;
        uint32_t x;
        char buf[PATH_MAX+1];
-       ChanCount nchans(track.audio_diskstream()->n_channels());
+       ChanCount nchans(track.n_channels());
        nframes_t position;
        nframes_t this_chunk;
        nframes_t to_do;
@@ -3973,7 +3505,7 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
 
        /* call tree *MUST* hold route_lock */
 
-       if ((playlist = track.diskstream()->playlist()) == 0) {
+       if ((playlist = track.playlist()) == 0) {
                goto out;
        }
 
@@ -4069,9 +3601,14 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
 
                /* construct a region to represent the bounced material */
 
-               result = RegionFactory::create (srcs, 0,
-                               srcs.front()->length(srcs.front()->timeline_position()),
-                               region_name_from_path (srcs.front()->name(), true));
+               PropertyList plist;
+               
+               plist.add (Properties::start, 0);
+               plist.add (Properties::length, srcs.front()->length(srcs.front()->timeline_position()));
+               plist.add (Properties::name, region_name_from_path (srcs.front()->name(), true));
+               
+               result = RegionFactory::create (srcs, plist);
+                          
        }
 
   out:
@@ -4100,9 +3637,23 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
        return result;
 }
 
+gain_t*
+Session::gain_automation_buffer() const
+{
+        return ProcessThread::gain_automation_buffer ();
+}
+
+pan_t**
+Session::pan_automation_buffer() const
+{
+        return ProcessThread::pan_automation_buffer ();
+}
+
 BufferSet&
 Session::get_silent_buffers (ChanCount count)
 {
+        return ProcessThread::get_silent_buffers (count);
+#if 0
        assert(_silent_buffers->available() >= count);
        _silent_buffers->set_count(count);
 
@@ -4113,11 +3664,14 @@ Session::get_silent_buffers (ChanCount count)
        }
 
        return *_silent_buffers;
+#endif
 }
 
 BufferSet&
 Session::get_scratch_buffers (ChanCount count)
 {
+        return ProcessThread::get_scratch_buffers (count);
+#if 0
        if (count != ChanCount::ZERO) {
                assert(_scratch_buffers->available() >= count);
                _scratch_buffers->set_count(count);
@@ -4126,14 +3680,18 @@ Session::get_scratch_buffers (ChanCount count)
        }
 
        return *_scratch_buffers;
+#endif
 }
 
 BufferSet&
 Session::get_mix_buffers (ChanCount count)
 {
+        return ProcessThread::get_mix_buffers (count);
+#if 0
        assert(_mix_buffers->available() >= count);
        _mix_buffers->set_count(count);
        return *_mix_buffers;
+#endif
 }
 
 uint32_t
@@ -4203,28 +3761,34 @@ Session::sync_order_keys (std::string const & base)
        set_remote_control_ids ();
 }
 
-/** @return true if there is at least one record-enabled diskstream, otherwise false */
+/** @return true if there is at least one record-enabled track, otherwise false */
 bool
-Session::have_rec_enabled_diskstream () const
+Session::have_rec_enabled_track () const
 {
-       return g_atomic_int_get (&_have_rec_enabled_diskstream) == 1;
+       return g_atomic_int_get (&_have_rec_enabled_track) == 1;
 }
 
-/** Update the state of our rec-enabled diskstreams flag */
+/** Update the state of our rec-enabled tracks flag */
 void
-Session::update_have_rec_enabled_diskstream ()
+Session::update_have_rec_enabled_track ()
 {
-       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader ();
-       DiskstreamList::iterator i = dsl->begin ();
-       while (i != dsl->end () && (*i)->record_enabled () == false) {
+       boost::shared_ptr<RouteList> rl = routes.reader ();
+       RouteList::iterator i = rl->begin();
+       while (i != rl->end ()) {
+
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (tr && tr->record_enabled ()) {
+                       break;
+               }
+               
                ++i;
        }
 
-       int const old = g_atomic_int_get (&_have_rec_enabled_diskstream);
+       int const old = g_atomic_int_get (&_have_rec_enabled_track);
 
-       g_atomic_int_set (&_have_rec_enabled_diskstream, i != dsl->end () ? 1 : 0);
+       g_atomic_int_set (&_have_rec_enabled_track, i != rl->end () ? 1 : 0);
 
-       if (g_atomic_int_get (&_have_rec_enabled_diskstream) != old) {
+       if (g_atomic_int_get (&_have_rec_enabled_track) != old) {
                RecordStateChanged (); /* EMIT SIGNAL */
        }
 }
@@ -4247,7 +3811,7 @@ Session::listen_position_changed ()
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               (*i)->put_control_outs_at (p);
+               (*i)->put_monitor_send_at (p);
        }
 }
 
@@ -4256,11 +3820,11 @@ Session::solo_control_mode_changed ()
 {
        /* cancel all solo or all listen when solo control mode changes */
 
-       if (Config->get_solo_control_is_listen_control()) {
-               set_solo (routes.reader(), false);
-       } else {
-               set_listen (routes.reader(), false);
-       }
+        if (soloing()) {
+                set_solo (get_routes(), false);
+        } else if (listening()) {
+                set_listen (get_routes(), false);
+        }
 }
 
 void
@@ -4299,12 +3863,7 @@ Session::get_routes_with_regions_at (nframes64_t const p) const
                        continue;
                }
                
-               boost::shared_ptr<Diskstream> ds = tr->diskstream ();
-               if (!ds) {
-                       continue;
-               }
-
-               boost::shared_ptr<Playlist> pl = ds->playlist ();
+               boost::shared_ptr<Playlist> pl = tr->playlist ();
                if (!pl) {
                        continue;
                }