handle no audio-output AUs
[ardour.git] / libs / ardour / audio_diskstream.cc
index 30dd556735988f9c817e372617ea3014259eb826..330b9d582acda0367d509993f54c0b1b2b98e339 100644 (file)
@@ -16,7 +16,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include <fstream>
 #include <cstdio>
 #include <unistd.h>
 #include <cmath>
 #include <fcntl.h>
 #include <cstdlib>
 #include <ctime>
-#include <sys/stat.h>
-#include <sys/mman.h>
 
+#include "pbd/gstdio_compat.h"
 #include "pbd/error.h"
-#include <glibmm/thread.h>
 #include "pbd/xml++.h"
 #include "pbd/memento_command.h"
 #include "pbd/enumwriter.h"
 #include "pbd/stateful_diff_command.h"
 
 #include "ardour/analyser.h"
-#include "ardour/ardour.h"
 #include "ardour/audio_buffer.h"
 #include "ardour/audio_diskstream.h"
 #include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/audiofilesource.h"
-
 #include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
 #include "ardour/butler.h"
-#include "ardour/configuration.h"
-#include "ardour/cycle_timer.h"
 #include "ardour/debug.h"
 #include "ardour/io.h"
 #include "ardour/playlist_factory.h"
+#include "ardour/profile.h"
 #include "ardour/region_factory.h"
-#include "ardour/send.h"
 #include "ardour/session.h"
+#include "ardour/session_playlists.h"
+#include "ardour/sndfile_helpers.h"
 #include "ardour/source_factory.h"
+#include "ardour/track.h"
+#include "ardour/types.h"
 #include "ardour/utils.h"
-#include "ardour/session_playlists.h"
-#include "ardour/route.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 #include <locale.h>
 
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-size_t  AudioDiskstream::_working_buffers_size = 0;
 Sample* AudioDiskstream::_mixdown_buffer       = 0;
 gain_t* AudioDiskstream::_gain_buffer          = 0;
 
 AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
        : Diskstream(sess, name, flag)
-       , deprecated_io_node(NULL)
        , channels (new ChannelList)
 {
        /* prevent any write sources from being created */
@@ -82,11 +75,14 @@ AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream:
        in_set_state = true;
        use_new_playlist ();
        in_set_state = false;
+
+       if (flag & Destructive) {
+               use_destructive_playlist ();
+       }
 }
 
 AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node)
        : Diskstream(sess, node)
-       , deprecated_io_node(NULL)
        , channels (new ChannelList)
 {
        in_set_state = true;
@@ -132,18 +128,18 @@ AudioDiskstream::~AudioDiskstream ()
        }
 
        channels.flush ();
-
-       delete deprecated_io_node;
 }
 
 void
 AudioDiskstream::allocate_working_buffers()
 {
-       assert(disk_io_frames() > 0);
-
-       _working_buffers_size = disk_io_frames();
-       _mixdown_buffer       = new Sample[_working_buffers_size];
-       _gain_buffer          = new gain_t[_working_buffers_size];
+       /* with varifill buffer refilling, we compute the read size in bytes (to optimize
+          for disk i/o bandwidth) and then convert back into samples. These buffers
+          need to reflect the maximum size we could use, which is 4MB reads, or 2M samples
+          using 16 bit samples.
+       */
+       _mixdown_buffer       = new Sample[2*1048576];
+       _gain_buffer          = new gain_t[2*1048576];
 }
 
 void
@@ -151,7 +147,6 @@ AudioDiskstream::free_working_buffers()
 {
        delete [] _mixdown_buffer;
        delete [] _gain_buffer;
-       _working_buffers_size = 0;
        _mixdown_buffer       = 0;
        _gain_buffer          = 0;
 }
@@ -159,14 +154,21 @@ AudioDiskstream::free_working_buffers()
 void
 AudioDiskstream::non_realtime_input_change ()
 {
+       bool need_write_sources = false;
+
        {
-               Glib::Mutex::Lock lm (state_lock);
+               Glib::Threads::Mutex::Lock lm (state_lock);
 
                if (input_change_pending.type == IOChange::NoChange) {
                        return;
                }
 
-               {
+               boost::shared_ptr<ChannelList> cr = channels.reader();
+               if (!cr->empty() && !cr->front()->write_source) {
+                       need_write_sources = true;
+               }
+
+               if (input_change_pending.type & IOChange::ConfigurationChanged) {
                        RCUWriter<ChannelList> writer (channels);
                        boost::shared_ptr<ChannelList> c = writer.get_copy();
 
@@ -177,15 +179,13 @@ AudioDiskstream::non_realtime_input_change ()
                        } else if (_io->n_ports().n_audio() < _n_channels.n_audio()) {
                                remove_channel_from (c, _n_channels.n_audio() - _io->n_ports().n_audio());
                        }
-               }
 
-               get_input_sources ();
-               set_capture_offset ();
+                       need_write_sources = true;
+               }
 
-               if (first_input_change) {
-                       set_align_style (_persistent_alignment_style);
-                       first_input_change = false;
-               } else {
+               if (input_change_pending.type & IOChange::ConnectionsChanged) {
+                       get_input_sources ();
+                       set_capture_offset ();
                        set_align_style_from_io ();
                }
 
@@ -194,9 +194,9 @@ AudioDiskstream::non_realtime_input_change ()
                /* implicit unlock */
        }
 
-       /* reset capture files */
-
-       reset_write_sources (false);
+       if (need_write_sources) {
+               reset_write_sources (false);
+       }
 
        /* now refill channel buffers */
 
@@ -213,9 +213,9 @@ AudioDiskstream::non_realtime_locate (framepos_t location)
        /* now refill channel buffers */
 
        if (speed() != 1.0f || speed() != -1.0f) {
-               seek ((framepos_t) (location * (double) speed()));
+               seek ((framepos_t) (location * (double) speed()), true);
        } else {
-               seek (location);
+               seek (location, true);
        }
 }
 
@@ -233,16 +233,13 @@ AudioDiskstream::get_input_sources ()
 
                connections.clear ();
 
-               if (_io->nth (n)->get_connections (connections) == 0) {
-
-                       if ((*chan)->source) {
+               if ((_io->nth (n).get()) && (_io->nth (n)->get_connections (connections) == 0)) {
+                       if (!(*chan)->source.name.empty()) {
                                // _source->disable_metering ();
                        }
-
-                       (*chan)->source = 0;
-
+                       (*chan)->source.name = string();
                } else {
-                       (*chan)->source = dynamic_cast<AudioPort*>(_session.engine().get_port_by_name (connections[0]) );
+                       (*chan)->source.name = connections[0];
                }
        }
 }
@@ -292,7 +289,6 @@ AudioDiskstream::use_new_playlist ()
 
        if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (DataType::AUDIO, _session, newname, hidden()))) != 0) {
 
-               playlist->set_orig_diskstream_id (id());
                return use_playlist (playlist);
 
        } else {
@@ -320,7 +316,6 @@ AudioDiskstream::use_copy_playlist ()
        newname = Playlist::bump_name (_playlist->name(), _session);
 
        if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist>(PlaylistFactory::create (audio_playlist(), newname))) != 0) {
-               playlist->set_orig_diskstream_id (id());
                return use_playlist (playlist);
        } else {
                return -1;
@@ -344,10 +339,13 @@ AudioDiskstream::setup_destructive_playlist ()
        PropertyList plist;
        plist.add (Properties::name, _name.val());
        plist.add (Properties::start, 0);
-       plist.add (Properties::length, max_framepos - (max_framepos - srcs.front()->natural_position()));
+       plist.add (Properties::length, max_framepos - srcs.front()->natural_position());
 
        boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist));
        _playlist->add_region (region, srcs.front()->natural_position());
+
+       /* apply region properties and update write sources */
+       use_destructive_playlist();
 }
 
 void
@@ -359,7 +357,14 @@ AudioDiskstream::use_destructive_playlist ()
           with the (presumed single, full-extent) region.
        */
 
-       boost::shared_ptr<Region> rp = _playlist->find_next_region (_session.current_start_frame(), Start, 1);
+       boost::shared_ptr<Region> rp;
+       {
+               const RegionList& rl (_playlist->region_list_property().rlist());
+               if (rl.size() > 0) {
+                       assert((rl.size() == 1));
+                       rp = rl.front();
+               }
+       }
 
        if (!rp) {
                reset_write_sources (false, true);
@@ -372,9 +377,9 @@ AudioDiskstream::use_destructive_playlist ()
                throw failed_constructor();
        }
 
