fix #4405, by explicitly cancelling solo when a route's inputs drop to zero
[ardour.git] / libs / ardour / audio_diskstream.cc
index 71e57e1dd78888b65096a7379bd74cf04af1def7..037ff34eb5ddd28f9dab537e4a920c3c3c194e6e 100644 (file)
@@ -31,7 +31,6 @@
 #include <sys/mman.h>
 
 #include "pbd/error.h"
 #include <sys/mman.h>
 
 #include "pbd/error.h"
-#include <glibmm/thread.h>
 #include "pbd/xml++.h"
 #include "pbd/memento_command.h"
 #include "pbd/enumwriter.h"
 #include "pbd/xml++.h"
 #include "pbd/memento_command.h"
 #include "pbd/enumwriter.h"
@@ -57,6 +56,7 @@
 #include "ardour/send.h"
 #include "ardour/session.h"
 #include "ardour/source_factory.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
 #include "ardour/source_factory.h"
+#include "ardour/track.h"
 #include "ardour/utils.h"
 #include "ardour/session_playlists.h"
 #include "ardour/route.h"
 #include "ardour/utils.h"
 #include "ardour/session_playlists.h"
 #include "ardour/route.h"
@@ -74,7 +74,6 @@ gain_t* AudioDiskstream::_gain_buffer          = 0;
 
 AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
        : Diskstream(sess, name, flag)
 
 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 */
        , channels (new ChannelList)
 {
        /* prevent any write sources from being created */
@@ -86,7 +85,6 @@ AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream:
 
 AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node)
        : Diskstream(sess, node)
 
 AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node)
        : Diskstream(sess, node)
-       , deprecated_io_node(NULL)
        , channels (new ChannelList)
 {
        in_set_state = true;
        , channels (new ChannelList)
 {
        in_set_state = true;
@@ -114,9 +112,6 @@ AudioDiskstream::init ()
 
        set_block_size (_session.get_block_size());
        allocate_temporary_buffers ();
 
        set_block_size (_session.get_block_size());
        allocate_temporary_buffers ();
-
-       add_channel (1);
-       assert(_n_channels == ChanCount(DataType::AUDIO, 1));
 }
 
 AudioDiskstream::~AudioDiskstream ()
 }
 
 AudioDiskstream::~AudioDiskstream ()
@@ -135,8 +130,6 @@ AudioDiskstream::~AudioDiskstream ()
        }
 
        channels.flush ();
        }
 
        channels.flush ();
-
-       delete deprecated_io_node;
 }
 
 void
 }
 
 void
@@ -165,11 +158,11 @@ AudioDiskstream::non_realtime_input_change ()
        {
                Glib::Mutex::Lock lm (state_lock);
 
        {
                Glib::Mutex::Lock lm (state_lock);
 
-               if (input_change_pending == NoChange) {
+               if (input_change_pending.type == IOChange::NoChange) {
                        return;
                }
 
                        return;
                }
 
-               {
+               if (input_change_pending.type == IOChange::ConfigurationChanged) {
                        RCUWriter<ChannelList> writer (channels);
                        boost::shared_ptr<ChannelList> c = writer.get_copy();
 
                        RCUWriter<ChannelList> writer (channels);
                        boost::shared_ptr<ChannelList> c = writer.get_copy();
 
@@ -182,17 +175,13 @@ AudioDiskstream::non_realtime_input_change ()
                        }
                }
 
                        }
                }
 
-               get_input_sources ();
-               set_capture_offset ();
-
-               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 ();
                }
 
                        set_align_style_from_io ();
                }
 
-               input_change_pending = NoChange;
+               input_change_pending = IOChange::NoChange;
 
                /* implicit unlock */
        }
 
                /* implicit unlock */
        }
@@ -204,19 +193,19 @@ AudioDiskstream::non_realtime_input_change ()
        /* now refill channel buffers */
 
        if (speed() != 1.0f || speed() != -1.0f) {
        /* now refill channel buffers */
 
        if (speed() != 1.0f || speed() != -1.0f) {
-               seek ((nframes_t) (_session.transport_frame() * (double) speed()));
+               seek ((framepos_t) (_session.transport_frame() * (double) speed()));
        } else {
                seek (_session.transport_frame());
        }
 }
 
 void
        } else {
                seek (_session.transport_frame());
        }
 }
 
 void
-AudioDiskstream::non_realtime_locate (nframes_t location)
+AudioDiskstream::non_realtime_locate (framepos_t location)
 {
        /* now refill channel buffers */
 
        if (speed() != 1.0f || speed() != -1.0f) {
 {
        /* now refill channel buffers */
 
        if (speed() != 1.0f || speed() != -1.0f) {
-               seek ((nframes_t) (location * (double) speed()));
+               seek ((framepos_t) (location * (double) speed()));
        } else {
                seek (location);
        }
        } else {
                seek (location);
        }
@@ -237,15 +226,12 @@ AudioDiskstream::get_input_sources ()
                connections.clear ();
 
                if (_io->nth (n)->get_connections (connections) == 0) {
                connections.clear ();
 
                if (_io->nth (n)->get_connections (connections) == 0) {
-
-                       if ((*chan)->source) {
+                       if (!(*chan)->source.name.empty()) {
                                // _source->disable_metering ();
                        }
                                // _source->disable_metering ();
                        }
-
-                       (*chan)->source = 0;
-
+                       (*chan)->source.name = string();
                } else {
                } else {
-                       (*chan)->source = dynamic_cast<AudioPort*>(_session.engine().get_port_by_name (connections[0]) );
+                       (*chan)->source.name = connections[0];
                }
        }
 }
                }
        }
 }
