more loop/transport fixups; make visible PH track transport frame as an experiment...
[ardour.git] / libs / ardour / session.cc
index 4b0d618a3087727959e2c3313a22ffcc8280e3ea..c2141e62e630f39a64a39c4ba18220c4a069aa39 100644 (file)
 #include <cerrno>
 #include <unistd.h>
 #include <limits.h>
+#include <sys/time.h>
 
 #include <sigc++/bind.h>
 #include <sigc++/retype.h>
 
 #include <glibmm/thread.h>
 #include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
 
 #include <pbd/error.h>
 #include <glibmm/thread.h>
@@ -44,6 +46,7 @@
 #include <ardour/audioengine.h>
 #include <ardour/configuration.h>
 #include <ardour/session.h>
+#include <ardour/analyser.h>
 #include <ardour/audio_diskstream.h>
 #include <ardour/utils.h>
 #include <ardour/audioplaylist.h>
@@ -78,6 +81,12 @@ using namespace ARDOUR;
 using namespace PBD;
 using boost::shared_ptr;
 
+#ifdef __x86_64__
+static const int CPU_CACHE_ALIGN = 64;
+#else
+static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
+#endif
+
 const char* Session::_template_suffix = X_(".template");
 const char* Session::_statefile_suffix = X_(".ardour");
 const char* Session::_pending_suffix = X_(".pending");
@@ -88,18 +97,29 @@ const char* Session::dead_sound_dir_name = X_("dead_sounds");
 const char* Session::interchange_dir_name = X_("interchange");
 const char* Session::export_dir_name = X_("export");
 
-Session::compute_peak_t                                Session::compute_peak                   = 0;
+bool Session::_disable_all_loaded_plugins = false;
+
+Session::compute_peak_t                        Session::compute_peak           = 0;
+Session::find_peaks_t                  Session::find_peaks             = 0;
 Session::apply_gain_to_buffer_t                Session::apply_gain_to_buffer   = 0;
 Session::mix_buffers_with_gain_t       Session::mix_buffers_with_gain  = 0;
 Session::mix_buffers_no_gain_t         Session::mix_buffers_no_gain    = 0;
 
+sigc::signal<void,std::string> Session::Dialog;
 sigc::signal<int> Session::AskAboutPendingState;
+sigc::signal<int,nframes_t,nframes_t> Session::AskAboutSampleRateMismatch;
 sigc::signal<void> Session::SendFeedback;
 
 sigc::signal<void> Session::SMPTEOffsetChanged;
 sigc::signal<void> Session::StartTimeChanged;
 sigc::signal<void> Session::EndTimeChanged;
 
+sigc::signal<void> Session::AutoBindingOn;
+sigc::signal<void> Session::AutoBindingOff;
+
+
+sigc::signal<void, std::string, std::string> Session::Exported;
+
 int
 Session::find_session (string str, string& path, string& snapshot, bool& isnew)
 {
@@ -251,20 +271,27 @@ Session::find_session (string str, string& path, string& snapshot, bool& isnew)
 }
 
 Session::Session (AudioEngine &eng,
-                 string fullpath,
-                 string snapshot_name,
-                 string* mix_template)
+                 const string& fullpath,
+                 const string& snapshot_name,
+                 string mix_template)
 
        : _engine (eng),
+         mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
          _midi_port (default_midi_port),
          pending_events (2048),
+         state_tree (0),
+         _send_smpte_update (false),
+         midi_thread (pthread_t (0)),
          midi_requests (128), // the size of this should match the midi request pool size
          diskstreams (new DiskstreamList),
          routes (new RouteList),
          auditioner ((Auditioner*) 0),
+         _total_free_4k_blocks (0),
          _click_io ((IO*) 0),
+         click_data (0),
+         click_emphasis_data (0),
          main_outs (0)
 {
        bool new_session;
@@ -273,17 +300,17 @@ Session::Session (AudioEngine &eng,
                throw failed_constructor();
        }
 
-       cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
+       info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
 
-       n_physical_outputs = _engine.n_physical_outputs();
-       n_physical_inputs =  _engine.n_physical_inputs();
+       n_physical_audio_outputs = _engine.n_physical_audio_outputs();
+       n_physical_audio_inputs =  _engine.n_physical_audio_inputs();
 
        first_stage_init (fullpath, snapshot_name);
        
-       new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+       new_session = !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())) {
-                       cerr << "create failed\n";
                        destroy ();
                        throw failed_constructor ();
                }
@@ -319,13 +346,22 @@ Session::Session (AudioEngine &eng,
                  nframes_t initial_length)
 
        : _engine (eng),
+         mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
          _midi_port (default_midi_port),
          pending_events (2048),
+         state_tree (0),
+         _send_smpte_update (false),
+         midi_thread (pthread_t (0)),
          midi_requests (16),
          diskstreams (new DiskstreamList),
          routes (new RouteList),