-       /* be sure to stretch the region out to the maximum length */
+       /* be sure to stretch the region out to the maximum length (non-musical)*/
 
-       region->set_length (max_framepos - region->position(), this);
+       region->set_length (max_framepos - region->position(), 0);
 
        uint32_t n;
        ChannelList::iterator chan;
@@ -400,12 +405,12 @@ AudioDiskstream::prepare_record_status(framepos_t capture_start_frame)
                boost::shared_ptr<ChannelList> c = channels.reader();
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
 
-                       RingBufferNPT<CaptureTransition>::rw_vector transvec;
-                       (*chan)->capture_transition_buf->get_write_vector(&transvec);
+                       RingBufferNPT<CaptureTransition>::rw_vector transitions;
+                       (*chan)->capture_transition_buf->get_write_vector (&transitions);
 
-                       if (transvec.len[0] > 0) {
-                               transvec.buf[0]->type = CaptureStart;
-                               transvec.buf[0]->capture_val = capture_start_frame;
+                       if (transitions.len[0] > 0) {
+                               transitions.buf[0]->type = CaptureStart;
+                               transitions.buf[0]->capture_val = capture_start_frame;
                                (*chan)->capture_transition_buf->increment_write_ptr(1);
                        } else {
                                // bad!
@@ -416,18 +421,27 @@ AudioDiskstream::prepare_record_status(framepos_t capture_start_frame)
        }
 }
 
+
+/** Do some record stuff [not described in this comment!]
+ *
+ *  Also:
+ *    - Setup playback_distance with the nframes, or nframes adjusted
+ *      for current varispeed, if appropriate.
+ *    - Setup current_playback_buffer in each ChannelInfo to point to data
+ *      that someone can read playback_distance worth of data from.
+ */
 int
-AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler)
+AudioDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal)
 {
        uint32_t n;
        boost::shared_ptr<ChannelList> c = channels.reader();
        ChannelList::iterator chan;
-       int ret = -1;
        framecnt_t rec_offset = 0;
        framecnt_t rec_nframes = 0;
        bool collect_playback = false;
+       bool can_record = _session.actively_recording ();
 
-        playback_distance = 0;
+       playback_distance = 0;
 
        if (!_io || !_io->active()) {
                return 0;
@@ -439,9 +453,9 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
                return 0;
        }
 
-        Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK);
+       Glib::Threads::Mutex::Lock sm (state_lock, Glib::Threads::TRY_LOCK);
 
-        if (!sm.locked()) {
+       if (!sm.locked()) {
                return 1;
        }
 
@@ -452,31 +466,27 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
                (*chan)->current_playback_buffer = 0;
        }
 
-        /* two conditions to test for here:
-           
-           A: this track is rec-enabled, and the session has confirmed that we can record
-           B: this track is rec-enabled, has been recording, and we are set up for auto-punch-in
+       // Safeguard against situations where process() goes haywire when autopunching
+       // and last_recordable_frame < first_recordable_frame
 
-           The second test is necessary to capture the extra material that arrives AFTER the transport
-           frame has left the punch range (which will cause the "can_record" argument to be false).
-        */
+       if (last_recordable_frame < first_recordable_frame) {
+               last_recordable_frame = max_framepos;
+       }
 
+       if (record_enabled()) {
 
-        // Safeguard against situations where process() goes haywire when autopunching 
-        // and last_recordable_frame < first_recordable_frame
+               Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
+               // XXX should this be transport_frame + nframes - 1 ? coverage() expects its parameter ranges to include their end points
+               // XXX also, first_recordable_frame & last_recordable_frame may both be == max_framepos: coverage() will return OverlapNone in that case. Is thak OK?
+               calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
 
-        if (last_recordable_frame < first_recordable_frame) {
-                last_recordable_frame = max_framepos;
-        }
-        
-        OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
+               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: this time record %2 of %3 frames, offset %4\n", _name, rec_nframes, nframes, rec_offset));
 
-        calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
-        
-        if (rec_nframes && !was_recording) {
-                capture_captured = 0;
-                was_recording = true;
-        }
+               if (rec_nframes && !was_recording) {
+                       capture_captured = 0;
+                       was_recording = true;
+               }
+       }
 
        if (can_record && !_last_capture_sources.empty()) {
                _last_capture_sources.clear ();
@@ -507,25 +517,28 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
                                   for recording, and use rec_offset
                                */
 
-                               AudioPort* const ap = _io->audio (n);
+                               boost::shared_ptr<AudioPort> const ap = _io->audio (n);
                                assert(ap);
                                assert(rec_nframes <= (framecnt_t) ap->get_audio_buffer(nframes).capacity());
-                               memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer (nframes).data(rec_offset), sizeof (Sample) * rec_nframes);
 
+                               Sample *buf = bufs.get_audio (n).data(rec_offset);
+                               memcpy (chaninfo->current_capture_buffer, buf, sizeof (Sample) * rec_nframes);
 
                        } else {
 
                                framecnt_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1];
 
                                if (rec_nframes > total) {
+                                        DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 overrun in %2, rec_nframes = %3 total space = %4\n",
+                                                                                    DEBUG_THREAD_SELF, name(), rec_nframes, total));
                                        DiskOverrun ();
-                                       goto out;
+                                       return -1;
                                }
 
-                               AudioPort* const ap = _io->audio (n);
+                               boost::shared_ptr<AudioPort> const ap = _io->audio (n);
                                assert(ap);
 
-                               Sample* buf = ap->get_audio_buffer(nframes).data();
+                               Sample *buf = bufs.get_audio (n).data(rec_offset);
                                framecnt_t first = chaninfo->capture_vector.len[0];
 
                                memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first);
@@ -540,7 +553,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
        } else {
 
                if (was_recording) {
-                       finish_capture (rec_monitors_input, c);
+                       finish_capture (c);
                }
 
        }
@@ -585,7 +598,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
                collect_playback = true;
        }
 