@@ -295,7 +281,6 @@ AudioDiskstream::use_new_playlist ()
 
        if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (DataType::AUDIO, _session, newname, hidden()))) != 0) {
 
 
        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 {
                return use_playlist (playlist);
 
        } else {
@@ -323,7 +308,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) {
        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;
                return use_playlist (playlist);
        } else {
                return -1;
@@ -347,7 +331,7 @@ AudioDiskstream::setup_destructive_playlist ()
        PropertyList plist;
        plist.add (Properties::name, _name.val());
        plist.add (Properties::start, 0);
        PropertyList plist;
        plist.add (Properties::name, _name.val());
        plist.add (Properties::start, 0);
-       plist.add (Properties::length, max_frames - max_frames - srcs.front()->natural_position());
+       plist.add (Properties::length, max_framepos - (max_framepos - srcs.front()->natural_position()));
 
        boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist));
        _playlist->add_region (region, srcs.front()->natural_position());
 
        boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist));
        _playlist->add_region (region, srcs.front()->natural_position());
@@ -377,7 +361,7 @@ AudioDiskstream::use_destructive_playlist ()
 
        /* be sure to stretch the region out to the maximum length */
 
 
        /* be sure to stretch the region out to the maximum length */
 
-       region->set_length (max_frames - region->position(), this);
+       region->set_length (max_framepos - region->position());
 
        uint32_t n;
        ChannelList::iterator chan;
 
        uint32_t n;
        ChannelList::iterator chan;
@@ -397,21 +381,20 @@ AudioDiskstream::use_destructive_playlist ()
 }
 
 void
 }
 
 void
-AudioDiskstream::prepare_record_status(nframes_t capture_start_frame)
+AudioDiskstream::prepare_record_status(framepos_t capture_start_frame)
 {
        if (recordable() && destructive()) {
                boost::shared_ptr<ChannelList> c = channels.reader();
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
 
 {
        if (recordable() && destructive()) {
                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);
                                (*chan)->capture_transition_buf->increment_write_ptr(1);
-                       }
-                       else {
+                       } else {
                                // bad!
                                fatal << X_("programming error: capture_transition_buf is full on rec start!  inconceivable!")
                                        << endmsg;
                                // bad!
                                fatal << X_("programming error: capture_transition_buf is full on rec start!  inconceivable!")
                                        << endmsg;
@@ -420,32 +403,41 @@ AudioDiskstream::prepare_record_status(nframes_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
 int
-AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input, bool& need_butler)
+AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance)
 {
        uint32_t n;
        boost::shared_ptr<ChannelList> c = channels.reader();
        ChannelList::iterator chan;
 {
        uint32_t n;
        boost::shared_ptr<ChannelList> c = channels.reader();
        ChannelList::iterator chan;
-       int ret = -1;
-       nframes_t rec_offset = 0;
-       nframes_t rec_nframes = 0;
+       framecnt_t rec_offset = 0;
+       framecnt_t rec_nframes = 0;
        bool collect_playback = false;
        bool collect_playback = false;
+       bool can_record = _session.actively_recording ();
 
 
-        playback_distance = 0;
+       playback_distance = 0;
 
        if (!_io || !_io->active()) {
                return 0;
        }
 
 
        if (!_io || !_io->active()) {
                return 0;
        }
 
-       check_record_status (transport_frame, nframes, can_record);
+       check_record_status (transport_frame, can_record);
 
        if (nframes == 0) {
                return 0;
        }
 
 
        if (nframes == 0) {
                return 0;
        }
 
-        Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK);
+       Glib::Mutex::Lock sm (state_lock, Glib::TRY_LOCK);
 
 
-        if (!sm.locked()) {
+       if (!sm.locked()) {
                return 1;
        }
 
                return 1;
        }
 
@@ -456,29 +448,23 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
                (*chan)->current_playback_buffer = 0;
        }
 
                (*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
+
+       if (last_recordable_frame < first_recordable_frame) {
+               last_recordable_frame = max_framepos;
+       }
 
 
-           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 (record_enabled()) {
 
 
+               OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
+               calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
 
 
-        // Safeguard against situations where process() goes haywire when autopunching and last_recordable_frame < first_recordable_frame
-        if (last_recordable_frame < first_recordable_frame) {
-                last_recordable_frame = max_frames;
-        }
-        
-        OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
-        
-        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 ();
 
        if (can_record && !_last_capture_sources.empty()) {
                _last_capture_sources.clear ();
@@ -501,7 +487,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
 
                        chaninfo->capture_buf->get_write_vector (&chaninfo->capture_vector);
 
 
                        chaninfo->capture_buf->get_write_vector (&chaninfo->capture_vector);
 
-                       if (rec_nframes <= chaninfo->capture_vector.len[0]) {
+                       if (rec_nframes <= (framecnt_t) chaninfo->capture_vector.len[0]) {
 
                                chaninfo->current_capture_buffer = chaninfo->capture_vector.buf[0];
 
 
                                chaninfo->current_capture_buffer = chaninfo->capture_vector.buf[0];
 
@@ -509,26 +495,27 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
                                   for recording, and use rec_offset
                                */
 
                                   for recording, and use rec_offset
                                */
 
-                               AudioPort* const ap = _io->audio (n);
+                               boost::shared_ptr<AudioPort> const ap = _io->audio (n);
                                assert(ap);
                                assert(ap);
-                               assert(rec_nframes <= ap->get_audio_buffer(nframes).capacity());
-                               memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer (nframes).data(rec_offset), sizeof (Sample) * rec_nframes);
+                               assert(rec_nframes <= (framecnt_t) ap->get_audio_buffer(nframes).capacity());
 
 
+                               Sample *buf = ap->get_audio_buffer (nframes).data (rec_offset);
+                               memcpy (chaninfo->current_capture_buffer, buf, sizeof (Sample) * rec_nframes);
 
                        } else {
 
 
                        } else {
 
-                               nframes_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1];
+                               framecnt_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1];
 
                                if (rec_nframes > total) {
                                        DiskOverrun ();
 
                                if (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);
 
                                assert(ap);
 
-                               Sample* buf = ap->get_audio_buffer(nframes).data();
-                               nframes_t first = chaninfo->capture_vector.len[0];
+                               Sample* buf = ap->get_audio_buffer(nframes).data (rec_offset);
+                               framecnt_t first = chaninfo->capture_vector.len[0];
 
                                memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first);
                                memcpy (chaninfo->capture_vector.buf[0], buf, sizeof (Sample) * first);
 
                                memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first);
                                memcpy (chaninfo->capture_vector.buf[0], buf, sizeof (Sample) * first);
@@ -542,7 +529,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
        } else {
 
                if (was_recording) {
        } else {
 
                if (was_recording) {
-                       finish_capture (rec_monitors_input, c);
+                       finish_capture (c);
                }
 
        }
                }
 
        }
@@ -587,16 +574,16 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
                collect_playback = true;
        }
 
                collect_playback = true;
        }
 