+         auditioner ((Auditioner *) 0),
+         _total_free_4k_blocks (0),
+         _click_io ((IO *) 0),
+         click_data (0),
+         click_emphasis_data (0),
          main_outs (0)
 
 {
@@ -335,17 +371,17 @@ Session::Session (AudioEngine &eng,
                throw failed_constructor();
        }
 
-       cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
+       info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
 
-       n_physical_outputs = _engine.n_physical_outputs();
-       n_physical_inputs = _engine.n_physical_inputs();
+       n_physical_audio_outputs = _engine.n_physical_audio_outputs();
+       n_physical_audio_inputs = _engine.n_physical_audio_inputs();
 
-       if (n_physical_inputs) {
-               n_physical_inputs = max (requested_physical_in, n_physical_inputs);
+       if (n_physical_audio_inputs) {
+               n_physical_audio_inputs = max (requested_physical_in, n_physical_audio_inputs);
        }
 
-       if (n_physical_outputs) {
-               n_physical_outputs = max (requested_physical_out, n_physical_outputs);
+       if (n_physical_audio_outputs) {
+               n_physical_audio_outputs = max (requested_physical_out, n_physical_audio_outputs);
        }
 
        first_stage_init (fullpath, snapshot_name);
@@ -353,7 +389,7 @@ Session::Session (AudioEngine &eng,
        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, 0, initial_length)) {
+               if (create (new_session, string(), initial_length)) {
                        destroy ();
                        throw failed_constructor ();
                }
@@ -383,7 +419,7 @@ Session::Session (AudioEngine &eng,
                }
                
                if (!rl.empty()) {
-                       add_routes (rl);
+                       add_routes (rl, false);
                }
                
        }
@@ -396,17 +432,12 @@ Session::Session (AudioEngine &eng,
                throw failed_constructor ();
        }
        
-       store_recent_sessions(_name, _path);
+       store_recent_sessions (_name, _path);
        
-       bool was_dirty = dirty ();
-
        _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
 
-       Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
 
-       if (was_dirty) {
-               DirtyChanged (); /* EMIT SIGNAL */
-       }
+       Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
 }
 
 Session::~Session ()
@@ -424,6 +455,7 @@ Session::destroy ()
        remove_pending_capture_state ();
 
        _state_of_the_state = StateOfTheState (CannotSave|Deletion);
+
        _engine.remove_session ();
 
        GoingAway (); /* EMIT SIGNAL */
@@ -437,19 +469,16 @@ Session::destroy ()
        _history.clear ();
 
        /* clear state tree so that no references to objects are held any more */
-       
-       if (state_tree) {
-               delete state_tree;
-       }
+       delete state_tree;
 
        terminate_butler_thread ();
        terminate_midi_thread ();
        
-       if (click_data && click_data != default_click) {
+       if (click_data != default_click) {
                delete [] click_data;
        }
 
-       if (click_emphasis_data && click_emphasis_data != default_click_emphasis) {
+       if (click_emphasis_data != default_click_emphasis) {
                delete [] click_emphasis_data;
        }
 
@@ -568,14 +597,13 @@ Session::destroy ()
 
                tmp = i;
                ++tmp;
-
+               
                i->second->drop_references ();
-
+               
                i = tmp;
        }
-
        audio_sources.clear ();
-
+       
 #ifdef TRACK_DESTRUCTION
        cerr << "delete mix groups\n";
 #endif /* TRACK_DESTRUCTION */
@@ -618,19 +646,9 @@ Session::destroy ()
                i = tmp;
        }
 
-       if (butler_mixdown_buffer) {
-               delete [] butler_mixdown_buffer;
-       }
-
-       if (butler_gain_buffer) {
-               delete [] butler_gain_buffer;
-       }
-
        Crossfade::set_buffer_size (0);
 
-       if (mmc) {
-               delete mmc;
-       }
+       delete mmc;
 }
 
 void
@@ -654,13 +672,15 @@ Session::set_worst_io_latencies ()
 void
 Session::when_engine_running ()
 {
-       string first_physical_output;
-
        /* we don't want to run execute this again */
 
+       BootMessage (_("Set block size and sample rate"));
+
        set_block_size (_engine.frames_per_cycle());
        set_frame_rate (_engine.frame_rate());
 
+       BootMessage (_("Using configuration"));
+
        Config->map_parameters (mem_fun (*this, &Session::config_changed));
 
        /* every time we reconnect, recompute worst case output latencies */
@@ -698,17 +718,21 @@ Session::when_engine_running ()
 
                } else {
                        
-                       /* default state for Click */
-
-                       first_physical_output = _engine.get_nth_physical_output (0);
+                       /* default state for Click: dual-mono to first 2 physical outputs */
                        
-                       if (first_physical_output.length()) {
-                               if (_click_io->add_output_port (first_physical_output, this)) {
-                                       // relax, even though its an error
-                               } else {
-                                       _clicking = Config->get_clicking ();
+                       for (int physport = 0; physport < 2; ++physport) {
+                               string physical_output = _engine.get_nth_physical_audio_output (physport);
+                       
+                               if (physical_output.length()) {
+                                       if (_click_io->add_output_port (physical_output, this)) {
+                                               // relax, even though its an error
+                                       } 
                                }
                        }
+
+                       if (_click_io->n_outputs() > 0) {
+                               _clicking = Config->get_clicking ();
+                       }
                }
        }
 
@@ -716,6 +740,8 @@ Session::when_engine_running ()
                error << _("cannot setup Click I/O") << endmsg;
        }
 