-       if (collect_playback) {
+       if ((_track->monitoring_state () & MonitoringDisk) || collect_playback) {
 
                /* we're doing playback */
 
@@ -593,8 +606,8 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
 
                /* no varispeed playback if we're recording, because the output .... TBD */
 
-               if (rec_nframes == 0 && _actual_speed != 1.0f) {
-                       necessary_samples = (framecnt_t) floor ((nframes * fabs (_actual_speed))) + 1;
+               if (rec_nframes == 0 && _actual_speed != 1.0) {
+                       necessary_samples = (framecnt_t) ceil ((nframes * fabs (_actual_speed))) + 2;
                } else {
                        necessary_samples = nframes;
                }
@@ -605,12 +618,17 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
 
                n = 0;
 
+               /* Setup current_playback_buffer in each ChannelInfo to point to data that someone
+                  can read necessary_samples (== nframes at a transport speed of 1) worth of data
+                  from right now.
+               */
+
                for (chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
                        ChannelInfo* chaninfo (*chan);
 
                        if (necessary_samples <= (framecnt_t) chaninfo->playback_vector.len[0]) {
-
+                               /* There are enough samples in the first part of the ringbuffer */
                                chaninfo->current_playback_buffer = chaninfo->playback_vector.buf[0];
 
                        } else {
@@ -619,14 +637,26 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
                                if (necessary_samples > total) {
                                        cerr << _name << " Need " << necessary_samples << " total = " << total << endl;
                                        cerr << "underrun for " << _name << endl;
+                                        DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 underrun in %2, rec_nframes = %3 total space = %4\n",
+                                                                                    DEBUG_THREAD_SELF, name(), rec_nframes, total));
                                        DiskUnderrun ();
-                                       goto out;
+                                       return -1;
 
                                } else {
 
+                                       /* We have enough samples, but not in one lump.  Coalesce the two parts
+                                          into one in playback_wrap_buffer in our ChannelInfo, and specify that
+                                          as our current_playback_buffer.
+                                       */
+
+                                       assert(wrap_buffer_size >= necessary_samples);
+
+                                       /* Copy buf[0] from playback_buf */
                                        memcpy ((char *) chaninfo->playback_wrap_buffer,
                                                        chaninfo->playback_vector.buf[0],
                                                        chaninfo->playback_vector.len[0] * sizeof (Sample));
+
+                                       /* Copy buf[1] from playback_buf */
                                        memcpy (chaninfo->playback_wrap_buffer + chaninfo->playback_vector.len[0],
                                                        chaninfo->playback_vector.buf[1],
                                                        (necessary_samples - chaninfo->playback_vector.len[0])
@@ -638,45 +668,100 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
                }
 
                if (rec_nframes == 0 && _actual_speed != 1.0f && _actual_speed != -1.0f) {
-                       process_varispeed_playback(nframes, c);
+
+                       interpolation.set_speed (_target_speed);
+
+                       int channel = 0;
+                       for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) {
+                               ChannelInfo* chaninfo (*chan);
+
+                               playback_distance = interpolation.interpolate (
+                                       channel, nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer);
+
+                               chaninfo->current_playback_buffer = chaninfo->speed_buffer;
+                       }
+
                } else {
                        playback_distance = nframes;
                }
 
                _speed = _target_speed;
+       }
 
-       } 
+       if (need_disk_signal) {
 
-       ret = 0;
+               /* copy data over to buffer set */
 
-        if (commit (nframes)) {
-                need_butler = true;
-        }
+               size_t n_buffers = bufs.count().n_audio();
+               size_t n_chans = c->size();
+               gain_t scaling = 1.0f;
 
-  out:
-       return ret;
-}
+               if (n_chans > n_buffers) {
+                       scaling = ((float) n_buffers)/n_chans;
+               }
 
-void
-AudioDiskstream::process_varispeed_playback (pframes_t nframes, boost::shared_ptr<ChannelList> c)
-{
-       ChannelList::iterator chan;
+               for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
-       interpolation.set_speed (_target_speed);
+                       AudioBuffer& buf (bufs.get_audio (n%n_buffers));
+                       ChannelInfo* chaninfo (*chan);
 
-       int channel = 0;
-       for (chan = c->begin(); chan != c->end(); ++chan, ++channel) {
-               ChannelInfo* chaninfo (*chan);
+                       if (n < n_chans) {
+                               if (scaling != 1.0f) {
+                                       buf.read_from_with_gain (chaninfo->current_playback_buffer, nframes, scaling);
+                               } else {
+                                       buf.read_from (chaninfo->current_playback_buffer, nframes);
+                               }
+                       } else {
+                               if (scaling != 1.0f) {
+                                       buf.accumulate_with_gain_from (chaninfo->current_playback_buffer, nframes, scaling);
+                               } else {
+                                       buf.accumulate_from (chaninfo->current_playback_buffer, nframes);
+                               }
+                       }
+               }
+
+               /* leave the MIDI count alone */
+               ChanCount cnt (DataType::AUDIO, n_chans);
+               cnt.set (DataType::MIDI, bufs.count().n_midi());
+               bufs.set_count (cnt);
+
+               /* extra buffers will already be silent, so leave them alone */
+       }
+
+       return 0;
+}
+
+frameoffset_t
+AudioDiskstream::calculate_playback_distance (pframes_t nframes)
+{
+       frameoffset_t playback_distance = nframes;
 
-               playback_distance = interpolation.interpolate (
-                               channel, nframes, chaninfo->current_playback_buffer, chaninfo->speed_buffer);
+       if (record_enabled()) {
+               playback_distance = nframes;
+       } else if (_actual_speed != 1.0f && _actual_speed != -1.0f) {
+               interpolation.set_speed (_target_speed);
+               boost::shared_ptr<ChannelList> c = channels.reader();
+               int channel = 0;
+               for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) {
+                       playback_distance = interpolation.interpolate (channel, nframes, NULL, NULL);
+               }
+       } else {
+               playback_distance = nframes;
+       }
 
-               chaninfo->current_playback_buffer = chaninfo->speed_buffer;
+       if (_actual_speed < 0.0) {
+               return -playback_distance;
+       } else {
+               return playback_distance;
        }
 }
 
+/** Update various things including playback_sample, read pointer on each channel's playback_buf
+ *  and write pointer on each channel's capture_buf.  Also wout whether the butler is needed.
+ *  @return true if the butler is required.
+ */
 bool
-AudioDiskstream::commit (framecnt_t /* nframes */)
+AudioDiskstream::commit (framecnt_t playback_distance)
 {
        bool need_butler = false;
 
@@ -702,13 +787,14 @@ AudioDiskstream::commit (framecnt_t /* nframes */)
 
        if (adjust_capture_position != 0) {
                capture_captured += adjust_capture_position;
+               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 now captured %2 (by %3)\n", name(), capture_captured, adjust_capture_position));
                adjust_capture_position = 0;
        }
-       
+
        if (c->empty()) {
                return false;
        }
-       
+
        if (_slaved) {
                if (_io && _io->active()) {
                        need_butler = c->front()->playback_buf->write_space() >= c->front()->playback_buf->bufsize() / 2;
@@ -717,10 +803,10 @@ AudioDiskstream::commit (framecnt_t /* nframes */)
                }
        } else {
                if (_io && _io->active()) {
-                       need_butler = ((framecnt_t) c->front()->playback_buf->write_space() >= disk_io_chunk_frames)
-                               || ((framecnt_t) c->front()->capture_buf->read_space() >= disk_io_chunk_frames);
+                       need_butler = ((framecnt_t) c->front()->playback_buf->write_space() >= disk_read_chunk_frames)
+                               || ((framecnt_t) c->front()->capture_buf->read_space() >= disk_write_chunk_frames);
                } else {
-                       need_butler = ((framecnt_t) c->front()->capture_buf->read_space() >= disk_io_chunk_frames);
+                       need_butler = ((framecnt_t) c->front()->capture_buf->read_space() >= disk_write_chunk_frames);
                }
        }
 
@@ -750,7 +836,7 @@ AudioDiskstream::overwrite_existing_buffers ()
                _pending_overwrite = false;
                return 0;
        }
-       
+
        Sample* mixdown_buffer;
        float* gain_buffer;
        int ret = -1;
@@ -764,7 +850,9 @@ AudioDiskstream::overwrite_existing_buffers ()
        mixdown_buffer = new Sample[size];
        gain_buffer = new float[size];
 
-       /* reduce size so that we can fill the buffer correctly. */
+       /* reduce size so that we can fill the buffer correctly (ringbuffers
+          can only handle size-1, otherwise they appear to be empty)
+       */
        size--;
 
        uint32_t n=0;
@@ -788,9 +876,9 @@ AudioDiskstream::overwrite_existing_buffers ()
 
                framecnt_t to_read = size - overwrite_offset;
 
-               if (read ((*chan)->playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, start, to_read, *chan, n, reversed)) {
+               if (read ((*chan)->playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, start, to_read, n, reversed)) {
                        error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"),
-                                        _id, size, playback_sample) << endmsg;
+                                               id(), size, playback_sample) << endmsg;
                        goto out;
                }
 
@@ -798,10 +886,9 @@ AudioDiskstream::overwrite_existing_buffers ()
 
                        cnt -= to_read;
 
-                       if (read ((*chan)->playback_buf->buffer(), mixdown_buffer, gain_buffer,
-                                 start, cnt, *chan, n, reversed)) {
+                       if (read ((*chan)->playback_buf->buffer(), mixdown_buffer, gain_buffer, start, cnt, n, reversed)) {
                                error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"),
-                                                _id, size, playback_sample) << endmsg;
+                                                       id(), size, playback_sample) << endmsg;
                                goto out;
                        }
                }
@@ -824,7 +911,7 @@ AudioDiskstream::seek (framepos_t frame, bool complete_refill)
        ChannelList::iterator chan;
        boost::shared_ptr<ChannelList> c = channels.reader();
 
-       Glib::Mutex::Lock lm (state_lock);
+       Glib::Threads::Mutex::Lock lm (state_lock);
 
        for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
                (*chan)->playback_buf->reset ();
@@ -841,9 +928,15 @@ AudioDiskstream::seek (framepos_t frame, bool complete_refill)
        file_frame = frame;
 
        if (complete_refill) {
-               while ((ret = do_refill_with_alloc ()) > 0) ;
+               /* call _do_refill() to refill the entire buffer, using
+                  the largest reads possible.
+               */
+               while ((ret = do_refill_with_alloc (false)) > 0) ;
        } else {
-               ret = do_refill_with_alloc ();
+               /* call _do_refill() to refill just one chunk, and then
+                  return.
+               */
+               ret = do_refill_with_alloc (true);
        }
 
        return ret;