-       if (collect_playback) {
-
+       if ((_track->monitoring_state () & MonitoringDisk) || collect_playback) {
+               
                /* we're doing playback */
 
                /* we're doing playback */
 
-               nframes_t necessary_samples;
+               framecnt_t necessary_samples;
 
                /* no varispeed playback if we're recording, because the output .... TBD */
 
                if (rec_nframes == 0 && _actual_speed != 1.0f) {
 
                /* no varispeed playback if we're recording, because the output .... TBD */
 
                if (rec_nframes == 0 && _actual_speed != 1.0f) {
-                       necessary_samples = (nframes_t) floor ((nframes * fabs (_actual_speed))) + 1;
+                       necessary_samples = (framecnt_t) floor ((nframes * fabs (_actual_speed))) + 1;
                } else {
                        necessary_samples = nframes;
                }
                } else {
                        necessary_samples = nframes;
                }
@@ -607,28 +594,41 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
 
                n = 0;
 
 
                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);
 
                for (chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
                        ChannelInfo* chaninfo (*chan);
 
-                       if (necessary_samples <= chaninfo->playback_vector.len[0]) {
-
+                       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 {
                                chaninfo->current_playback_buffer = chaninfo->playback_vector.buf[0];
 
                        } else {
-                               nframes_t total = chaninfo->playback_vector.len[0] + chaninfo->playback_vector.len[1];
+                               framecnt_t total = chaninfo->playback_vector.len[0] + chaninfo->playback_vector.len[1];
 
                                if (necessary_samples > total) {
                                        cerr << _name << " Need " << necessary_samples << " total = " << total << endl;
                                        cerr << "underrun for " << _name << endl;
                                        DiskUnderrun ();
 
                                if (necessary_samples > total) {
                                        cerr << _name << " Need " << necessary_samples << " total = " << total << endl;
                                        cerr << "underrun for " << _name << endl;
                                        DiskUnderrun ();
-                                       goto out;
+                                       return -1;
 
                                } else {
 
 
                                } 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.
+                                       */
+
+                                       /* Copy buf[0] from playback_buf */
                                        memcpy ((char *) chaninfo->playback_wrap_buffer,
                                                        chaninfo->playback_vector.buf[0],
                                                        chaninfo->playback_vector.len[0] * sizeof (Sample));
                                        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])
                                        memcpy (chaninfo->playback_wrap_buffer + chaninfo->playback_vector.len[0],
                                                        chaninfo->playback_vector.buf[1],
                                                        (necessary_samples - chaninfo->playback_vector.len[0])
@@ -640,45 +640,35 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
                }
 
                if (rec_nframes == 0 && _actual_speed != 1.0f && _actual_speed != -1.0f) {
                }
 
                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;
                } else {
                        playback_distance = nframes;
                }
 
                _speed = _target_speed;
-
-       } 
-
-       ret = 0;
-
-        if (commit (nframes)) {
-                need_butler = true;
-        }
-
-  out:
-       return ret;
-}
-
-void
-AudioDiskstream::process_varispeed_playback(nframes_t nframes, boost::shared_ptr<ChannelList> c)
-{
-       ChannelList::iterator chan;
-
-       interpolation.set_speed (_target_speed);
-
-       int channel = 0;
-       for (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;
        }
        }
+
+       return 0;
 }
 
 }
 
+/** 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
 bool
-AudioDiskstream::commit (nframes_t /* nframes */)
+AudioDiskstream::commit (framecnt_t playback_distance)
 {
        bool need_butler = false;
 
 {
        bool need_butler = false;
 
@@ -707,6 +697,10 @@ AudioDiskstream::commit (nframes_t /* nframes */)
                adjust_capture_position = 0;
        }
 
                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;
        if (_slaved) {
                if (_io && _io->active()) {
                        need_butler = c->front()->playback_buf->write_space() >= c->front()->playback_buf->bufsize() / 2;
@@ -715,10 +709,10 @@ AudioDiskstream::commit (nframes_t /* nframes */)
                }
        } else {
                if (_io && _io->active()) {
                }
        } else {
                if (_io && _io->active()) {
-                       need_butler = c->front()->playback_buf->write_space() >= disk_io_chunk_frames
-                               || c->front()->capture_buf->read_space() >= disk_io_chunk_frames;
+                       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);
                } else {
                } else {
-                       need_butler = c->front()->capture_buf->read_space() >= disk_io_chunk_frames;
+                       need_butler = ((framecnt_t) c->front()->capture_buf->read_space() >= disk_io_chunk_frames);
                }
        }
 
                }
        }
 
@@ -733,13 +727,22 @@ AudioDiskstream::set_pending_overwrite (bool yn)
        _pending_overwrite = yn;
 
        overwrite_frame = playback_sample;
        _pending_overwrite = yn;
 
        overwrite_frame = playback_sample;
-       overwrite_offset = channels.reader()->front()->playback_buf->get_read_ptr();
+
+       boost::shared_ptr<ChannelList> c = channels.reader ();
+       if (!c->empty ()) {
+               overwrite_offset = c->front()->playback_buf->get_read_ptr();
+       }
 }
 
 int
 AudioDiskstream::overwrite_existing_buffers ()
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 }
 
 int
 AudioDiskstream::overwrite_existing_buffers ()
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
+       if (c->empty ()) {
+               _pending_overwrite = false;
+               return 0;
+       }
+
        Sample* mixdown_buffer;
        float* gain_buffer;
        int ret = -1;
        Sample* mixdown_buffer;
        float* gain_buffer;
        int ret = -1;