+       BootMessage (_("Compute I/O Latencies"));
+
        set_worst_io_latencies ();
 
        if (_clicking) {
@@ -726,35 +752,37 @@ Session::when_engine_running ()
           to the physical outputs currently available
        */
 
+       BootMessage (_("Set up standard connections"));
+
        /* ONE: MONO */
 
-       for (uint32_t np = 0; np < n_physical_outputs; ++np) {
+       for (uint32_t np = 0; np < n_physical_audio_outputs; ++np) {
                char buf[32];
                snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
 
                Connection* c = new OutputConnection (buf, true);
 
                c->add_port ();
-               c->add_connection (0, _engine.get_nth_physical_output (np));
+               c->add_connection (0, _engine.get_nth_physical_audio_output (np));
 
                add_connection (c);
        }
 
-       for (uint32_t np = 0; np < n_physical_inputs; ++np) {
+       for (uint32_t np = 0; np < n_physical_audio_inputs; ++np) {
                char buf[32];
                snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
 
                Connection* c = new InputConnection (buf, true);
 
                c->add_port ();
-               c->add_connection (0, _engine.get_nth_physical_input (np));
+               c->add_connection (0, _engine.get_nth_physical_audio_input (np));
 
                add_connection (c);
        }
 
        /* TWO: STEREO */
 
-       for (uint32_t np = 0; np < n_physical_outputs; np +=2) {
+       for (uint32_t np = 0; np < n_physical_audio_outputs; np +=2) {
                char buf[32];
                snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2);
 
@@ -762,13 +790,13 @@ Session::when_engine_running ()
 
                c->add_port ();
                c->add_port ();
-               c->add_connection (0, _engine.get_nth_physical_output (np));
-               c->add_connection (1, _engine.get_nth_physical_output (np+1));
+               c->add_connection (0, _engine.get_nth_physical_audio_output (np));
+               c->add_connection (1, _engine.get_nth_physical_audio_output (np+1));
 
                add_connection (c);
        }
 
-       for (uint32_t np = 0; np < n_physical_inputs; np +=2) {
+       for (uint32_t np = 0; np < n_physical_audio_inputs; np +=2) {
                char buf[32];
                snprintf (buf, sizeof (buf), _("in %" PRIu32 "+%" PRIu32), np+1, np+2);
 
@@ -776,8 +804,8 @@ Session::when_engine_running ()
 
                c->add_port ();
                c->add_port ();
-               c->add_connection (0, _engine.get_nth_physical_input (np));
-               c->add_connection (1, _engine.get_nth_physical_input (np+1));
+               c->add_connection (0, _engine.get_nth_physical_audio_input (np));
+               c->add_connection (1, _engine.get_nth_physical_audio_input (np+1));
 
                add_connection (c);
        }
@@ -810,7 +838,7 @@ Session::when_engine_running ()
                        }
                        n = 0;
                        while ((int) _master_out->n_outputs() < _master_out->output_maximum()) {
-                               if (_master_out->add_output_port (_engine.get_nth_physical_output (n), this)) {
+                               if (_master_out->add_output_port (_engine.get_nth_physical_audio_output (n), this)) {
                                        error << _("cannot setup master outputs")
                                              << endmsg;
                                        break;
@@ -830,11 +858,15 @@ Session::when_engine_running ()
                }
                add_connection (c);
        } 
+       
+       BootMessage (_("Setup signal flow and plugins"));
 
        hookup_io ();
 
        /* catch up on send+insert cnts */
 
+       BootMessage (_("Catch up with send/insert state"));
+
        insert_cnt = 0;
        
        for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) {
@@ -864,17 +896,18 @@ Session::when_engine_running ()
 
        /* hook us up to the engine */
 
+       BootMessage (_("Connect to engine"));
+
        _engine.set_session (this);
 
 #ifdef HAVE_LIBLO
        /* and to OSC */
 
+       BootMessage (_("OSC startup"));
+
        osc->set_session (*this);
 #endif
     
-       _state_of_the_state = Clean;
-
-       DirtyChanged (); /* EMIT SIGNAL */
 }
 
 void
@@ -886,6 +919,7 @@ Session::hookup_io ()
 
        _state_of_the_state = StateOfTheState (_state_of_the_state | InitialConnecting);
 
+
        if (auditioner == 0) {
                
                /* we delay creating the auditioner till now because
@@ -908,6 +942,7 @@ Session::hookup_io ()
 
        if (_control_out) {
                uint32_t n;
+               vector<string> cports;
 
                while ((int) _control_out->n_inputs() < _control_out->input_maximum()) {
                        if (_control_out->add_input_port ("", this)) {
@@ -918,14 +953,27 @@ Session::hookup_io ()
                }
                n = 0;
                while ((int) _control_out->n_outputs() < _control_out->output_maximum()) {
-                       if (_control_out->add_output_port (_engine.get_nth_physical_output (n), this)) {
+                       if (_control_out->add_output_port (_engine.get_nth_physical_audio_output (n), this)) {
                                error << _("cannot set up master outputs")
                                      << endmsg;
                                break;
                        }
                        n++;
                }
-       }
+
+
+               uint32_t ni = _control_out->n_inputs();
+
+               for (n = 0; n < ni; ++n) {
+                       cports.push_back (_control_out->input(n)->name());
+               }
+
+               boost::shared_ptr<RouteList> r = routes.reader ();              
+
+               for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
+                       (*x)->set_control_outs (cports);
+               }
+       } 
 
        /* Tell all IO objects to connect themselves together */
 
@@ -941,6 +989,7 @@ Session::hookup_io ()
 
        _state_of_the_state = StateOfTheState (_state_of_the_state & ~InitialConnecting);
 
+
        /* now handle the whole enchilada as if it was one
           graph reorder event.
        */
@@ -965,8 +1014,15 @@ Session::playlist_length_changed ()
 }
 
 void
-Session::diskstream_playlist_changed (boost::shared_ptr<Diskstream> dstream)
+Session::diskstream_playlist_changed (boost::weak_ptr<Diskstream> wptr)
 {
+       boost::shared_ptr<Diskstream> dstream = wptr.lock();
+       
+       if (!dstream) {
+               return;
+
+       }
+
        boost::shared_ptr<Playlist> playlist;
 
        if ((playlist = dstream->playlist()) != 0) {
@@ -1052,9 +1108,9 @@ Session::auto_loop_changed (Location* location)
 
        if (transport_rolling() && play_loop) {
 
-               //if (_transport_frame < location->start() || _transport_frame > location->end()) {
+               // if (_transport_frame > location->end()) {
 
-               if (_transport_frame > location->end()) {
+               if (_transport_frame < location->start() || _transport_frame > location->end()) {
                        // relocate to beginning of loop
                        clear_events (Event::LocateRoll);
                        
@@ -1077,7 +1133,6 @@ Session::auto_loop_changed (Location* location)
        }       
 
        last_loopend = location->end();
-       
 }
 
 void
@@ -1115,6 +1170,10 @@ Session::set_auto_punch_location (Location* location)
        auto_punch_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_punch_changed));
 
        location->set_auto_punch (true, this);
+
+
+       auto_punch_changed (location);
+
        auto_punch_location_changed (location);
 }
 
@@ -1154,6 +1213,13 @@ Session::set_auto_loop_location (Location* location)
        auto_loop_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_loop_changed));
 
        location->set_auto_loop (true, this);
+
+       /* take care of our stuff first */
+
+       auto_loop_changed (location);
+
+       /* now tell everyone else */
+
        auto_loop_location_changed (location);
 }
 