@@ -870,7 +963,7 @@ AudioDiskstream::internal_playback_seek (framecnt_t distance)
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (chan = c->begin(); chan != c->end(); ++chan) {
-               (*chan)->playback_buf->increment_read_ptr (distance);
+               (*chan)->playback_buf->increment_read_ptr (::llabs(distance));
        }
 
        if (first_recordable_frame < max_framepos) {
@@ -881,10 +974,17 @@ AudioDiskstream::internal_playback_seek (framecnt_t distance)
        return 0;
 }
 
+/** Read some data for 1 channel from our playlist into a buffer.
+ *  @param buf Buffer to write to.
+ *  @param start Session frame to start reading from; updated to where we end up
+ *         after the read.
+ *  @param cnt Count of samples to read.
+ *  @param reversed true if we are running backwards, otherwise false.
+ */
 int
-AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, 
+AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
                        framepos_t& start, framecnt_t cnt,
-                      ChannelInfo* /*channel_info*/, int channel, bool reversed)
+                       int channel, bool reversed)
 {
        framecnt_t this_read = 0;
        bool reloop = false;
@@ -918,25 +1018,25 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
                */
 
                if (loc && start >= loop_end) {
-                       //cerr << "start adjusted from " << start;
                        start = loop_start + ((start - loop_start) % loop_length);
-                       //cerr << "to " << start << endl;
                }
 
-               //cerr << "start is " << start << "  loopstart: " << loop_start << "  loopend: " << loop_end << endl;
        }
 
        if (reversed) {
                start -= cnt;
        }