@@ -748,21 +751,23 @@ AudioDiskstream::overwrite_existing_buffers ()
        overwrite_queued = false;
 
        /* assume all are the same size */
        overwrite_queued = false;
 
        /* assume all are the same size */
-       nframes_t size = c->front()->playback_buf->bufsize();
+       framecnt_t size = c->front()->playback_buf->bufsize();
 
        mixdown_buffer = new Sample[size];
        gain_buffer = new float[size];
 
 
        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;
        size--;
 
        uint32_t n=0;
-       nframes_t start;
+       framepos_t start;
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
                start = overwrite_frame;
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
                start = overwrite_frame;
-               nframes_t cnt = size;
+               framecnt_t cnt = size;
 
                /* to fill the buffer without resetting the playback sample, we need to
                   do it one or two chunks (normally two).
 
                /* to fill the buffer without resetting the playback sample, we need to
                   do it one or two chunks (normally two).
@@ -775,11 +780,11 @@ AudioDiskstream::overwrite_existing_buffers ()
 
                */
 
 
                */
 
-               nframes_t to_read = size - overwrite_offset;
+               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"),
                        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;
                }
 
                        goto out;
                }
 
@@ -787,10 +792,9 @@ AudioDiskstream::overwrite_existing_buffers ()
 
                        cnt -= to_read;
 
 
                        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"),
                                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;
                        }
                }
                                goto out;
                        }
                }
@@ -806,7 +810,7 @@ AudioDiskstream::overwrite_existing_buffers ()
 }
 
 int
 }
 
 int
-AudioDiskstream::seek (nframes_t frame, bool complete_refill)
+AudioDiskstream::seek (framepos_t frame, bool complete_refill)
 {
        uint32_t n;
        int ret = -1;
 {
        uint32_t n;
        int ret = -1;
@@ -839,13 +843,13 @@ AudioDiskstream::seek (nframes_t frame, bool complete_refill)
 }
 
 int
 }
 
 int
-AudioDiskstream::can_internal_playback_seek (nframes_t distance)
+AudioDiskstream::can_internal_playback_seek (framecnt_t distance)
 {
        ChannelList::iterator chan;
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (chan = c->begin(); chan != c->end(); ++chan) {
 {
        ChannelList::iterator chan;
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (chan = c->begin(); chan != c->end(); ++chan) {
-               if ((*chan)->playback_buf->read_space() < distance) {
+               if ((*chan)->playback_buf->read_space() < (size_t) distance) {
                        return false;
                }
        }
                        return false;
                }
        }
@@ -853,7 +857,7 @@ AudioDiskstream::can_internal_playback_seek (nframes_t distance)
 }
 
 int
 }
 
 int
-AudioDiskstream::internal_playback_seek (nframes_t distance)
+AudioDiskstream::internal_playback_seek (framecnt_t distance)
 {
        ChannelList::iterator chan;
        boost::shared_ptr<ChannelList> c = channels.reader();
 {
        ChannelList::iterator chan;
        boost::shared_ptr<ChannelList> c = channels.reader();
@@ -862,28 +866,38 @@ AudioDiskstream::internal_playback_seek (nframes_t distance)
                (*chan)->playback_buf->increment_read_ptr (distance);
        }
 
                (*chan)->playback_buf->increment_read_ptr (distance);
        }
 
-       first_recordable_frame += distance;
+       if (first_recordable_frame < max_framepos) {
+               first_recordable_frame += distance;
+       }
        playback_sample += distance;
 
        return 0;
 }
 
        playback_sample += 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
 int
-AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, nframes_t& start, nframes_t cnt,
-                      ChannelInfo* /*channel_info*/, int channel, bool reversed)
+AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
+                       framepos_t& start, framecnt_t cnt,
+                       int channel, bool reversed)
 {
 {
-       nframes_t this_read = 0;
+       framecnt_t this_read = 0;
        bool reloop = false;
        bool reloop = false;
-       nframes_t loop_end = 0;
-       nframes_t loop_start = 0;
-       nframes_t offset = 0;
+       framepos_t loop_end = 0;
+       framepos_t loop_start = 0;
+       framecnt_t offset = 0;
        Location *loc = 0;
 
        /* XXX we don't currently play loops in reverse. not sure why */
 
        if (!reversed) {
 
        Location *loc = 0;
 
        /* XXX we don't currently play loops in reverse. not sure why */
 
        if (!reversed) {
 
-               nframes_t loop_length = 0;
+               framecnt_t loop_length = 0;
 
                /* Make the use of a Location atomic for this read operation.
 
 
                /* Make the use of a Location atomic for this read operation.
 
@@ -904,25 +918,24 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
                */
 
                if (loc && start >= loop_end) {
                */
 
                if (loc && start >= loop_end) {
-                       //cerr << "start adjusted from " << start;
                        start = loop_start + ((start - loop_start) % loop_length);
                        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;
        }
 
        }
 
-       while (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.
+       */
 
 
-               if (reversed) {
-                       start -= cnt;
-               }
+       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;
 
                /* 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;
                        reloop = true;
                } else {
                        reloop = false;
@@ -936,13 +949,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) {
                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;
                }
 
                                         start) << endmsg;
                        return -1;
                }
 
-               _read_data_count = _playlist->read_data_count();
-
                if (reversed) {
 
                        swap_by_ptr (buf, buf + this_read - 1);
                if (reversed) {
 
                        swap_by_ptr (buf, buf + this_read - 1);
@@ -979,19 +990,22 @@ AudioDiskstream::do_refill_with_alloc ()
        return ret;
 }
 
        return ret;
 }
 
+/** Get some more data from disk and put it in our channels' playback_bufs,
+ *  if there is suitable space in them.
+ */
 int
 AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 {
        int32_t ret = 0;
 int
 AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 {
        int32_t ret = 0;
-       nframes_t to_read;
+       framecnt_t to_read;
        RingBufferNPT<Sample>::rw_vector vector;
        RingBufferNPT<Sample>::rw_vector vector;
-       bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
-       nframes_t total_space;
-       nframes_t zero_fill;
+       bool const reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
+       framecnt_t total_space;
+       framecnt_t zero_fill;
        uint32_t chan_n;
        ChannelList::iterator i;
        boost::shared_ptr<ChannelList> c = channels.reader();
        uint32_t chan_n;
        ChannelList::iterator i;
        boost::shared_ptr<ChannelList> c = channels.reader();
-       nframes_t ts;
+       framecnt_t ts;
 
        if (c->empty()) {
                return 0;
 
        if (c->empty()) {
                return 0;
@@ -1008,6 +1022,7 @@ 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) {
        c->front()->playback_buf->get_write_vector (&vector);
 
        if ((total_space = vector.len[0] + vector.len[1]) == 0) {
+               /* nowhere to write to */
                return 0;
        }
 
                return 0;
        }
 
@@ -1016,7 +1031,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
           for us to be called again, ASAP.
        */
 
           for us to be called again, ASAP.
        */
 
-       if (total_space >= (_slaved?3:2) * disk_io_chunk_frames) {
+       if (total_space >= (_slaved ? 3 : 2) * disk_io_chunk_frames) {
                ret = 1;
        }
 
                ret = 1;
        }
 
@@ -1025,6 +1040,10 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 
           at higher speeds, just do it because the sync between butler
           and audio thread may not be good enough.
 
           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_io_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_io_chunk_frames) && fabs (_actual_speed) < 2.0f) {
@@ -1036,7 +1055,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
           work with.
        */
 
           work with.
        */
 
-       if (_slaved && total_space < (c->front()->playback_buf->bufsize() / 2)) {
+       if (_slaved && total_space < (framecnt_t) (c->front()->playback_buf->bufsize() / 2)) {
                return 0;
        }
 
                return 0;
        }
 
@@ -1071,7 +1090,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 
                        zero_fill = total_space - file_frame;
                        total_space = file_frame;
 
                        zero_fill = total_space - file_frame;
                        total_space = file_frame;
-                       file_frame = 0;
 
                } else {
 
 
                } else {
 
@@ -1080,7 +1098,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
 
        } else {
 
 
        } else {
 
-               if (file_frame == max_frames) {
+               if (file_frame == max_framepos) {
 
                        /* at end: nothing to do but fill with silence */
 
 
                        /* at end: nothing to do but fill with silence */
 
@@ -1097,30 +1115,30 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
                        return 0;
                }
 
                        return 0;
                }
 
-               if (file_frame > max_frames - total_space) {
+               if (file_frame > max_framepos - total_space) {
 
                        /* to close to the end: read what we can, and zero fill the rest */
 
 
                        /* to close to the end: read what we can, and zero fill the rest */
 
-                       zero_fill = total_space - (max_frames - file_frame);
-                       total_space = max_frames - file_frame;
+                       zero_fill = total_space - (max_framepos - file_frame);
+                       total_space = max_framepos - file_frame;
 
                } else {
                        zero_fill = 0;
                }
        }
 
 
                } else {
                        zero_fill = 0;
                }
        }
 
-       nframes_t file_frame_tmp = 0;
+       framepos_t file_frame_tmp = 0;
 
        for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
 
                ChannelInfo* chan (*i);
                Sample* buf1;
                Sample* buf2;
 
        for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
 
                ChannelInfo* chan (*i);
                Sample* buf1;
                Sample* buf2;
-               nframes_t len1, len2;
+               framecnt_t len1, len2;
 
                chan->playback_buf->get_write_vector (&vector);
 
 
                chan->playback_buf->get_write_vector (&vector);
 
-               if (vector.len[0] > disk_io_chunk_frames) {
+               if ((framecnt_t) vector.len[0] > disk_io_chunk_frames) {
 
                        /* 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:
 
                        /* 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:
@@ -1154,9 +1172,11 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
                to_read = min (ts, len1);
                to_read = min (to_read, disk_io_chunk_frames);
 
                to_read = min (ts, len1);
                to_read = min (to_read, disk_io_chunk_frames);
 
+               assert (to_read >= 0);
+
                if (to_read) {
 
                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;
                        }
                                ret = -1;
                                goto out;
                        }
@@ -1173,7 +1193,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
                           so read some or all of vector.len[1] as well.
                        */
 
                           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;
                        }
                                ret = -1;
                                goto out;
                        }
@@ -1182,12 +1202,13 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
                }
 
                if (zero_fill) {
                }
 
                if (zero_fill) {
-                       /* do something */
+                       /* XXX: do something */
                }
 
        }
 
        file_frame = file_frame_tmp;
                }
 
        }
 
        file_frame = file_frame_tmp;
+       assert (file_frame >= 0);
 
   out:
 
 
   out:
 
@@ -1211,9 +1232,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
        int32_t ret = 0;
        RingBufferNPT<Sample>::rw_vector vector;
        RingBufferNPT<CaptureTransition>::rw_vector transvec;
        int32_t ret = 0;
        RingBufferNPT<Sample>::rw_vector vector;
        RingBufferNPT<CaptureTransition>::rw_vector transvec;
-       nframes_t total;
-
-       _write_data_count = 0;
+       framecnt_t total;
 
        transvec.buf[0] = 0;
        transvec.buf[1] = 0;
 
        transvec.buf[0] = 0;
        transvec.buf[1] = 0;
@@ -1246,7 +1265,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                        ret = 1;
                }
 
                        ret = 1;
                }
 
-               to_write = min (disk_io_chunk_frames, (nframes_t) vector.len[0]);
+               to_write = min (disk_io_chunk_frames, (framecnt_t) vector.len[0]);
 
                // check the transition buffer when recording destructive
                // important that we get this after the capture buf
 
                // check the transition buffer when recording destructive
                // important that we get this after the capture buf