@@ -1190,6 +1256,12 @@ 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 (!set_loop) {
@@ -1231,7 +1303,7 @@ Session::disable_record (bool rt_context, bool force)
 
        if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
 
-               if (!Config->get_latched_record_enable () || force) {
+               if ((!Config->get_latched_record_enable () && !play_loop) || force) {
                        g_atomic_int_set (&_record_status, Disabled);
                } else {
                        if (rs == Recording) {
@@ -1262,15 +1334,18 @@ Session::disable_record (bool rt_context, bool force)
 void
 Session::step_back_from_record ()
 {
-       g_atomic_int_set (&_record_status, Enabled);
+       /* XXX really atomic compare+swap here */
+       if (g_atomic_int_get (&_record_status) == Recording) {
+               g_atomic_int_set (&_record_status, Enabled);
 
-       if (Config->get_monitoring_model() == HardwareMonitoring) {
-               boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-               
-               for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                       if (Config->get_auto_input() && (*i)->record_enabled ()) {
-                               //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
-                               (*i)->monitor_input (false);   
+               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 ()) {
+                                       //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (false);   
+                               }
                        }
                }
        }
@@ -1306,6 +1381,10 @@ Session::audible_frame () const
        nframes_t offset;
        nframes_t tf;
 
+       if (_transport_speed == 0.0f && non_realtime_work_pending()) {
+               return last_stop_frame;
+       }
+
        /* the first of these two possible settings for "offset"
           mean that the audible frame is stationary until 
           audio emerges from the latency compensation
@@ -1334,24 +1413,43 @@ Session::audible_frame () const
        } else {
                tf = _transport_frame;
        }
-
-       if (_transport_speed == 0) {
-               return tf;
-       }
-
-       if (tf < offset) {
-               return 0;
-       }
-
+       
        ret = tf;
 
        if (!non_realtime_work_pending()) {
 
                /* MOVING */
 
-               /* take latency into account */
-               
-               ret -= offset;
+               /* check to see if we have passed the first guaranteed
+                  audible frame past our last stopping position. if not,
+                  the return that last stopping point because in terms
+                  of audible frames, we have not moved yet.
+               */
+
+               if (_transport_speed > 0.0f) {
+
+                       if (!play_loop || !have_looped) {
+                               if (tf < last_stop_frame + offset) {
+                                       return last_stop_frame;
+                                       
+                               }
+                       } 
+                       
+
+                       /* forwards */
+                       ret -= offset;
+
+               } else if (_transport_speed < 0.0f) {
+
+                       /* XXX wot? no backward looping? */
+
+                       if (tf > last_stop_frame - offset) {
+                               return last_stop_frame;
+                       } else {
+                               /* backwards */
+                               ret += offset;
+                       }
+               }
        }
 
        return ret;
@@ -1371,7 +1469,9 @@ Session::set_frame_rate (nframes_t frames_per_second)
 
        sync_time_vars();
 
-       Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25));
+       IO::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval())));
+
+       clear_clicks ();
 
        // XXX we need some equivalent to this, somehow
        // SndFileSource::setup_standard_crossfades (frames_per_second);
@@ -1395,7 +1495,7 @@ Session::set_block_size (nframes_t nframes)
                uint32_t np;
                        
                current_block_size = nframes;
-               
+
                for (np = 0, i = _passthru_buffers.begin(); i != _passthru_buffers.end(); ++i, ++np) {
                        free (*i);
                }
@@ -1416,7 +1516,7 @@ Session::set_block_size (nframes_t nframes)
 #ifdef NO_POSIX_MEMALIGN
                        buf = (Sample *) malloc(current_block_size * sizeof(Sample));
 #else
-                       posix_memalign((void **)&buf,16,current_block_size * 4);
+                       posix_memalign((void **)&buf,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample));
 #endif                 
                        *i = buf;
 
@@ -1656,8 +1756,8 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
        uint32_t nphysical_in;
        uint32_t nphysical_out;
 
-       _engine.get_physical_outputs (physoutputs);
-       _engine.get_physical_inputs (physinputs);
+       _engine.get_physical_audio_outputs (physoutputs);
+       _engine.get_physical_audio_inputs (physinputs);
        control_id = ntracks() + nbusses() + 1;
 
        while (how_many) {
@@ -1681,26 +1781,29 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                } while (track_id < (UINT_MAX-1));
 
                if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                       nphysical_in = min (n_physical_inputs, (uint32_t) physinputs.size());
+                       nphysical_in = min (n_physical_audio_inputs, (uint32_t) physinputs.size());
                } else {
                        nphysical_in = 0;
                }
                
                if (Config->get_output_auto_connect() & AutoConnectPhysical) {
-                       nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
+                       nphysical_out = min (n_physical_audio_outputs, (uint32_t) physinputs.size());
                } else {
                        nphysical_out = 0;
                }
+
+               shared_ptr<AudioTrack> track;
                
                try {
-                       shared_ptr<AudioTrack> track (new AudioTrack (*this, track_name, Route::Flag (0), mode));
+                       track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode)));
                        
                        if (track->ensure_io (input_channels, output_channels, false, this)) {
                                error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
                                                         input_channels, output_channels)
                                      << endmsg;
+                               goto failed;
                        }
-                       
+       
                        if (nphysical_in) {
                                for (uint32_t x = 0; x < track->n_inputs() && x < nphysical_in; ++x) {
                                        
@@ -1735,19 +1838,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                        
                        channels_used += track->n_inputs ();
 
-                       if (_control_out) {
-                               vector<string> cports;
-                               uint32_t ni = _control_out->n_inputs();
-                               
-                               for (n = 0; n < ni; ++n) {
-                                       cports.push_back (_control_out->input(n)->name());
-                               }
-                               
-                               track->set_control_outs (cports);
-                       }
-
-                       // assert (current_thread != RT_thread)
-                       
                        track->audio_diskstream()->non_realtime_input_change();
                        
                        track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes));
@@ -1756,21 +1846,50 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
                        new_routes.push_back (track);
                        ret.push_back (track);
+
                }
 
                catch (failed_constructor &err) {
                        error << _("Session: could not create new audio track.") << endmsg;
-                       // XXX should we delete the tracks already created? 
-                       ret.clear ();
-                       return ret;
+
+                       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;
+               }
+
                --how_many;
        }
 
+  failed:
        if (!new_routes.empty()) {
-               add_routes (new_routes, false);
-               save_state (_current_snapshot_name);
+               add_routes (new_routes, true);
        }
 
        return ret;
@@ -1814,7 +1933,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
-                               if (!(*i)->hidden()) {
+                               if (!(*i)->hidden() && (*i)->name() != _("master")) {
                                        bus_id++;
                                }
                        }
@@ -1824,17 +1943,17 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
        vector<string> physinputs;
        vector<string> physoutputs;
 
-       _engine.get_physical_outputs (physoutputs);
-       _engine.get_physical_inputs (physinputs);
+       _engine.get_physical_audio_outputs (physoutputs);
+       _engine.get_physical_audio_inputs (physinputs);
        control_id = ntracks() + nbusses() + 1;
 
        while (how_many) {
 
                do {
-                       ++bus_id;
-
                        snprintf (bus_name, sizeof(bus_name), "Bus %" PRIu32, bus_id);
 
+                       bus_id++;
+
                        if (route_by_name (bus_name) == 0) {
                                break;
                        }
@@ -1848,27 +1967,28 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
                                                         input_channels, output_channels)
                                      << endmsg;
+                               goto failure;
                        }