-       
+
+       /* We need this while loop in case we hit a loop boundary, in which case our read from
+          the playlist must be split into more than one section.
+       */
+
        while (cnt) {
 
                /* take any loop into account. we can't read past the end of the loop. */
 
                if (loc && (loop_end - start < cnt)) {
                        this_read = loop_end - start;
-                       //cerr << "reloop true: thisread: " << this_read << "  cnt: " << cnt << endl;
                        reloop = true;
                } else {
                        reloop = false;
@@ -950,13 +1050,11 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
                this_read = min(cnt,this_read);
 
                if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, start, this_read, channel) != this_read) {
-                       error << string_compose(_("AudioDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read,
+                       error << string_compose(_("AudioDiskstream %1: cannot read %2 from playlist at frame %3"), id(), this_read,
                                         start) << endmsg;
                        return -1;
                }
 
-               _read_data_count = _playlist->read_data_count();
-
                if (reversed) {
 
                        swap_by_ptr (buf, buf + this_read - 1);
@@ -980,12 +1078,18 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
 }
 
 int
-AudioDiskstream::do_refill_with_alloc ()
+AudioDiskstream::_do_refill_with_alloc (bool partial_fill)
 {
-       Sample* mix_buf  = new Sample[disk_io_chunk_frames];
-       float*  gain_buf = new float[disk_io_chunk_frames];
+       /* We limit disk reads to at most 4MB chunks, which with floating point
+          samples would be 1M samples. But we might use 16 or 14 bit samples,
+          in which case 4MB is more samples than that. Therefore size this for
+          the smallest sample value .. 4MB = 2M samples (16 bit).
+       */
 
-       int ret = _do_refill(mix_buf, gain_buf);
+       Sample* mix_buf  = new Sample[2*1048576];
+       float*  gain_buf = new float[2*1048576];
+
+       int ret = _do_refill (mix_buf, gain_buf, (partial_fill ? disk_read_chunk_frames : 0));
 
        delete [] mix_buf;
        delete [] gain_buf;
@@ -993,13 +1097,22 @@ AudioDiskstream::do_refill_with_alloc ()
        return ret;
 }
 
+/** Get some more data from disk and put it in our channels' playback_bufs,
+ *  if there is suitable space in them.
+ *
+ * If fill_level is non-zero, then we will refill the buffer so that there is
+ * still at least fill_level samples of space left to be filled. This is used
+ * after locates so that we do not need to wait to fill the entire buffer.
+ *
+ */
+
 int
-AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
+AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, framecnt_t fill_level)
 {
        int32_t ret = 0;
        framecnt_t to_read;
        RingBufferNPT<Sample>::rw_vector vector;
-       bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
+       bool const reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
        framecnt_t total_space;
        framecnt_t zero_fill;
        uint32_t chan_n;
@@ -1007,6 +1120,14 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
        boost::shared_ptr<ChannelList> c = channels.reader();
        framecnt_t ts;
 
+       /* do not read from disk while session is marked as Loading, to avoid
+          useless redundant I/O.
+       */
+
+       if (_session.state_of_the_state() & Session::Loading) {
+               return 0;
+       }
+
        if (c->empty()) {
                return 0;
        }
@@ -1022,26 +1143,31 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
        c->front()->playback_buf->get_write_vector (&vector);
 
        if ((total_space = vector.len[0] + vector.len[1]) == 0) {
+               /* nowhere to write to */
                return 0;
        }
 
-       /* if there are 2+ chunks of disk i/o possible for
-          this track, let the caller know so that it can arrange
-          for us to be called again, ASAP.
-       */
-
-       if (total_space >= (_slaved?3:2) * disk_io_chunk_frames) {
-               ret = 1;
+       if (fill_level) {
+               if (fill_level < total_space) {
+                       total_space -= fill_level;
+               } else {
+                       /* we can't do anything with it */
+                       fill_level = 0;
+               }
        }
 
        /* if we're running close to normal speed and there isn't enough
-          space to do disk_io_chunk_frames of I/O, then don't bother.
+          space to do disk_read_chunk_frames of I/O, then don't bother.
 
           at higher speeds, just do it because the sync between butler
           and audio thread may not be good enough.
+
+          Note: it is a design assumption that disk_read_chunk_frames is smaller
+          than the playback buffer size, so this check should never trip when
+          the playback buffer is empty.
        */
 
-       if ((total_space < disk_io_chunk_frames) && fabs (_actual_speed) < 2.0f) {
+       if ((total_space < disk_read_chunk_frames) && fabs (_actual_speed) < 2.0f) {
                return 0;
        }
 
@@ -1054,10 +1180,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
                return 0;
        }
 
-       /* never do more than disk_io_chunk_frames worth of disk input per call (limit doesn't apply for memset) */
-
-       total_space = min (disk_io_chunk_frames, total_space);
-
        if (reversed) {
 
                if (file_frame == 0) {
@@ -1085,7 +1207,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 
                        zero_fill = total_space - file_frame;
                        total_space = file_frame;
-                       file_frame = 0;
 
                } else {
 
@@ -1125,6 +1246,30 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 
        framepos_t file_frame_tmp = 0;
 
+       /* total_space is in samples. We want to optimize read sizes in various sizes using bytes */
+
+       const size_t bits_per_sample = format_data_width (_session.config.get_native_file_data_format());
+       size_t total_bytes = total_space * bits_per_sample / 8;
+
+       /* chunk size range is 256kB to 4MB. Bigger is faster in terms of MB/sec, but bigger chunk size always takes longer
+        */
+       size_t byte_size_for_read = max ((size_t) (256 * 1024), min ((size_t) (4 * 1048576), total_bytes));
+
+       /* find nearest (lower) multiple of 16384 */
+
+       byte_size_for_read = (byte_size_for_read / 16384) * 16384;
+
+       /* now back to samples */
+
+       framecnt_t samples_to_read = byte_size_for_read / (bits_per_sample / 8);
+
+       //cerr << name() << " will read " << byte_size_for_read << " out of total bytes " << total_bytes << " in buffer of "
+       // << c->front()->playback_buf->bufsize() * bits_per_sample / 8 << " bps = " << bits_per_sample << endl;
+       // cerr << name () << " read samples = " << samples_to_read << " out of total space " << total_space << " in buffer of " << c->front()->playback_buf->bufsize() << " samples\n";
+
+       // uint64_t before = g_get_monotonic_time ();
+       // uint64_t elapsed;
+
        for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
 
                ChannelInfo* chan (*i);
@@ -1134,14 +1279,14 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 
                chan->playback_buf->get_write_vector (&vector);
 
-               if ((framecnt_t) vector.len[0] > disk_io_chunk_frames) {
+               if ((framecnt_t) vector.len[0] > samples_to_read) {
 
                        /* we're not going to fill the first chunk, so certainly do not bother with the
                           other part. it won't be connected with the part we do fill, as in:
 
                           .... => writable space
                           ++++ => readable space
-                          ^^^^ => 1 x disk_io_chunk_frames that would be filled
+                          ^^^^ => 1 x disk_read_chunk_frames that would be filled
 
                           |......|+++++++++++++|...............................|
                           buf1                buf0
@@ -1166,11 +1311,13 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
                len2 = vector.len[1];
 
                to_read = min (ts, len1);
-               to_read = min (to_read, disk_io_chunk_frames);
+               to_read = min (to_read, (framecnt_t) samples_to_read);
+
+               assert (to_read >= 0);
 
                if (to_read) {
 
-                       if (read (buf1, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) {
+                       if (read (buf1, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan_n, reversed)) {
                                ret = -1;
                                goto out;
                        }
@@ -1183,11 +1330,12 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 
                if (to_read) {
 
-                       /* we read all of vector.len[0], but it wasn't an entire disk_io_chunk_frames of data,
-                          so read some or all of vector.len[1] as well.
+                       /* we read all of vector.len[0], but it wasn't the
+                          entire samples_to_read of data, so read some or
+                          all of vector.len[1] as well.
                        */
 
-                       if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) {
+                       if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan_n, reversed)) {
                                ret = -1;
                                goto out;
                        }
@@ -1196,26 +1344,33 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
                }
 
                if (zero_fill) {
-                       /* do something */
+                       /* XXX: do something */
                }
 
        }
 
+       // elapsed = g_get_monotonic_time () - before;
+       // cerr << "\tbandwidth = " << (byte_size_for_read / 1048576.0) / (elapsed/1000000.0) << "MB/sec\n";
+
        file_frame = file_frame_tmp;
+       assert (file_frame >= 0);
 
-  out:
+       ret = ((total_space - samples_to_read) > disk_read_chunk_frames);
 
+       c->front()->playback_buf->get_write_vector (&vector);
+
+  out:
        return ret;
 }
 
 /** Flush pending data to disk.
  *
- * Important note: this function will write *AT MOST* disk_io_chunk_frames
+ * Important note: this function will write *AT MOST* disk_write_chunk_frames
  * of data to disk. it will never write more than that.  If it writes that
  * much and there is more than that waiting to be written, it will return 1,
  * otherwise 0 on success or -1 on failure.
  *
- * If there is less than disk_io_chunk_frames to be written, no data will be
+ * If there is less than disk_write_chunk_frames to be written, no data will be
  * written at all unless @a force_flush is true.
  */
 int
@@ -1227,8 +1382,6 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
        RingBufferNPT<CaptureTransition>::rw_vector transvec;
        framecnt_t total;
 
-       _write_data_count = 0;
-
        transvec.buf[0] = 0;
        transvec.buf[1] = 0;
        vector.buf[0] = 0;
@@ -1241,7 +1394,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
 
                total = vector.len[0] + vector.len[1];
 
-               if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
+               if (total == 0 || (total < disk_write_chunk_frames && !force_flush && was_recording)) {
                        goto out;
                }
 
@@ -1256,11 +1409,11 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                   let the caller know too.
                */
 
-               if (total >= 2 * disk_io_chunk_frames || ((force_flush || !was_recording) && total > disk_io_chunk_frames)) {
+               if (total >= 2 * disk_write_chunk_frames || ((force_flush || !was_recording) && total > disk_write_chunk_frames)) {
                        ret = 1;
                }
 
-               to_write = min (disk_io_chunk_frames, (framecnt_t) vector.len[0]);
+               to_write = min (disk_write_chunk_frames, (framecnt_t) vector.len[0]);
 
                // check the transition buffer when recording destructive
                // important that we get this after the capture buf
@@ -1268,7 +1421,6 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                if (destructive()) {
                        (*chan)->capture_transition_buf->get_read_vector(&transvec);
                        size_t transcount = transvec.len[0] + transvec.len[1];
-                       bool have_start = false;
                        size_t ti;
 
                        for (ti=0; ti < transcount; ++ti) {
@@ -1280,9 +1432,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                                        (*chan)->write_source->mark_capture_start (captrans.capture_val);
                                        (*chan)->curr_capture_cnt = 0;
 
-                                       have_start = true;
-                               }
-                               else if (captrans.type == CaptureEnd) {
+                               } else if (captrans.type == CaptureEnd) {
 
                                        // capture end, the capture_val represents total frames in capture
 
@@ -1316,29 +1466,29 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                }
 
                if ((!(*chan)->write_source) || (*chan)->write_source->write (vector.buf[0], to_write) != to_write) {
-                       error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
+                       error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg;
                        return -1;
                }
 
                (*chan)->capture_buf->increment_read_ptr (to_write);
                (*chan)->curr_capture_cnt += to_write;
 
-               if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames) && !destructive()) {
+               if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_write_chunk_frames) && !destructive()) {
 
                        /* we wrote all of vector.len[0] but it wasn't an entire
-                          disk_io_chunk_frames of data, so arrange for some part
+                          disk_write_chunk_frames of data, so arrange for some part
                           of vector.len[1] to be flushed to disk as well.
                        */
 
-                       to_write = min ((framecnt_t)(disk_io_chunk_frames - to_write), (framecnt_t) vector.len[1]);
+                       to_write = min ((framecnt_t)(disk_write_chunk_frames - to_write), (framecnt_t) vector.len[1]);
+
+                        DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 additional write of %2\n", name(), to_write));
 
                        if ((*chan)->write_source->write (vector.buf[1], to_write) != to_write) {
-                               error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
+                               error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg;
                                return -1;
                        }
 
-                       _write_data_count += (*chan)->write_source->write_data_count();
-
                        (*chan)->capture_buf->increment_read_ptr (to_write);
                        (*chan)->curr_capture_cnt += to_write;
                }
@@ -1364,7 +1514,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
        uint32_t n = 0;
        bool mark_write_completed = false;
 
-       finish_capture (true, c);
+       finish_capture (c);
 
        /* butler is already stopped, but there may be work to do
           to flush remaining data to disk.
@@ -1384,7 +1534,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
        }
 
        /* XXX is there anything we can do if err != 0 ? */
-       Glib::Mutex::Lock lm (capture_info_lock);
+       Glib::Threads::Mutex::Lock lm (capture_info_lock);
 
        if (capture_info.empty()) {
                return;
@@ -1402,7 +1552,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                                (*chan)->write_source->mark_for_remove ();
                                (*chan)->write_source->drop_references ();
-                                _session.remove_source ((*chan)->write_source);
                                (*chan)->write_source.reset ();
                        }
 
@@ -1424,9 +1573,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                if (s) {
                        srcs.push_back (s);
-                        if (s->unstubify ()) {
-                                error << string_compose (_("Could not move capture file from %1"), s->path()) << endmsg;
-                        }
                        s->update_header (capture_info.front()->start, when, twhen);
                        s->set_captured_for (_name.val());
                        s->mark_immutable ();
@@ -1434,6 +1580,8 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
                        if (Config->get_auto_analyse_audio()) {
                                Analyser::queue_source_for_analysis (s, true);
                        }
+
+                       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", s->path(), s->length (0)));
                }
        }
 
@@ -1482,9 +1630,8 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
 
-               // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
-
-                _playlist->clear_changes ();
+               _playlist->clear_changes ();
+               _playlist->set_capture_insertion_in_progress (true);
                _playlist->freeze ();
 
                for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
@@ -1493,16 +1640,17 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                        RegionFactory::region_name (region_name, whole_file_region_name, false);
 
-                       // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl;
+                       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture bufpos %5 start @ %2 length %3 add new region %4\n",
+                                                                             _name, (*ci)->start, (*ci)->frames, region_name, buffer_position));
 
                        try {
 
                                PropertyList plist;
-                               
+
                                plist.add (Properties::start, buffer_position);
                                plist.add (Properties::length, (*ci)->frames);
                                plist.add (Properties::name, region_name);
-                               
+
                                boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
                                region = boost::dynamic_pointer_cast<AudioRegion> (rx);
                        }
@@ -1514,21 +1662,15 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                        i_am_the_modifier++;
 
-                       if (_playlist->explicit_relayering()) {
-                               /* We are in `explicit relayering' mode, so we must specify which layer this new region
-                                  should end up on.  Put it at the top.
-                               */
-                               region->set_layer (_playlist->top_layer() + 1);
-                               region->set_pending_explicit_relayer (true);
-                       }
-                       
                        _playlist->add_region (region, (*ci)->start, 1, non_layered());