@@ -1254,7 +1273,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];
                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) {
                        size_t ti;
 
                        for (ti=0; ti < transcount; ++ti) {
@@ -1266,9 +1284,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                                        (*chan)->write_source->mark_capture_start (captrans.capture_val);
                                        (*chan)->curr_capture_cnt = 0;
 
                                        (*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
 
 
                                        // capture end, the capture_val represents total frames in capture
 
@@ -1302,7 +1318,7 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                }
 
                if ((!(*chan)->write_source) || (*chan)->write_source->write (vector.buf[0], to_write) != to_write) {
                }
 
                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;
                }
 
                        return -1;
                }
 
@@ -1316,15 +1332,13 @@ AudioDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                           of vector.len[1] to be flushed to disk as well.
                        */
 
                           of vector.len[1] to be flushed to disk as well.
                        */
 
-                       to_write = min ((nframes_t)(disk_io_chunk_frames - to_write), (nframes_t) vector.len[1]);
+                       to_write = min ((framecnt_t)(disk_io_chunk_frames - to_write), (framecnt_t) vector.len[1]);
 
                        if ((*chan)->write_source->write (vector.buf[1], to_write) != 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;
                        }
 
                                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;
                }
                        (*chan)->capture_buf->increment_read_ptr (to_write);
                        (*chan)->curr_capture_cnt += to_write;
                }
@@ -1341,7 +1355,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
        bool more_work = true;
        int err = 0;
        boost::shared_ptr<AudioRegion> region;
        bool more_work = true;
        int err = 0;
        boost::shared_ptr<AudioRegion> region;
-       nframes_t total_capture;
+       framecnt_t total_capture;
        SourceList srcs;
        SourceList::iterator src;
        ChannelList::iterator chan;
        SourceList srcs;
        SourceList::iterator src;
        ChannelList::iterator chan;
@@ -1350,7 +1364,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
        uint32_t n = 0;
        bool mark_write_completed = false;
 
        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.
 
        /* butler is already stopped, but there may be work to do
           to flush remaining data to disk.
@@ -1388,7 +1402,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                                (*chan)->write_source->mark_for_remove ();
                                (*chan)->write_source->drop_references ();
 
                                (*chan)->write_source->mark_for_remove ();
                                (*chan)->write_source->drop_references ();
-                                _session.remove_source ((*chan)->write_source);
                                (*chan)->write_source.reset ();
                        }
 
                                (*chan)->write_source.reset ();
                        }
 
@@ -1410,9 +1423,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                if (s) {
                        srcs.push_back (s);
 
                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 ();
                        s->update_header (capture_info.front()->start, when, twhen);
                        s->set_captured_for (_name.val());
                        s->mark_immutable ();
@@ -1470,7 +1480,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
 
 
                // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
 
-                _playlist->clear_changes ();
+               _playlist->clear_changes ();
                _playlist->freeze ();
 
                for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
                _playlist->freeze ();
 
                for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
@@ -1479,16 +1489,17 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 
                        RegionFactory::region_name (region_name, whole_file_region_name, false);
 
 
                        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 start @ %2 length %3 add new region %4\n",
+                                                                             _name, (*ci)->start, (*ci)->frames, region_name));
 
                        try {
 
                                PropertyList plist;
 
                        try {
 
                                PropertyList plist;
-                               
+
                                plist.add (Properties::start, buffer_position);
                                plist.add (Properties::length, (*ci)->frames);
                                plist.add (Properties::name, region_name);
                                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);
                        }
                                boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
                                region = boost::dynamic_pointer_cast<AudioRegion> (rx);
                        }
@@ -1499,7 +1510,9 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
                        }
 
                        i_am_the_modifier++;
                        }
 
                        i_am_the_modifier++;
+
                        _playlist->add_region (region, (*ci)->start, 1, non_layered());
                        _playlist->add_region (region, (*ci)->start, 1, non_layered());
+                       _playlist->set_layer (region, DBL_MAX);
                        i_am_the_modifier--;
 
                        buffer_position += (*ci)->frames;
                        i_am_the_modifier--;
 
                        buffer_position += (*ci)->frames;
@@ -1525,7 +1538,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
 }
 
 void
 }
 
 void
-AudioDiskstream::transport_looped (nframes_t transport_frame)
+AudioDiskstream::transport_looped (framepos_t transport_frame)
 {
        if (was_recording) {
                // all we need to do is finish this capture, with modified capture length
 {
        if (was_recording) {
                // all we need to do is finish this capture, with modified capture length
@@ -1543,14 +1556,14 @@ AudioDiskstream::transport_looped (nframes_t transport_frame)
                        }
                }
 
                        }
                }
 
-               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
                // no latency adjustment or capture offset needs to be made, as that already happened the first time
                capture_start_frame = transport_frame;
                first_recordable_frame = transport_frame; // mild lie
 
                // the next region will start recording via the normal mechanism
                // we'll set the start position to the current transport pos
                // no latency adjustment or capture offset needs to be made, as that already happened the first time
                capture_start_frame = transport_frame;
                first_recordable_frame = transport_frame; // mild lie
-               last_recordable_frame = max_frames;
+               last_recordable_frame = max_framepos;
                was_recording = true;
 
                if (recordable() && destructive()) {
                was_recording = true;
 
                if (recordable() && destructive()) {
@@ -1576,11 +1589,11 @@ AudioDiskstream::transport_looped (nframes_t transport_frame)
 }
 
 void
 }
 
 void
-AudioDiskstream::finish_capture (bool /*rec_monitors_input*/, boost::shared_ptr<ChannelList> c)
+AudioDiskstream::finish_capture (boost::shared_ptr<ChannelList> c)
 {
        was_recording = false;
 {
        was_recording = false;
-        first_recordable_frame = max_frames;
-        last_recordable_frame = max_frames;
+       first_recordable_frame = max_framepos;
+       last_recordable_frame = max_framepos;
 
        if (capture_captured == 0) {
                return;
 
        if (capture_captured == 0) {
                return;
@@ -1625,7 +1638,7 @@ AudioDiskstream::finish_capture (bool /*rec_monitors_input*/, boost::shared_ptr<
        capture_captured = 0;
 
        /* now we've finished a capture, reset first_recordable_frame for next time */
        capture_captured = 0;
 
        /* now we've finished a capture, reset first_recordable_frame for next time */
-       first_recordable_frame = max_frames;
+       first_recordable_frame = max_framepos;
 }
 
 void
 }
 
 void
@@ -1666,9 +1679,7 @@ AudioDiskstream::engage_record_enable ()
        if (Config->get_monitoring_model() == HardwareMonitoring) {
 
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
        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_jack_monitors_input (!(_session.config.get_auto_input() && rolling));
                        capturing_sources.push_back ((*chan)->write_source);
                        (*chan)->write_source->mark_streaming_write_started ();
                }
                        capturing_sources.push_back ((*chan)->write_source);
                        (*chan)->write_source->mark_streaming_write_started ();
                }
@@ -1690,9 +1701,7 @@ AudioDiskstream::disengage_record_enable ()
        boost::shared_ptr<ChannelList> c = channels.reader();
        if (Config->get_monitoring_model() == HardwareMonitoring) {
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
        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_jack_monitors_input (false);
                }
        }
        capturing_sources.clear ();
                }
        }
        capturing_sources.clear ();