-                       
-                       for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs(); ++x) {
-                               
+                       /*
+                       for (uint32_t x = 0; n_physical_audio_inputs && x < bus->n_inputs(); ++x) {
+                                       
                                port = "";
-
+                               
                                if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                               port = physinputs[((n+x)%n_physical_inputs)];
+                                       port = physinputs[((n+x)%n_physical_audio_inputs)];
                                } 
                                
                                if (port.length() && bus->connect_input (bus->input (x), port, this)) {
                                        break;
                                }
                        }
-                       
-                       for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs(); ++x) {
+                       */
+                       for (uint32_t x = 0; n_physical_audio_outputs && x < bus->n_outputs(); ++x) {
                                
                                port = "";
                                
                                if (Config->get_output_auto_connect() & AutoConnectPhysical) {
-                                       port = physoutputs[((n+x)%n_physical_outputs)];
+                                       port = physoutputs[((n+x)%n_physical_audio_outputs)];
                                } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
                                        if (_master_out) {
                                                port = _master_out->input (x%_master_out->n_inputs())->name();
@@ -1880,16 +2000,6 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                }
                        }
                        
-                       if (_control_out) {
-                               vector<string> cports;
-                               uint32_t ni = _control_out->n_inputs();
-                               
-                               for (uint32_t n = 0; n < ni; ++n) {
-                                       cports.push_back (_control_out->input(n)->name());
-                               }
-                               bus->set_control_outs (cports);
-                       }
-
                        bus->set_remote_control_id (control_id);
                        ++control_id;
 
@@ -1899,20 +2009,133 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
 
                catch (failed_constructor &err) {
                        error << _("Session: could not create new audio route.") << endmsg;
-                       ret.clear ();
-                       return ret;
+                       goto failure;
+               }
+
+               catch (AudioEngine::PortRegistrationFailure& pfe) {
+                       error << pfe.what() << endmsg;
+                       goto failure;
                }
 
+
                --how_many;
        }
 
+  failure:
        if (!ret.empty()) {
-               add_routes (ret, false);
-               save_state (_current_snapshot_name);
+               add_routes (ret, true);
+       }
+
+       return ret;
+
+}
+
+Session::RouteList
+Session::new_route_from_template (uint32_t how_many, const std::string& template_path)
+{
+       char name[32];
+       RouteList ret;
+       uint32_t control_id;
+       XMLTree tree;
+       uint32_t number = 1;
+
+       if (!tree.read (template_path.c_str())) {
+               return ret;
+       }
+
+       XMLNode* node = tree.root();
+
+       control_id = ntracks() + nbusses() + 1;
+
+       while (how_many) {
+
+               XMLNode node_copy (*node); // make a copy so we can change the name if we need to
+         
+               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) {
+                       fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
+                               /*NOTREACHED*/
+               }
+               
+               IO::set_name_in_state (*node_copy.children().front(), name);
+
+               Track::zero_diskstream_id_in_xml (node_copy);
+               
+               try {
+                       shared_ptr<Route> route (XMLRouteFactory (node_copy));
+           
+                       if (route == 0) {
+                               error << _("Session: cannot create track/bus from template description") << endmsg;
+                               goto out;
+                       }
+
+                       if (boost::dynamic_pointer_cast<Track>(route)) {
+                               /* force input/output change signals so that the new diskstream
+                                  picks up the configuration of the route. During session
+                                  loading this normally happens in a different way.
+                               */
+                               route->input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
+                               route->output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
+                       }
+
+                       route->set_remote_control_id (control_id);
+                       ++control_id;
+           
+                       ret.push_back (route);
+               }
+         
+               catch (failed_constructor &err) {
+                       error << _("Session: could not create new route from template") << endmsg;
+                       goto out;
+               }
+         
+               catch (AudioEngine::PortRegistrationFailure& pfe) {
+                       error << pfe.what() << endmsg;
+                       goto out;
+               }
+         
+               --how_many;
+       }
+
+  out:
+       if (!ret.empty()) {
+               add_routes (ret, true);
        }
 
        return ret;
+}
+
+boost::shared_ptr<Route>
+Session::new_video_track (string name)
+{
+       uint32_t control_id = ntracks() + nbusses() + 1;
+       shared_ptr<Route> new_route (
+               new Route ( *this, name, -1, -1, -1, -1, Route::Flag(0), ARDOUR::DataType::NIL));
+       new_route->set_remote_control_id (control_id);
 
+       RouteList rl;
+       rl.push_back (new_route);
+        {
+               RCUWriter<RouteList> writer (routes);
+               shared_ptr<RouteList> r = writer.get_copy ();
+                r->insert (r->end(), rl.begin(), rl.end());
+               resort_routes_using (r);
+        }
+       return new_route;
 }
 
 void
@@ -1940,9 +2163,24 @@ Session::add_routes (RouteList& new_routes, bool save)
                
                if ((*x)->control()) {
                        _control_out = (*x);
-               }
+               } 
        }
 
+       if (_control_out && IO::connecting_legal) {
+
+               vector<string> cports;
+               uint32_t ni = _control_out->n_inputs();
+               uint32_t n;
+
+               for (n = 0; n < ni; ++n) {
+                       cports.push_back (_control_out->input(n)->name());
+               }
+
+               for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
+                       (*x)->set_control_outs (cports);
+               }
+       } 
+
        set_dirty();
 
        if (save) {
@@ -1956,17 +2194,19 @@ 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->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);
-       }
-
-       dstream->set_block_size (current_block_size);
+               /* writer goes out of scope, copies ds back to main */
+       } 
 
-       dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), dstream));
+       dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), 
+                                                     boost::weak_ptr<Diskstream> (dstream)));
        /* this will connect to future changes, and check the current length */
        diskstream_playlist_changed (dstream);
 
@@ -2023,17 +2263,20 @@ Session::remove_route (shared_ptr<Route> route)
                        boost::shared_ptr<DiskstreamList> d = dsl.get_copy();
                        d->remove (ds);
                }
+
+               diskstreams.flush ();
        }
 
        find_current_end ();
        
+       // We need to disconnect the routes inputs and outputs 
+
+       route->disconnect_inputs (0);
+       route->disconnect_outputs (0);
+       
        update_latency_compensation (false, false);
        set_dirty();
 
-       // We need to disconnect the routes inputs and outputs 
-       route->disconnect_inputs(NULL);
-       route->disconnect_outputs(NULL);
-       
        /* get rid of it from the dead wood collection in the route list manager */
 
        /* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
@@ -2044,6 +2287,8 @@ Session::remove_route (shared_ptr<Route> route)
 
        route->drop_references ();
 
+       sync_order_keys (N_("session"));
+
        /* save the new state of the world */
 
        if (save_state (_current_snapshot_name)) {
@@ -2086,7 +2331,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
                        
                        /* don't mess with busses */
                        
-                       if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*i) == 0) {
                                continue;
                        }
                        