+                       _playlist->set_layer (region, DBL_MAX);
                        i_am_the_modifier--;
 
                        buffer_position += (*ci)->frames;
                }
 
                _playlist->thaw ();
+               _playlist->set_capture_insertion_in_progress (false);
                _session.add_command (new StatefulDiffCommand (_playlist));
        }
 
@@ -1554,19 +1696,7 @@ AudioDiskstream::transport_looped (framepos_t transport_frame)
                // all we need to do is finish this capture, with modified capture length
                boost::shared_ptr<ChannelList> c = channels.reader();
 
-               // adjust the capture length knowing that the data will be recorded to disk
-               // only necessary after the first loop where we're recording
-               if (capture_info.size() == 0) {
-                       capture_captured += _capture_offset;
-
-                       if (_alignment_style == ExistingMaterial) {
-                               capture_captured += _session.worst_output_latency();
-                       } else {
-                               capture_captured += _roll_delay;
-                       }
-               }
-
-               finish_capture (true, c);
+               finish_capture (c);
 
                // the next region will start recording via the normal mechanism
                // we'll set the start position to the current transport pos
@@ -1599,11 +1729,11 @@ AudioDiskstream::transport_looped (framepos_t transport_frame)
 }
 
 void
-AudioDiskstream::finish_capture (bool /*rec_monitors_input*/, boost::shared_ptr<ChannelList> c)
+AudioDiskstream::finish_capture (boost::shared_ptr<ChannelList> c)
 {
        was_recording = false;
-        first_recordable_frame = max_framepos;
-        last_recordable_frame = max_framepos;
+       first_recordable_frame = max_framepos;
+       last_recordable_frame = max_framepos;
 
        if (capture_captured == 0) {
                return;
@@ -1642,7 +1772,7 @@ AudioDiskstream::finish_capture (bool /*rec_monitors_input*/, boost::shared_ptr<
           accessors, so that invalidation will not occur (both non-realtime).
        */
 
-       // cerr << "Finish capture, add new CI, " << ci->start << '+' << ci->frames << endl;
+       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("Finish capture, add new CI, %1 + %2\n", ci->start, ci->frames));
 
        capture_info.push_back (ci);
        capture_captured = 0;
@@ -1654,7 +1784,7 @@ AudioDiskstream::finish_capture (bool /*rec_monitors_input*/, boost::shared_ptr<
 void
 AudioDiskstream::set_record_enabled (bool yn)
 {
-       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) {
+       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0 || record_safe ()) {
                return;
        }
 
@@ -1674,75 +1804,102 @@ AudioDiskstream::set_record_enabled (bool yn)
                } else {
                        disengage_record_enable ();
                }
+
+               RecordEnableChanged (); /* EMIT SIGNAL */
        }
 }
 
 void
-AudioDiskstream::engage_record_enable ()
+AudioDiskstream::set_record_safe (bool yn)
+{
+       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) {
+               return;
+       }
+
+       /* can't rec-safe in destructive mode if transport is before start ????
+        REQUIRES REVIEW */
+
+       if (destructive() && yn && _session.transport_frame() < _session.current_start_frame()) {
+               return;
+       }
+
+       /* yes, i know that this not proof against race conditions, but its
+        good enough. i think.
+        */
+
+       if (record_safe () != yn) {
+               if (yn) {
+                       engage_record_safe ();
+               } else {
+                       disengage_record_safe ();
+               }
+
+               RecordSafeChanged (); /* EMIT SIGNAL */
+       }
+}
+
+bool
+AudioDiskstream::prep_record_enable ()
 {
+       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0 || record_safe ()) { // REQUIRES REVIEW "|| record_safe ()"
+               return false;
+       }
+
+       /* can't rec-enable in destructive mode if transport is before start */
+
+       if (destructive() && _session.transport_frame() < _session.current_start_frame()) {
+               return false;
+       }
+
        bool rolling = _session.transport_speed() != 0.0f;
        boost::shared_ptr<ChannelList> c = channels.reader();
 
-       g_atomic_int_set (&_record_enabled, 1);
        capturing_sources.clear ();
 
        if (Config->get_monitoring_model() == HardwareMonitoring) {
 
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                       if ((*chan)->source) {
-                               (*chan)->source->ensure_monitor_input (!(_session.config.get_auto_input() && rolling));
-                       }
+                       (*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling));
                        capturing_sources.push_back ((*chan)->write_source);
-                       (*chan)->write_source->mark_streaming_write_started ();
+                       Source::Lock lock((*chan)->write_source->mutex());
+                       (*chan)->write_source->mark_streaming_write_started (lock);
                }
 
        } else {
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
                        capturing_sources.push_back ((*chan)->write_source);
-                       (*chan)->write_source->mark_streaming_write_started ();
+                       Source::Lock lock((*chan)->write_source->mutex());
+                       (*chan)->write_source->mark_streaming_write_started (lock);
                }
        }
 
-       RecordEnableChanged (); /* EMIT SIGNAL */
+       return true;
 }
 
-void
-AudioDiskstream::disengage_record_enable ()
+bool
+AudioDiskstream::prep_record_disable ()
 {
-       g_atomic_int_set (&_record_enabled, 0);
        boost::shared_ptr<ChannelList> c = channels.reader();
        if (Config->get_monitoring_model() == HardwareMonitoring) {
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                       if ((*chan)->source) {
-                               (*chan)->source->ensure_monitor_input (false);
-                       }
+                       (*chan)->source.request_input_monitoring (false);
                }
        }
        capturing_sources.clear ();
-       RecordEnableChanged (); /* EMIT SIGNAL */
+
+       return true;
 }
 
 XMLNode&
 AudioDiskstream::get_state ()
 {
-       XMLNode* node = new XMLNode ("Diskstream");
+       XMLNode& node (Diskstream::get_state());
        char buf[64] = "";
-       LocaleGuard lg (X_("POSIX"));
-       boost::shared_ptr<ChannelList> c = channels.reader();
+       LocaleGuard lg;
 
-       node->add_property ("flags", enum_2_string (_flags));
-
-       snprintf (buf, sizeof(buf), "%zd", c->size());
-       node->add_property ("channels", buf);
-
-       node->add_property ("playlist", _playlist->name());
-
-       snprintf (buf, sizeof(buf), "%.12g", _visible_speed);
-       node->add_property ("speed", buf);
-
-       node->add_property("name", _name);
-       id().print (buf, sizeof (buf));
-       node->add_property("id", buf);
+       boost::shared_ptr<ChannelList> c = channels.reader();
+       snprintf (buf, sizeof(buf), "%u", (unsigned int) c->size());
+       node.add_property ("channels", buf);
 
        if (!capturing_sources.empty() && _session.get_record_enabled()) {
 
@@ -1766,25 +1923,23 @@ AudioDiskstream::get_state ()
                }
 
                cs_child->add_property (X_("at"), buf);
-               node->add_child_nocopy (*cs_child);
+               node.add_child_nocopy (*cs_child);
        }
 
-       if (_extra_xml) {
-               node->add_child_copy (*_extra_xml);
-       }
-
-       return* node;
+       return node;
 }
 
 int
-AudioDiskstream::set_state (const XMLNode& node, int /*version*/)
+AudioDiskstream::set_state (const XMLNode& node, int version)
 {
-       const XMLProperty* prop;
+       XMLProperty const * prop;
        XMLNodeList nlist = node.children();
        XMLNodeIterator niter;
        uint32_t nchans = 1;
        XMLNode* capture_pending_node = 0;
-       LocaleGuard lg (X_("POSIX"));
+       LocaleGuard lg;
+
+       /* prevent write sources from being created */
 
        in_set_state = true;
 
@@ -1798,26 +1953,8 @@ AudioDiskstream::set_state (const XMLNode& node, int /*version*/)
                }
        }
 