@@ -1702,24 +1711,13 @@ AudioDiskstream::disengage_record_enable ()
 XMLNode&
 AudioDiskstream::get_state ()
 {
 XMLNode&
 AudioDiskstream::get_state ()
 {
-       XMLNode* node = new XMLNode ("Diskstream");
+       XMLNode& node (Diskstream::get_state());
        char buf[64] = "";
        LocaleGuard lg (X_("POSIX"));
        char buf[64] = "";
        LocaleGuard lg (X_("POSIX"));
-       boost::shared_ptr<ChannelList> c = channels.reader();
-
-       node->add_property ("flags", enum_2_string (_flags));
 
 
+       boost::shared_ptr<ChannelList> c = channels.reader();
        snprintf (buf, sizeof(buf), "%zd", c->size());
        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);
+       node.add_property ("channels", buf);
 
        if (!capturing_sources.empty() && _session.get_record_enabled()) {
 
 
        if (!capturing_sources.empty() && _session.get_record_enabled()) {
 
@@ -1743,18 +1741,14 @@ AudioDiskstream::get_state ()
                }
 
                cs_child->add_property (X_("at"), buf);
                }
 
                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
 }
 
 int
-AudioDiskstream::set_state (const XMLNode& node, int /*version*/)
+AudioDiskstream::set_state (const XMLNode& node, int version)
 {
        const XMLProperty* prop;
        XMLNodeList nlist = node.children();
 {
        const XMLProperty* prop;
        XMLNodeList nlist = node.children();
@@ -1763,6 +1757,8 @@ AudioDiskstream::set_state (const XMLNode& node, int /*version*/)
        XMLNode* capture_pending_node = 0;
        LocaleGuard lg (X_("POSIX"));
 
        XMLNode* capture_pending_node = 0;
        LocaleGuard lg (X_("POSIX"));
 
+       /* prevent write sources from being created */
+
        in_set_state = true;
 
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
        in_set_state = true;
 
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
@@ -1775,26 +1771,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) {
        }
 
        if ((prop = node.property ("channels")) != 0) {
@@ -1816,37 +1794,14 @@ AudioDiskstream::set_state (const XMLNode& node, int /*version*/)
                remove_channel (_n_channels.n_audio() - nchans);
        }
 
                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;
        }
 
        in_set_state = false;
@@ -1879,13 +1834,8 @@ AudioDiskstream::use_new_write_source (uint32_t n)
        ChannelInfo* chan = (*c)[n];
 
        try {
        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(), name(), n, destructive())) == 0) {
                        throw failed_constructor();
                }
        }
                        throw failed_constructor();
                }
        }
@@ -1899,16 +1849,16 @@ 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());
        /* do not remove destructive files even if they are empty */
 
        chan->write_source->set_allow_remove_if_empty (!destructive());
-       
+
        return 0;
 }
 
        return 0;
 }
 
-list<boost::shared_ptr<Source> > 
+list<boost::shared_ptr<Source> >
 AudioDiskstream::steal_write_sources()
 {
 AudioDiskstream::steal_write_sources()
 {
-        /* not possible to steal audio write sources */
-        list<boost::shared_ptr<Source> > ret;
-        return ret;
+       /* not possible to steal audio write sources */
+       list<boost::shared_ptr<Source> > ret;
+       return ret;
 }
 
 void
 }
 
 void
@@ -1935,14 +1885,13 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
                                        (*chan)->write_source->done_with_peakfile_writes ();
                                }
 
                                        (*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);
 
 
                        use_new_write_source (n);
 
@@ -1970,25 +1919,8 @@ 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
 void
-AudioDiskstream::set_block_size (nframes_t /*nframes*/)
+AudioDiskstream::set_block_size (pframes_t /*nframes*/)
 {
        if (_session.get_block_size() > speed_buffer_size) {
                speed_buffer_size = _session.get_block_size();
 {
        if (_session.get_block_size() > speed_buffer_size) {
                speed_buffer_size = _session.get_block_size();
@@ -2012,18 +1944,20 @@ AudioDiskstream::allocate_temporary_buffers ()
        */
 
        double const sp = max (fabsf (_actual_speed), 1.2f);
        */
 
        double const sp = max (fabsf (_actual_speed), 1.2f);
-       nframes_t required_wrap_size = (nframes_t) floor (_session.get_block_size() * sp) + 1;
+       framecnt_t required_wrap_size = (framecnt_t) floor (_session.get_block_size() * sp) + 1;
 
        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 (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;
                                delete [] (*chan)->playback_wrap_buffer;
+                       }
                        (*chan)->playback_wrap_buffer = new Sample[required_wrap_size];
                        (*chan)->playback_wrap_buffer = new Sample[required_wrap_size];
-                       if ((*chan)->capture_wrap_buffer)
+                       if ((*chan)->capture_wrap_buffer) {
                                delete [] (*chan)->capture_wrap_buffer;
                                delete [] (*chan)->capture_wrap_buffer;
+                       }
                        (*chan)->capture_wrap_buffer = new Sample[required_wrap_size];
                }
 
                        (*chan)->capture_wrap_buffer = new Sample[required_wrap_size];
                }
 
@@ -2032,15 +1966,12 @@ AudioDiskstream::allocate_temporary_buffers ()
 }
 
 void
 }
 
 void