@@ -2094,7 +2339,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
                        
                        /* don't mess with tracks */
                        
-                       if (dynamic_cast<AudioTrack*>((*i).get()) != 0) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*i) != 0) {
                                continue;
                        }
                }
@@ -2168,8 +2413,6 @@ Session::update_route_solo_state ()
        bool is_track = false;
        bool signal = false;
 
-       /* caller must hold RouteLock */
-
        /* this is where we actually implement solo by changing
           the solo mute setting of each track.
        */
@@ -2179,7 +2422,7 @@ Session::update_route_solo_state ()
         for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((*i)->soloed()) {
                        mute = true;
-                       if (dynamic_cast<AudioTrack*>((*i).get())) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*i)) {
                                is_track = true;
                        }
                        break;
@@ -2224,7 +2467,7 @@ Session::modify_solo_mute (bool is_track, bool mute)
                        
                        /* only alter track solo mute */
                        
-                       if (dynamic_cast<AudioTrack*>((*i).get())) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*i)) {
                                if ((*i)->soloed()) {
                                        (*i)->set_solo_mute (!mute);
                                } else {
@@ -2235,8 +2478,8 @@ Session::modify_solo_mute (bool is_track, bool mute)
                } else {
 
                        /* only alter bus solo mute */
-
-                       if (!dynamic_cast<AudioTrack*>((*i).get())) {
+                       
+                       if (!boost::dynamic_pointer_cast<AudioTrack>(*i)) {
 
                                if ((*i)->soloed()) {
 
@@ -2270,7 +2513,24 @@ Session::catch_up_on_solo ()
        */
        update_route_solo_state();
 }      
-               
+
+void
+Session::catch_up_on_solo_mute_override ()
+{
+       if (Config->get_solo_model() != InverseMute) {
+               return;
+       }
+
+       /* this is called whenever the param solo-mute-override is
+          changed.
+       */
+       shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               (*i)->catch_up_on_solo_mute_override ();
+       }
+}      
+
 shared_ptr<Route>
 Session::route_by_name (string name)
 {
@@ -2338,6 +2598,8 @@ Session::get_maximum_extent () const
        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;
@@ -2429,7 +2691,7 @@ Session::new_region_name (string old)
 }
 
 int
-Session::region_name (string& result, string base, bool newlevel) const
+Session::region_name (string& result, string base, bool newlevel)
 {
        char buf[16];
        string subbase;
@@ -2439,15 +2701,11 @@ Session::region_name (string& result, string base, bool newlevel) const
                Glib::Mutex::Lock lm (region_lock);
 
                snprintf (buf, sizeof (buf), "%d", (int)audio_regions.size() + 1);
-
-               
                result = "region.";
                result += buf;
 
        } else {
 
-               /* XXX this is going to be slow. optimize me later */
-               
                if (newlevel) {
                        subbase = base;
                } else {
@@ -2460,43 +2718,38 @@ Session::region_name (string& result, string base, bool newlevel) const
                        subbase = base.substr (0, pos);
 
                }
-
-               bool name_taken = true;
                
                {
                        Glib::Mutex::Lock lm (region_lock);
-                       
-                       for (int n = 1; n < 5000; ++n) {
-                               
-                               result = subbase;
-                               snprintf (buf, sizeof (buf), ".%d", n);
+
+                       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;
-                               
-                               name_taken = false;
-                               
-                               for (AudioRegionList::const_iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) {
-                                       if (i->second->name() == result) {
-                                               name_taken = true;
-                                               break;
-                                       }
-                               }
-                               
-                               if (!name_taken) {
-                                       break;
-                               }
                        }
                }
-                       
-               if (name_taken) {
-                       fatal << string_compose(_("too many regions with names like %1"), base) << endmsg;
-                       /*NOTREACHED*/
-               }
        }
+
        return 0;
 }      
 
 void
 Session::add_region (boost::shared_ptr<Region> region)
+{
+       vector<boost::shared_ptr<Region> > v;
+       v.push_back (region);
+       add_regions (v);
+}
+               
+void
+Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
 {
        boost::shared_ptr<AudioRegion> ar;
        boost::shared_ptr<AudioRegion> oar;
@@ -2505,56 +2758,110 @@ Session::add_region (boost::shared_ptr<Region> region)
        { 
                Glib::Mutex::Lock lm (region_lock);
 
-               if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
-
-                       AudioRegionList::iterator x;
-
-                       for (x = audio_regions.begin(); x != audio_regions.end(); ++x) {
+               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+               
+                       boost::shared_ptr<Region> region = *ii;
+                       
+                       if (region == 0) {
 
-                               oar = boost::dynamic_pointer_cast<AudioRegion> (x->second);
+                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
 
-                               if (ar->region_list_equivalent (oar)) {
-                                       break;
+                       } else if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
+                               
+                               AudioRegionList::iterator x;
+                               
+                               for (x = audio_regions.begin(); x != audio_regions.end(); ++x) {
+                                       
+                                       oar = boost::dynamic_pointer_cast<AudioRegion> (x->second);
+                                       
+                                       if (ar->region_list_equivalent (oar)) {
+                                               break;
+                                       }
                                }
+                               
+                               if (x == audio_regions.end()) {
+                                       
+                                       pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry;
+                                       
+                                       entry.first = region->id();
+                                       entry.second = ar;
+                                       
+                                       pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+                                       
+                                       if (!x.second) {
+                                               return;
+                                       }
+                                       
+                                       added = true;
+                               } 
+
+                       } else {
+                               
+                               fatal << _("programming error: ")
+                                     << X_("unknown region type passed to Session::add_region()")
+                                     << endmsg;
+                               /*NOTREACHED*/
+                               
                        }
+               }
+       }
 
-                       if (x == audio_regions.end()) {
+       /* mark dirty because something has changed even if we didn't
+          add the region to the region list.
+       */
+       
+       set_dirty ();
+       
+       if (added) {
 
-                               pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry;
+               vector<boost::weak_ptr<AudioRegion> > v;
+               boost::shared_ptr<AudioRegion> first_ar;
 
-                               entry.first = region->id();
-                               entry.second = ar;
+               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
 
-                               pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+                       boost::shared_ptr<Region> region = *ii;
+                       boost::shared_ptr<AudioRegion> ar;
 
-                               
-                               if (!x.second) {
-                                       return;
-                               }
+                       if (region == 0) {
 
-                               added = true;
-                       } 
+                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
 
-               } else {
+                       } else if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
+                               v.push_back (ar);
 
-                       fatal << _("programming error: ")
-                             << X_("unknown region type passed to Session::add_region()")
-                             << endmsg;
-                       /*NOTREACHED*/
+                               if (!first_ar) {
+                                       first_ar = ar;
+                               }
+                       }
 
+                       region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
+                       region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
+
+                       update_region_name_map (region);
+               }
+
+               if (!v.empty()) {
+                       AudioRegionsAdded (v); /* EMIT SIGNAL */
                }
        }
+}
 