-       /* prevent write sources from being created */
-
-       in_set_state = true;
-
-       if ((prop = node.property ("name")) != 0) {
-               _name = prop->value();
-       }
-
-       if (deprecated_io_node) {
-               if ((prop = deprecated_io_node->property ("id")) != 0) {
-                       _id = prop->value ();
-               }
-       } else {
-               if ((prop = node.property ("id")) != 0) {
-                       _id = prop->value ();
-               }
-       }
-
-       if ((prop = node.property ("flags")) != 0) {
-               _flags = Flag (string_2_enum (prop->value(), _flags));
+       if (Diskstream::set_state (node, version)) {
+               return -1;
        }
 
        if ((prop = node.property ("channels")) != 0) {
@@ -1839,37 +1976,14 @@ AudioDiskstream::set_state (const XMLNode& node, int /*version*/)
                remove_channel (_n_channels.n_audio() - nchans);
        }
 
-       if ((prop = node.property ("playlist")) == 0) {
-               return -1;
-       }
-
-       {
-               bool had_playlist = (_playlist != 0);
-
-               if (find_and_use_playlist (prop->value())) {
-                       return -1;
-               }
 
-               if (!had_playlist) {
-                       _playlist->set_orig_diskstream_id (id());
-               }
 
-               if (!destructive() && capture_pending_node) {
-                       /* destructive streams have one and only one source per channel,
-                          and so they never end up in pending capture in any useful
-                          sense.
-                       */
-                       use_pending_capture_data (*capture_pending_node);
-               }
-
-       }
-
-       if ((prop = node.property ("speed")) != 0) {
-               double sp = atof (prop->value().c_str());
-
-               if (realtime_set_speed (sp, false)) {
-                       non_realtime_set_speed ();
-               }
+       if (!destructive() && capture_pending_node) {
+               /* destructive streams have one and only one source per channel,
+                  and so they never end up in pending capture in any useful
+                  sense.
+               */
+               use_pending_capture_data (*capture_pending_node);
        }
 
        in_set_state = false;
@@ -1902,13 +2016,8 @@ AudioDiskstream::use_new_write_source (uint32_t n)
        ChannelInfo* chan = (*c)[n];
 
        try {
-                /* file starts off as a stub file, it will be converted
-                   when we're done with a capture pass.
-                */
-
-               if ((chan->write_source = _session.create_audio_source_for_session (n_channels().n_audio(), 
-                                                                                    name(), n, destructive(), 
-                                                                                    true)) == 0) {
+               if ((chan->write_source = _session.create_audio_source_for_session (
+                            n_channels().n_audio(), write_source_name(), n, destructive())) == 0) {
                        throw failed_constructor();
                }
        }
@@ -1922,16 +2031,8 @@ AudioDiskstream::use_new_write_source (uint32_t n)
        /* do not remove destructive files even if they are empty */
 
        chan->write_source->set_allow_remove_if_empty (!destructive());
-       
-       return 0;
-}
 
-list<boost::shared_ptr<Source> > 
-AudioDiskstream::steal_write_sources()
-{
-        /* not possible to steal audio write sources */
-        list<boost::shared_ptr<Source> > ret;
-        return ret;
+       return 0;
 }
 
 void
@@ -1954,18 +2055,18 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
                        if ((*chan)->write_source) {
 
                                if (mark_write_complete) {
-                                       (*chan)->write_source->mark_streaming_write_completed ();
+                                       Source::Lock lock((*chan)->write_source->mutex());
+                                       (*chan)->write_source->mark_streaming_write_completed (lock);
                                        (*chan)->write_source->done_with_peakfile_writes ();
                                }
 
-                                if ((*chan)->write_source->removable()) {
-                                        (*chan)->write_source->mark_for_remove ();
-                                        (*chan)->write_source->drop_references ();
-                                        _session.remove_source ((*chan)->write_source);
-                                }
-                               
-                                (*chan)->write_source.reset ();
-                        }
+                               if ((*chan)->write_source->removable()) {
+                                       (*chan)->write_source->mark_for_remove ();
+                                       (*chan)->write_source->drop_references ();
+                               }
+
+                               (*chan)->write_source.reset ();
+                       }
 
                        use_new_write_source (n);
 
@@ -1993,23 +2094,6 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
        }
 }
 
-int
-AudioDiskstream::rename_write_sources ()
-{
-       ChannelList::iterator chan;
-       boost::shared_ptr<ChannelList> c = channels.reader();
-       uint32_t n;
-
-       for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
-               if ((*chan)->write_source != 0) {
-                       (*chan)->write_source->set_source_name (_name.val(), destructive());
-                       /* XXX what to do if one of them fails ? */
-               }
-       }
-
-       return 0;
-}
-
 void
 AudioDiskstream::set_block_size (pframes_t /*nframes*/)
 {
@@ -2034,19 +2118,21 @@ AudioDiskstream::allocate_temporary_buffers ()
           when slaving to MTC, Timecode etc.
        */
 
-       double const sp = max (fabsf (_actual_speed), 1.2f);
-       framecnt_t required_wrap_size = (framecnt_t) floor (_session.get_block_size() * sp) + 1;
+       double const sp = max (fabs (_actual_speed), 1.2);
+       framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() * sp) + 2;
 
        if (required_wrap_size > wrap_buffer_size) {
 
                boost::shared_ptr<ChannelList> c = channels.reader();
 
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                       if ((*chan)->playback_wrap_buffer)
+                       if ((*chan)->playback_wrap_buffer) {
                                delete [] (*chan)->playback_wrap_buffer;
+                       }
                        (*chan)->playback_wrap_buffer = new Sample[required_wrap_size];
-                       if ((*chan)->capture_wrap_buffer)
+                       if ((*chan)->capture_wrap_buffer) {
                                delete [] (*chan)->capture_wrap_buffer;
+                       }
                        (*chan)->capture_wrap_buffer = new Sample[required_wrap_size];
                }
 
@@ -2055,15 +2141,12 @@ AudioDiskstream::allocate_temporary_buffers ()
 }
 
 void
-AudioDiskstream::monitor_input (bool yn)
+AudioDiskstream::request_input_monitoring (bool yn)
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-
-               if ((*chan)->source) {
-                       (*chan)->source->ensure_monitor_input (yn);
-               }
+               (*chan)->source.request_input_monitoring (yn);
        }
 }
 
@@ -2072,6 +2155,10 @@ AudioDiskstream::set_align_style_from_io ()
 {
        bool have_physical = false;
 
+       if (_alignment_choice != Automatic) {
+               return;
+       }
+
        if (_io == 0) {
                return;
        }
@@ -2081,7 +2168,7 @@ AudioDiskstream::set_align_style_from_io ()
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-               if ((*chan)->source && (*chan)->source->flags() & JackPortIsPhysical) {
+               if ((*chan)->source.is_physical ()) {
                        have_physical = true;
                        break;
                }
@@ -2098,10 +2185,13 @@ int
 AudioDiskstream::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many)
 {
        while (how_many--) {
-               c->push_back (new ChannelInfo(_session.butler()->audio_diskstream_playback_buffer_size(), 
-                                              _session.butler()->audio_diskstream_capture_buffer_size(),
-                                              speed_buffer_size, wrap_buffer_size));
-               interpolation.add_channel_to (_session.butler()->audio_diskstream_playback_buffer_size(), speed_buffer_size);
+               c->push_back (new ChannelInfo(
+                                     _session.butler()->audio_diskstream_playback_buffer_size(),
+                                     _session.butler()->audio_diskstream_capture_buffer_size(),
+                                     speed_buffer_size, wrap_buffer_size));
+               interpolation.add_channel_to (
+                       _session.butler()->audio_diskstream_playback_buffer_size(),
+                       speed_buffer_size);
        }
 
        _n_channels.set(DataType::AUDIO, c->size());
@@ -2147,11 +2237,11 @@ AudioDiskstream::playback_buffer_load () const
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        if (c->empty ()) {
-               return 0;
+               return 1.0;
        }
 
        return (float) ((double) c->front()->playback_buf->read_space()/
-                       (double) c->front()->playback_buf->bufsize());
+                          (double) c->front()->playback_buf->bufsize());
 }
 
 float
@@ -2160,9 +2250,9 @@ AudioDiskstream::capture_buffer_load () const
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        if (c->empty ()) {
-               return 0;
+               return 1.0;
        }
-       
+
        return (float) ((double) c->front()->capture_buf->write_space()/
                        (double) c->front()->capture_buf->bufsize());
 }
@@ -2170,7 +2260,7 @@ AudioDiskstream::capture_buffer_load () const
 int
 AudioDiskstream::use_pending_capture_data (XMLNode& node)
 {
-       const XMLProperty* prop;
+       XMLProperty const * prop;
        XMLNodeList nlist = node.children();
        XMLNodeIterator niter;
        boost::shared_ptr<AudioFileSource> fs;
@@ -2194,15 +2284,21 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
                        }
 
                        // This protects sessions from errant CapturingSources in stored sessions