-AudioDiskstream::monitor_input (bool yn)
+AudioDiskstream::request_jack_monitors_input (bool yn)
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
 {
        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_jack_monitors_input (yn);
        }
 }
 
        }
 }
 
@@ -2049,6 +1980,10 @@ AudioDiskstream::set_align_style_from_io ()
 {
        bool have_physical = false;
 
 {
        bool have_physical = false;
 
+       if (_alignment_choice != Automatic) {
+               return;
+       }
+
        if (_io == 0) {
                return;
        }
        if (_io == 0) {
                return;
        }
@@ -2058,7 +1993,7 @@ AudioDiskstream::set_align_style_from_io ()
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
        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;
                }
                        have_physical = true;
                        break;
                }
@@ -2075,10 +2010,13 @@ int
 AudioDiskstream::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many)
 {
        while (how_many--) {
 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());
        }
 
        _n_channels.set(DataType::AUDIO, c->size());
@@ -2123,6 +2061,10 @@ AudioDiskstream::playback_buffer_load () const
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
+       if (c->empty ()) {
+               return 0;
+       }
+
        return (float) ((double) c->front()->playback_buf->read_space()/
                        (double) c->front()->playback_buf->bufsize());
 }
        return (float) ((double) c->front()->playback_buf->read_space()/
                        (double) c->front()->playback_buf->bufsize());
 }
@@ -2132,6 +2074,10 @@ AudioDiskstream::capture_buffer_load () const
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
 {
        boost::shared_ptr<ChannelList> c = channels.reader();
 
+       if (c->empty ()) {
+               return 0;
+       }
+
        return (float) ((double) c->front()->capture_buf->write_space()/
                        (double) c->front()->capture_buf->bufsize());
 }
        return (float) ((double) c->front()->capture_buf->write_space()/
                        (double) c->front()->capture_buf->bufsize());
 }
@@ -2145,13 +2091,13 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
        boost::shared_ptr<AudioFileSource> fs;
        boost::shared_ptr<AudioFileSource> first_fs;
        SourceList pending_sources;
        boost::shared_ptr<AudioFileSource> fs;
        boost::shared_ptr<AudioFileSource> first_fs;
        SourceList pending_sources;
-       nframes_t position;
+       framepos_t position;
 
        if ((prop = node.property (X_("at"))) == 0) {
                return -1;
        }
 
 
        if ((prop = node.property (X_("at"))) == 0) {
                return -1;
        }
 
-       if (sscanf (prop->value().c_str(), "%" PRIu32, &position) != 1) {
+       if (sscanf (prop->value().c_str(), "%" PRIu64, &position) != 1) {
                return -1;
        }
 
                return -1;
        }
 
@@ -2170,8 +2116,9 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
 
                        try {
                                fs = boost::dynamic_pointer_cast<AudioFileSource> (
 
                        try {
                                fs = boost::dynamic_pointer_cast<AudioFileSource> (
-                                               SourceFactory::createWritable (DataType::AUDIO, _session,
-                                                               prop->value(), false, _session.frame_rate()));
+                                       SourceFactory::createWritable (
+                                               DataType::AUDIO, _session,
+                                               prop->value(), string(), false, _session.frame_rate()));
                        }
 
                        catch (failed_constructor& err) {
                        }
 
                        catch (failed_constructor& err) {
@@ -2205,9 +2152,9 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
        boost::shared_ptr<AudioRegion> region;
 
        try {
        boost::shared_ptr<AudioRegion> region;
 
        try {
-               
+
                PropertyList plist;
                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));
                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));
@@ -2316,30 +2263,48 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const
        return true;
 }
 
        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) {
 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) {
 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_jack_monitors_input (bool yn) const
+{
+       if (name.empty()) {
+               return;
+       }
+
+       return AudioEngine::instance()->request_jack_monitors_input (name, yn);
 }
 
 }
 
-AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t playback_bufsize, nframes_t capture_bufsize, nframes_t speed_size, nframes_t wrap_size)
+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;
        current_capture_buffer = 0;
        current_playback_buffer = 0;
        curr_capture_cnt = 0;
@@ -2364,17 +2329,17 @@ AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t playback_bufsize, nframes_t
 }
 
 void
 }
 
 void
-AudioDiskstream::ChannelInfo::resize_playback (nframes_t playback_bufsize)
+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());
 }
 
 void
        playback_buf = new RingBufferNPT<Sample> (playback_bufsize);
        memset (playback_buf->buffer(), 0, sizeof (Sample) * playback_buf->bufsize());
 }
 
 void
-AudioDiskstream::ChannelInfo::resize_capture (nframes_t capture_bufsize)
+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());
 
        capture_buf = new RingBufferNPT<Sample> (capture_bufsize);
        memset (capture_buf->buffer(), 0, sizeof (Sample) * capture_buf->bufsize());
@@ -2382,7 +2347,7 @@ AudioDiskstream::ChannelInfo::resize_capture (nframes_t capture_bufsize)
 
 AudioDiskstream::ChannelInfo::~ChannelInfo ()
 {
 
 AudioDiskstream::ChannelInfo::~ChannelInfo ()
 {
-        write_source.reset ();
+       write_source.reset ();
 
        delete [] speed_buffer;
        speed_buffer = 0;
 
        delete [] speed_buffer;
        speed_buffer = 0;
@@ -2403,3 +2368,21 @@ AudioDiskstream::ChannelInfo::~ChannelInfo ()
        capture_transition_buf = 0;
 }
 
        capture_transition_buf = 0;
 }
 
+
+bool
+AudioDiskstream::set_name (string const & name)
+{
+       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;
+}