-       /* mark dirty because something has changed even if we didn't
-          add the region to the region list.
-       */
-       
-       set_dirty();
+void
+Session::update_region_name_map (boost::shared_ptr<Region> region)
+{
+       string::size_type last_period = region->name().find_last_of ('.');
        
-       if (added) {
-               region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
-               region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
-               AudioRegionAdded (ar); /* EMIT SIGNAL */
+       if (last_period != string::npos && last_period < region->name().length() - 1) {
+               
+               string base = region->name().substr (0, last_period);
+               string number = region->name().substr (last_period+1);
+               map<string,uint32_t>::iterator x;
+               
+               /* note that if there is no number, we get zero from atoi,
+                  which is just fine
+               */
+               
+               region_name_map[base] = atoi (number);
        }
 }
 
@@ -2571,6 +2878,10 @@ Session::region_changed (Change what_changed, boost::weak_ptr<Region> weak_regio
                /* relay hidden changes */
                RegionHiddenChange (region);
        }
+
+       if (what_changed & NameChanged) {
+               update_region_name_map (region);
+       }
 }
 
 void
@@ -2711,6 +3022,9 @@ Session::remove_last_capture ()
        }
 
        destroy_regions (r);
+
+       save_state (_current_snapshot_name);
+
        return 0;
 }
 
@@ -2746,6 +3060,9 @@ Session::add_source (boost::shared_ptr<Source> source)
                        set_dirty();
                }
 
+               if (Config->get_auto_analyse_audio()) {
+                       Analyser::queue_source_for_analysis (source, false);
+               }
        } 
 }
 
@@ -2793,16 +3110,27 @@ Session::source_by_id (const PBD::ID& id)
        return source;
 }
 
-string
-Session::peak_path_from_audio_path (string audio_path) const
+
+boost::shared_ptr<Source>
+Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
 {
-       string res;
+       Glib::Mutex::Lock lm (audio_source_lock);
 
-       res = peak_dir ();
-       res += PBD::basename_nosuffix (audio_path);
-       res += ".peak";
+       for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ++i) {
+               boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(i->second);
 
-       return res;
+               if (afs && afs->path() == path && chn == afs->channel()) {
+                       return afs;
+               } 
+                      
+       }
+       return boost::shared_ptr<Source>();
+}
+
+Glib::ustring
+Session::peak_path (Glib::ustring base) const
+{
+       return Glib::build_filename(peak_dir (), base + ".peak");
 }
 
 string
@@ -3210,7 +3538,7 @@ Session::remove_empty_sounds ()
 {
        PathScanner scanner;
 
-       vector<string *>* possible_audiofiles = scanner (sound_dir(), "\\.(wav|aiff|caf|w64)$", false, true);
+       vector<string *>* possible_audiofiles = scanner (sound_dir(), "\\.(wav|aiff|caf|w64|L|R)$", false, true);
        
        Glib::Mutex::Lock lm (audio_source_lock);
        
@@ -3236,12 +3564,12 @@ Session::remove_empty_sounds ()
                        continue;
                }
                        
-               if (AudioFileSource::is_empty (*this, *(*i))) {
+               if (AudioFileSource::is_empty (*this, **i)) {
 
                        unlink ((*i)->c_str());
                        
-                       string peak_path = peak_path_from_audio_path (**i);
-                       unlink (peak_path.c_str());
+                       Glib::ustring peakpath = peak_path (PBD::basename_nosuffix (**i));
+                       unlink (peakpath.c_str());
                }
 
                delete* i;
@@ -3265,7 +3593,7 @@ void
 Session::set_all_solo (bool yn)
 {
        shared_ptr<RouteList> r = routes.reader ();
-       
+
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if (!(*i)->hidden()) {
                        (*i)->set_solo (yn, this);
@@ -3308,7 +3636,7 @@ void
 Session::graph_reordered ()
 {
        /* don't do this stuff if we are setting up connections
-          from a set_state() call.
+          from a set_state() call or creating new tracks.
        */
 
        if (_state_of_the_state & InitialConnecting) {
@@ -3442,6 +3770,10 @@ Session::available_capture_duration ()
                sample_bytes_on_disk = 3.0;
                break;
 
+       case FormatInt16:
+               sample_bytes_on_disk = 2.0;
+               break;
+
        default: 
                /* impossible, but keep some gcc versions happy */
                fatal << string_compose (_("programming error: %1"),
@@ -3512,18 +3844,36 @@ void
 Session::tempo_map_changed (Change ignored)
 {
        clear_clicks ();
+       
+       for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+               (*i)->update_after_tempo_map_change ();
+       }
+
+       for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+               (*i)->update_after_tempo_map_change ();
+       }
+
        set_dirty ();
 }
 
 void
 Session::ensure_passthru_buffers (uint32_t howmany)
 {
+       if (current_block_size == 0) {
+               return;
+       }
+
        while (howmany > _passthru_buffers.size()) {
                Sample *p;
 #ifdef NO_POSIX_MEMALIGN
                p =  (Sample *) malloc(current_block_size * sizeof(Sample));
 #else
-               posix_memalign((void **)&p,16,current_block_size * 4);
+               if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample)) != 0) {
+                       fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+                                                current_block_size, sizeof (Sample), strerror (errno))
+                             << endmsg;
+                       /*NOTREACHED*/
+               }
 #endif                 
                _passthru_buffers.push_back (p);
 
@@ -3532,7 +3882,12 @@ Session::ensure_passthru_buffers (uint32_t howmany)
 #ifdef NO_POSIX_MEMALIGN
                p =  (Sample *) malloc(current_block_size * sizeof(Sample));
 #else
-               posix_memalign((void **)&p,16,current_block_size * 4);
+               if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample)) != 0) {
+                       fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+                                                current_block_size, sizeof (Sample), strerror (errno))
+                             << endmsg;
+                       /*NOTREACHED*/
+               }
 #endif                 
                memset (p, 0, sizeof (Sample) * current_block_size);
                _silent_buffers.push_back (p);