-                       struct stat sbuf;
-                       if (stat (prop->value().c_str(), &sbuf)) {
+                       GStatBuf sbuf;
+                       if (g_stat (prop->value().c_str(), &sbuf)) {
                                continue;
                        }
 
+                       /* XXX as of June 2014, we always record to mono
+                          files. Since this Source is being created as part of
+                          crash recovery, we know that we need the first
+                          channel (the final argument to the SourceFactory
+                          call below). If we ever support non-mono files for
+                          capture, this will need rethinking.
+                       */
+
                        try {
-                               fs = boost::dynamic_pointer_cast<AudioFileSource> (
-                                               SourceFactory::createWritable (DataType::AUDIO, _session,
-                                                                               prop->value(), string(), false, _session.frame_rate()));
+                               fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createForRecovery (DataType::AUDIO, _session, prop->value(), 0));
                        }
 
                        catch (failed_constructor& err) {
@@ -2233,21 +2329,31 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
                return -1;
        }
 
-       boost::shared_ptr<AudioRegion> region;
-
        try {
-               
+
+               boost::shared_ptr<AudioRegion> wf_region;
+               boost::shared_ptr<AudioRegion> region;
+
+               /* First create the whole file region */
+
                PropertyList plist;
-               
+
                plist.add (Properties::start, 0);
                plist.add (Properties::length, first_fs->length (first_fs->timeline_position()));
                plist.add (Properties::name, region_name_from_path (first_fs->name(), true));
 
+               wf_region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
+
+               wf_region->set_automatic (true);
+               wf_region->set_whole_file (true);
+               wf_region->special_set_position (position);
+
+               /* Now create a region that isn't the whole file for adding to
+                * the playlist */
+
                region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
 
-               region->set_automatic (true);
-               region->set_whole_file (true);
-               region->special_set_position (0);
+               _playlist->add_region (region, position);
        }
 
        catch (failed_constructor& err) {
@@ -2258,7 +2364,6 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
                return -1;
        }
 
-       _playlist->add_region (region, position);
 
        return 0;
 }
@@ -2305,11 +2410,22 @@ AudioDiskstream::set_destructive (bool yn)
 bool
 AudioDiskstream::can_become_destructive (bool& requires_bounce) const
 {
+       if (Profile->get_trx()) {
+               return false;
+       }
+
        if (!_playlist) {
                requires_bounce = false;
                return false;
        }
 
+       /* if no regions are present: easy */
+
+       if (_playlist->n_regions() == 0) {
+               requires_bounce = false;
+               return true;
+       }
+
        /* is there only one region ? */
 
        if (_playlist->n_regions() != 1) {
@@ -2317,7 +2433,14 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const
                return false;
        }
 
-       boost::shared_ptr<Region> first = _playlist->find_next_region (_session.current_start_frame(), Start, 1);
+       boost::shared_ptr<Region> first;
+       {
+               const RegionList& rl (_playlist->region_list_property().rlist());
+               assert((rl.size() == 1));
+               first = rl.front();
+
+       }
+
        if (!first) {
                requires_bounce = false;
                return true;
@@ -2326,12 +2449,24 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const
        /* do the source(s) for the region cover the session start position ? */
 
        if (first->position() != _session.current_start_frame()) {
+               // what is the idea here?  why start() ??
                if (first->start() > _session.current_start_frame()) {
                        requires_bounce = true;
                        return false;
                }
        }
 
+       /* currently RouteTimeAxisView::set_track_mode does not
+        * implement bounce. Existing regions cannot be converted.
+        *
+        * so let's make sure this region is already set up
+        * as tape-track (spanning the complete range)
+        */
+       if (first->length() != max_framepos - first->position()) {
+               requires_bounce = true;
+               return false;
+       }
+
        /* is the source used by only 1 playlist ? */
 
        boost::shared_ptr<AudioRegion> afirst = boost::dynamic_pointer_cast<AudioRegion> (first);
@@ -2347,30 +2482,48 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const
        return true;
 }
 
-void 
+void
 AudioDiskstream::adjust_playback_buffering ()
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                (*chan)->resize_playback (_session.butler()->audio_diskstream_playback_buffer_size());
-        }
+               (*chan)->resize_playback (_session.butler()->audio_diskstream_playback_buffer_size());
+       }
 }
 
-void 
+void
 AudioDiskstream::adjust_capture_buffering ()
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                (*chan)->resize_capture (_session.butler()->audio_diskstream_capture_buffer_size());
-        }
+               (*chan)->resize_capture (_session.butler()->audio_diskstream_capture_buffer_size());
+       }
+}
+
+bool
+AudioDiskstream::ChannelSource::is_physical () const
+{
+       if (name.empty()) {
+               return false;
+       }
+
+       return AudioEngine::instance()->port_is_physical (name);
+}
+
+void
+AudioDiskstream::ChannelSource::request_input_monitoring (bool yn) const
+{
+       if (name.empty()) {
+               return;
+       }
+
+       return AudioEngine::instance()->request_input_monitoring (name, yn);
 }
 
 AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt_t capture_bufsize, framecnt_t speed_size, framecnt_t wrap_size)
 {
-       peak_power = 0.0f;
-       source = 0;
        current_capture_buffer = 0;
        current_playback_buffer = 0;
        curr_capture_cnt = 0;
@@ -2397,7 +2550,7 @@ AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt
 void
 AudioDiskstream::ChannelInfo::resize_playback (framecnt_t playback_bufsize)
 {
-        delete playback_buf;
+       delete playback_buf;
        playback_buf = new RingBufferNPT<Sample> (playback_bufsize);
        memset (playback_buf->buffer(), 0, sizeof (Sample) * playback_buf->bufsize());
 }
@@ -2405,7 +2558,7 @@ AudioDiskstream::ChannelInfo::resize_playback (framecnt_t playback_bufsize)
 void
 AudioDiskstream::ChannelInfo::resize_capture (framecnt_t capture_bufsize)
 {
-        delete capture_buf;
+       delete capture_buf;
 
        capture_buf = new RingBufferNPT<Sample> (capture_bufsize);
        memset (capture_buf->buffer(), 0, sizeof (Sample) * capture_buf->bufsize());
@@ -2413,7 +2566,25 @@ AudioDiskstream::ChannelInfo::resize_capture (framecnt_t capture_bufsize)
 
 AudioDiskstream::ChannelInfo::~ChannelInfo ()
 {
-        write_source.reset ();
+       if (write_source) {
+               if (write_source->removable()) {
+                       /* this is a "stub" write source which exists in the
+                          Session source list, but is removable. We must emit
+                          a drop references call because it should not
+                          continue to exist. If we do not do this, then the
+                          Session retains a reference to it, it is not
+                          deleted, and later attempts to create a new source
+                          file will use wierd naming because it already
+                          exists.
+
+                          XXX longer term TO-DO: do not add to session source
+                          list until we write to the source.
+                       */
+                       write_source->drop_references ();
+               }
+       }
+
+       write_source.reset ();
 
        delete [] speed_buffer;
        speed_buffer = 0;
@@ -2434,3 +2605,45 @@ AudioDiskstream::ChannelInfo::~ChannelInfo ()
        capture_transition_buf = 0;
 }
 
+
+bool
+AudioDiskstream::set_name (string const & name)
+{
+       if (_name == name) {
+               return true;
+       }
+       Diskstream::set_name (name);
+
+       /* get a new write source so that its name reflects the new diskstream name */
+
+       boost::shared_ptr<ChannelList> c = channels.reader();
+       ChannelList::iterator i;
+       int n = 0;
+
+       for (n = 0, i = c->begin(); i != c->end(); ++i, ++n) {
+               use_new_write_source (n);
+       }
+
+       return true;
+}
+
+bool
+AudioDiskstream::set_write_source_name (const std::string& str) {
+       if (_write_source_name == str) {
+               return true;
+       }
+
+       Diskstream::set_write_source_name (str);
+
+       if (_write_source_name == name()) {
+               return true;
+       }
+       boost::shared_ptr<ChannelList> c = channels.reader();
+       ChannelList::iterator i;
+       int n = 0;
+
+       for (n = 0, i = c->begin(); i != c->end(); ++i, ++n) {
+               use_new_write_source (n);
+       }
+       return true;
+}