@@ -3542,7 +3897,7 @@ Session::ensure_passthru_buffers (uint32_t howmany)
 #ifdef NO_POSIX_MEMALIGN
                p =  (Sample *) malloc(current_block_size * sizeof(Sample));
 #else
-               posix_memalign((void **)&p,16,current_block_size * 4);
+               posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample));
 #endif                 
                memset (p, 0, sizeof (Sample) * current_block_size);
                _send_buffers.push_back (p);
@@ -3560,7 +3915,6 @@ Session::next_insert_id ()
                for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < insert_bitset.size(); ++n) {
                        if (!insert_bitset[n]) {
                                insert_bitset[n] = true;
-                               cerr << "Returning " << n << " as insert ID\n";
                                return n;
                                
                        }
@@ -3581,7 +3935,6 @@ Session::next_send_id ()
                for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < send_bitset.size(); ++n) {
                        if (!send_bitset[n]) {
                                send_bitset[n] = true;
-                               cerr << "Returning " << n << " as send ID\n";
                                return n;
                                
                        }
@@ -3747,11 +4100,11 @@ Session::freeze (InterThreadInfo& itt)
        return 0;
 }
 
-int
-Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len,     
-                              bool overwrite, vector<boost::shared_ptr<AudioSource> >& srcs, InterThreadInfo& itt)
+boost::shared_ptr<Region>
+Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t end,     
+                              bool overwrite, vector<boost::shared_ptr<AudioSource> >& srcs, InterThreadInfo& itt, bool enable_processing)
 {
-       int ret = -1;
+       boost::shared_ptr<Region> result;
        boost::shared_ptr<Playlist> playlist;
        boost::shared_ptr<AudioFileSource> fsource;
        uint32_t x;
@@ -3761,12 +4114,21 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
        nframes_t position;
        nframes_t this_chunk;
        nframes_t to_do;
+       nframes_t len = end - start;
        vector<Sample*> buffers;
 
+       if (end <= start) {
+               error << string_compose (_("Cannot write a range where end <= start (e.g. %1 <= %2)"),
+                                        end, start) << endmsg;
+               return result;
+       }
+
        // any bigger than this seems to cause stack overflows in called functions
        const nframes_t chunk_size = (128 * 1024)/4;
 
-       g_atomic_int_set (&processing_prohibited, 1);
+       // block all process callback handling
+
+       block_processing ();
        
        /* call tree *MUST* hold route_lock */
        
@@ -3822,16 +4184,20 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
 #ifdef NO_POSIX_MEMALIGN
                b =  (Sample *) malloc(chunk_size * sizeof(Sample));
 #else
-               posix_memalign((void **)&b,16,chunk_size * 4);
+               posix_memalign((void **)&b,4096,chunk_size * sizeof(Sample));
 #endif                 
                buffers.push_back (b);
        }
 
+       for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
+               (*src)->prepare_for_peakfile_writes ();
+       }
+                       
        while (to_do && !itt.cancel) {
                
                this_chunk = min (to_do, chunk_size);
                
-               if (track.export_stuff (buffers, nchans, start, this_chunk)) {
+               if (track.export_stuff (buffers, nchans, start, this_chunk, enable_processing)) {
                        goto out;
                }
 
@@ -3865,56 +4231,79 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
 
                        if (afs) {
                                afs->update_header (position, *xnow, now);
+                               afs->flush_header ();
                        }
                }
                
-               /* build peakfile for new source */
-               
-               for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
-                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
-                       if (afs) {
-                               afs->build_peaks ();
-                       }
-               }
-
                /* construct a region to represent the bounced material */
 
-               boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(), 
-                                                                          region_name_from_path (srcs.front()->name(), true));
-
-               ret = 0;
+               result = RegionFactory::create (srcs, 0, srcs.front()->length(), 
+                                               region_name_from_path (srcs.front()->name(), true));
        }
                
   out:
-       if (ret) {
+       if (!result) {
                for (vector<boost::shared_ptr<AudioSource> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
                        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
 
                        if (afs) {
                                afs->mark_for_remove ();
                        }
-
+                       
                        (*src)->drop_references ();
                }
+
+       } else {
+               for (vector<boost::shared_ptr<AudioSource> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
+                       (*src)->done_with_peakfile_writes ();
+               }
        }
 
        for (vector<Sample*>::iterator i = buffers.begin(); i != buffers.end(); ++i) {
-               free(*i);
+               free (*i);
        }
 
-       g_atomic_int_set (&processing_prohibited, 0);
+       unblock_processing ();
 
        itt.done = true;
 
-       return ret;
+       return result;
 }
 
 vector<Sample*>&
 Session::get_silent_buffers (uint32_t howmany)
 {
+       if (howmany > _silent_buffers.size()) {
+
+               error << string_compose (_("Programming error: get_silent_buffers() called for %1 buffers but only %2 exist"),
+                                        howmany, _silent_buffers.size()) << endmsg;
+
+               if (howmany > 1000) {
+                       cerr << "ABSURD: more than 1000 silent buffers requested!\n";
+                       abort ();
+               }
+               
+               while (howmany > _silent_buffers.size()) {
+                       Sample *p = 0;
+                       
+#ifdef NO_POSIX_MEMALIGN
+                       p =  (Sample *) malloc(current_block_size * sizeof(Sample));
+#else
+                       if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample)) != 0) {
+                               fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+                                                        current_block_size, sizeof (Sample), strerror (errno))
+                                     << endmsg;
+                               /*NOTREACHED*/
+                       }
+#endif                 
+                       _silent_buffers.push_back (p);
+               }
+       }
+
        for (uint32_t i = 0; i < howmany; ++i) {
                memset (_silent_buffers[i], 0, sizeof (Sample) * current_block_size);
        }
+
        return _silent_buffers;
 }
 
@@ -3960,3 +4349,19 @@ Session::compute_initial_length ()
        return _engine.frame_rate() * 60 * 5;
 }
 
+void
+Session::sync_order_keys (const char* base)
+{
+       if (!Config->get_sync_all_route_ordering()) {
+               /* leave order keys as they are */
+               return;
+       }
+
+       boost::shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               (*i)->sync_order_keys (base);
+       }
+
+       Route::SyncOrderKeys (base); // EMIT SIGNAL
+}