convert codebase to use Temporal for various time types
[ardour.git] / libs / ardour / disk_writer.cc
index 2b38e0a2393d825f3b01b61e4b3c1f38ee2c2a25..b5dade0dc11f6c376aa900bfb51c35bda74cb7ca 100644 (file)
@@ -17,8 +17,6 @@
 
 */
 
-#include "pbd/i18n.h"
-
 #include "ardour/analyser.h"
 #include "ardour/audioengine.h"
 #include "ardour/audiofilesource.h"
 #include "ardour/session.h"
 #include "ardour/smf_source.h"
 
+#include "pbd/i18n.h"
+
 using namespace ARDOUR;
 using namespace PBD;
 using namespace std;
 
-ARDOUR::framecnt_t DiskWriter::_chunk_frames = DiskWriter::default_chunk_frames ();
+ARDOUR::samplecnt_t DiskWriter::_chunk_samples = DiskWriter::default_chunk_samples ();
 PBD::Signal0<void> DiskWriter::Overrun;
 
 DiskWriter::DiskWriter (Session& s, string const & str, DiskIOProcessor::Flag f)
        : DiskIOProcessor (s, str, f)
-        , capture_start_frame (0)
-        , capture_captured (0)
-        , was_recording (false)
-        , adjust_capture_position (0)
-        , _capture_offset (0)
-        , first_recordable_frame (max_framepos)
-        , last_recordable_frame (max_framepos)
-        , last_possibly_recording (0)
-        , _alignment_style (ExistingMaterial)
-        , _alignment_choice (Automatic)
+       , _record_enabled (0)
+       , _record_safe (0)
+       , capture_start_sample (0)
+       , capture_captured (0)
+       , was_recording (false)
+       , adjust_capture_position (0)
+       , _capture_offset (0)
+       , first_recordable_sample (max_samplepos)
+       , last_recordable_sample (max_samplepos)
+       , last_possibly_recording (0)
+       , _alignment_style (ExistingMaterial)
        , _num_captured_loops (0)
        , _accumulated_capture_offset (0)
        , _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
@@ -62,8 +63,19 @@ DiskWriter::DiskWriter (Session& s, string const & str, DiskIOProcessor::Flag f)
        DiskIOProcessor::init ();
 }
 
-framecnt_t
-DiskWriter::default_chunk_frames ()
+DiskWriter::~DiskWriter ()
+{
+       DEBUG_TRACE (DEBUG::Destruction, string_compose ("DiskWriter %1 @ %2 deleted\n", _name, this));
+
+       boost::shared_ptr<ChannelList> c = channels.reader();
+
+       for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+               (*chan)->write_source.reset ();
+       }
+}
+
+samplecnt_t
+DiskWriter::default_chunk_samples ()
 {
        return 65536;
 }
@@ -76,7 +88,7 @@ DiskWriter::set_write_source_name (string const & str)
 }
 
 void
-DiskWriter::check_record_status (framepos_t transport_frame, bool can_record)
+DiskWriter::check_record_status (samplepos_t transport_sample, bool can_record)
 {
        int possibly_recording;
        int rolling;
@@ -98,7 +110,7 @@ DiskWriter::check_record_status (framepos_t transport_frame, bool can_record)
                return;
        }
 
-       const framecnt_t existing_material_offset = _session.worst_playback_latency();
+       const samplecnt_t existing_material_offset = _session.worst_playback_latency();
 
        if (possibly_recording == fully_rec_enabled) {
 
@@ -106,27 +118,27 @@ DiskWriter::check_record_status (framepos_t transport_frame, bool can_record)
                        return;
                }
 
-               capture_start_frame = _session.transport_frame();
-               first_recordable_frame = capture_start_frame + _capture_offset;
-               last_recordable_frame = max_framepos;
+               capture_start_sample = _session.transport_sample();
+               first_recordable_sample = capture_start_sample + _capture_offset;
+               last_recordable_sample = max_samplepos;
 
                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 (%9) FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8 WOL %10 WTL %11\n",
-                                                                      name(), first_recordable_frame, last_recordable_frame, capture_start_frame,
+                                                                      name(), first_recordable_sample, last_recordable_sample, capture_start_sample,
                                                                       _capture_offset,
                                                                       existing_material_offset,
-                                                                      transport_frame,
-                                                                      _session.transport_frame(),
+                                                                      transport_sample,
+                                                                      _session.transport_sample(),
                                                                       _session.worst_output_latency(),
                                                                       _session.worst_track_latency()));
 
 
                 if (_alignment_style == ExistingMaterial) {
-                        first_recordable_frame += existing_material_offset;
+                        first_recordable_sample += existing_material_offset;
                         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift FRF by EMO %1\n",
-                                                                              first_recordable_frame));
+                                                                              first_recordable_sample));
                 }
 
-               prepare_record_status (capture_start_frame);
+               prepare_record_status (capture_start_sample);
 
        } else {
 
@@ -136,7 +148,7 @@ DiskWriter::check_record_status (framepos_t transport_frame, bool can_record)
 
                        if (change & transport_rolling) {
 
-                               /* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop(). We
+                               /* transport-change (stopped rolling): last_recordable_sample was set in ::prepare_to_stop(). We
                                 * had to set it there because we likely rolled past the stopping point to declick out,
                                 * and then backed up.
                                 */
@@ -144,10 +156,10 @@ DiskWriter::check_record_status (framepos_t transport_frame, bool can_record)
                        } else {
                                /* punch out */
 
-                               last_recordable_frame = _session.transport_frame() + _capture_offset;
+                               last_recordable_sample = _session.transport_sample() + _capture_offset;
 
                                if (_alignment_style == ExistingMaterial) {
-                                       last_recordable_frame += existing_material_offset;
+                                       last_recordable_sample += existing_material_offset;
                                }
                        }
                }
@@ -157,8 +169,8 @@ DiskWriter::check_record_status (framepos_t transport_frame, bool can_record)
 }
 
 void
-DiskWriter::calculate_record_range (Evoral::OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
-                                   framecnt_t & rec_nframes, framecnt_t & rec_offset)
+DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transport_sample, samplecnt_t nframes,
+                                   samplecnt_t & rec_nframes, samplecnt_t & rec_offset)
 {
        switch (ot) {
        case Evoral::OverlapNone:
@@ -177,9 +189,9 @@ DiskWriter::calculate_record_range (Evoral::OverlapType ot, framepos_t transport
                /*    |--------|    recrange
                 *  -----|          transrange
                 */
-               rec_nframes = transport_frame + nframes - first_recordable_frame;
+               rec_nframes = transport_sample + nframes - first_recordable_sample;
                if (rec_nframes) {
-                       rec_offset = first_recordable_frame - transport_frame;
+                       rec_offset = first_recordable_sample - transport_sample;
                }
                break;
 
@@ -187,7 +199,7 @@ DiskWriter::calculate_record_range (Evoral::OverlapType ot, framepos_t transport
                /*    |--------|    recrange
                 *       |--------  transrange
                 */
-               rec_nframes = last_recordable_frame - transport_frame;
+               rec_nframes = last_recordable_sample - transport_sample;
                rec_offset = 0;
                break;
 
@@ -195,34 +207,34 @@ DiskWriter::calculate_record_range (Evoral::OverlapType ot, framepos_t transport
                /*    |--------|    recrange
                 *  --------------  transrange
                 */
-               rec_nframes = last_recordable_frame - first_recordable_frame;
-               rec_offset = first_recordable_frame - transport_frame;
+               rec_nframes = last_recordable_sample - first_recordable_sample;
+               rec_offset = first_recordable_sample - transport_sample;
                break;
        }
 
         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n",
-                                                              _name, enum_2_string (ot), transport_frame, nframes,
-                                                              first_recordable_frame, last_recordable_frame, rec_nframes, rec_offset));
+                                                              _name, enum_2_string (ot), transport_sample, nframes,
+                                                              first_recordable_sample, last_recordable_sample, rec_nframes, rec_offset));
 }
 
 void
-DiskWriter::prepare_to_stop (framepos_t transport_frame, framepos_t audible_frame)
+DiskWriter::prepare_to_stop (samplepos_t transport_sample, samplepos_t audible_sample)
 {
        switch (_alignment_style) {
        case ExistingMaterial:
-               last_recordable_frame = transport_frame + _capture_offset;
-               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable frame to %2 + %3 = %4\n", _name, transport_frame, _capture_offset, last_recordable_frame));
+               last_recordable_sample = transport_sample + _capture_offset;
+               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable sample to %2 + %3 = %4\n", _name, transport_sample, _capture_offset, last_recordable_sample));
                break;
 
        case CaptureTime:
-               last_recordable_frame = audible_frame; // note that capture_offset is zero
-               /* we may already have captured audio before the last_recordable_frame (audible frame),
+               last_recordable_sample = audible_sample; // note that capture_offset is zero
+               /* we may already have captured audio before the last_recordable_sample (audible sample),
                   so deal with this.
                */
-               if (last_recordable_frame > capture_start_frame) {
-                       capture_captured = min (capture_captured, last_recordable_frame - capture_start_frame);
+               if (last_recordable_sample > capture_start_sample) {
+                       capture_captured = min (capture_captured, last_recordable_sample - capture_start_sample);
                }
-               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable frame to audible frame @ %2\n", _name, audible_frame));
+               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable sample to audible sample @ %2\n", _name, audible_sample));
                break;
        }
 
@@ -252,9 +264,9 @@ DiskWriter::disengage_record_safe ()
        g_atomic_int_set (&_record_safe, 0);
 }
 
-/** Get the start position (in session frames) of the nth capture in the current pass */
-ARDOUR::framepos_t
-DiskWriter::get_capture_start_frame (uint32_t n) const
+/** Get the start position (in session samples) of the nth capture in the current pass */
+ARDOUR::samplepos_t
+DiskWriter::get_capture_start_sample (uint32_t n) const
 {
        Glib::Threads::Mutex::Lock lm (capture_info_lock);
 
@@ -263,18 +275,18 @@ DiskWriter::get_capture_start_frame (uint32_t n) const
                return capture_info[n]->start;
        } else {
                /* this is the currently in-progress capture */
-               return capture_start_frame;
+               return capture_start_sample;
        }
 }
 
-ARDOUR::framecnt_t
-DiskWriter::get_captured_frames (uint32_t n) const
+ARDOUR::samplecnt_t
+DiskWriter::get_captured_samples (uint32_t n) const
 {
        Glib::Threads::Mutex::Lock lm (capture_info_lock);
 
        if (capture_info.size() > n) {
                /* this is a completed capture */
-               return capture_info[n]->frames;
+               return capture_info[n]->samples;
        } else {
                /* this is the currently in-progress capture */
                return capture_captured;
@@ -282,9 +294,10 @@ DiskWriter::get_captured_frames (uint32_t n) const
 }
 
 void
-DiskWriter::set_input_latency (framecnt_t l)
+DiskWriter::set_input_latency (samplecnt_t l)
 {
-       _input_latency = l;
+       Processor::set_input_latency (l);
+       set_capture_offset ();
 }
 
 void
@@ -301,7 +314,7 @@ DiskWriter::set_capture_offset ()
                break;
        }
 
-        DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: using IO latency, capture offset set to %2 with style = %3\n", name(), _capture_offset, enum_2_string (_alignment_style)));
+       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: using input latency %4, capture offset set to %2 with style = %3\n", name(), _capture_offset, enum_2_string (_alignment_style), _input_latency));
 }
 
 
@@ -319,92 +332,11 @@ DiskWriter::set_align_style (AlignStyle a, bool force)
        }
 }
 
-void
-DiskWriter::set_align_style_from_io ()
-{
-       bool have_physical = false;
-
-       if (_alignment_choice != Automatic) {
-               return;
-       }
-
-       if (!_route) {
-               return;
-       }
-
-       boost::shared_ptr<IO> input = _route->input ();
-
-       if (input) {
-               uint32_t n = 0;
-               vector<string> connections;
-               boost::shared_ptr<ChannelList> c = channels.reader();
-
-               for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) {
-
-                       if ((input->nth (n).get()) && (input->nth (n)->get_connections (connections) == 0)) {
-                               if (AudioEngine::instance()->port_is_physical (connections[0])) {
-                                       have_physical = true;
-                                       break;
-                               }
-                       }
-
-                       connections.clear ();
-               }
-       }
-
-#ifdef MIXBUS
-       // compensate for latency when bouncing from master or mixbus.
-       // we need to use "ExistingMaterial" to pick up the master bus' latency
-       // see also Route::direct_feeds_according_to_reality
-       IOVector ios;
-       ios.push_back (_io);
-       if (_session.master_out() && ios.fed_by (_session.master_out()->output())) {
-               have_physical = true;
-       }
-       for (uint32_t n = 0; n < NUM_MIXBUSES && !have_physical; ++n) {
-               if (_session.get_mixbus (n) && ios.fed_by (_session.get_mixbus(n)->output())) {
-                       have_physical = true;
-               }
-       }
-#endif
-
-       if (have_physical) {
-               set_align_style (ExistingMaterial);
-       } else {
-               set_align_style (CaptureTime);
-       }
-}
-
-void
-DiskWriter::set_align_choice (AlignChoice a, bool force)
-{
-       if (record_enabled() && _session.actively_recording()) {
-               return;
-       }
-
-       if ((a != _alignment_choice) || force) {
-               _alignment_choice = a;
-
-               switch (_alignment_choice) {
-                       case Automatic:
-                               set_align_style_from_io ();
-                               break;
-                       case UseExistingMaterial:
-                               set_align_style (ExistingMaterial);
-                               break;
-                       case UseCaptureTime:
-                               set_align_style (CaptureTime);
-                               break;
-               }
-       }
-}
-
 XMLNode&
 DiskWriter::state (bool full)
 {
        XMLNode& node (DiskIOProcessor::state (full));
-       node.set_property(X_("type"), X_("diskwriter"));
-       node.set_property (X_("capture-alignment"), enum_2_string (_alignment_choice));
+       node.set_property (X_("type"), X_("diskwriter"));
        node.set_property (X_("record-safe"), (_record_safe ? X_("yes" : "no")));
        return node;
 }
@@ -412,28 +344,21 @@ DiskWriter::state (bool full)
 int
 DiskWriter::set_state (const XMLNode& node, int version)
 {
-       XMLProperty const * prop;
-
        if (DiskIOProcessor::set_state (node, version)) {
                return -1;
        }
-#if 0 // XXX DISK
-       if (!node.property (X_("capture-alignment"))) != 0) {
-                set_align_choice (AlignChoice (string_2_enum (prop->value(), _alignment_choice)), true);
-        } else {
-                set_align_choice (Automatic, true);
-        }
-#endif
 
        if (!node.get_property (X_("record-safe"), _record_safe)) {
                _record_safe = false;
        }
 
+       reset_write_sources (false, true);
+
        return 0;
 }
 
 void
-DiskWriter::non_realtime_locate (framepos_t position)
+DiskWriter::non_realtime_locate (samplepos_t position)
 {
        if (_midi_write_source) {
                _midi_write_source->set_timeline_position (position);
@@ -444,7 +369,7 @@ DiskWriter::non_realtime_locate (framepos_t position)
 
 
 void
-DiskWriter::prepare_record_status(framepos_t capture_start_frame)
+DiskWriter::prepare_record_status(samplepos_t capture_start_sample)
 {
        if (recordable() && destructive()) {
                boost::shared_ptr<ChannelList> c = channels.reader();
@@ -455,7 +380,7 @@ DiskWriter::prepare_record_status(framepos_t capture_start_frame)
 
                        if (transitions.len[0] > 0) {
                                transitions.buf[0]->type = CaptureStart;
-                               transitions.buf[0]->capture_val = capture_start_frame;
+                               transitions.buf[0]->capture_val = capture_start_sample;
                                (*chan)->capture_transition_buf->increment_write_ptr(1);
                        } else {
                                // bad!
@@ -476,21 +401,34 @@ DiskWriter::prepare_record_status(framepos_t capture_start_frame)
  *      that someone can read playback_distance worth of data from.
  */
 void
-DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
+DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
                  double speed, pframes_t nframes, bool result_required)
 {
        uint32_t n;
        boost::shared_ptr<ChannelList> c = channels.reader();
        ChannelList::iterator chan;
-       framecnt_t rec_offset = 0;
-       framecnt_t rec_nframes = 0;
+       samplecnt_t rec_offset = 0;
+       samplecnt_t rec_nframes = 0;
        bool nominally_recording;
        bool re = record_enabled ();
        bool can_record = _session.actively_recording ();
 
+       if (_active) {
+               if (!_pending_active) {
+                       _active = false;
+                       return;
+               }
+       } else {
+               if (_pending_active) {
+                       _active = true;
+               } else {
+                       return;
+               }
+       }
+
        _need_butler = false;
 
-       check_record_status (start_frame, can_record);
+       check_record_status (start_sample, can_record);
 
        if (nframes == 0) {
                return;
@@ -499,16 +437,16 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
        nominally_recording = (can_record && re);
 
        // Safeguard against situations where process() goes haywire when autopunching
-       // and last_recordable_frame < first_recordable_frame
+       // and last_recordable_sample < first_recordable_sample
 
-       if (last_recordable_frame < first_recordable_frame) {
-               last_recordable_frame = max_framepos;
+       if (last_recordable_sample < first_recordable_sample) {
+               last_recordable_sample = max_samplepos;
        }
 
        const Location* const loop_loc    = loop_location;
-       framepos_t            loop_start  = 0;
-       framepos_t            loop_end    = 0;
-       framepos_t            loop_length = 0;
+       samplepos_t            loop_start  = 0;
+       samplepos_t            loop_end    = 0;
+       samplepos_t            loop_length = 0;
 
        if (loop_loc) {
                get_location_times (loop_loc, &loop_start, &loop_end, &loop_length);
@@ -518,12 +456,12 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
 
        if (nominally_recording || (re && was_recording && _session.get_record_enabled() && (_session.config.get_punch_in() || _session.preroll_record_punch_enabled()))) {
 
-               Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, start_frame, end_frame);
-               // 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, start_frame, nframes, rec_nframes, rec_offset);
+               Evoral::OverlapType ot = Evoral::coverage (first_recordable_sample, last_recordable_sample, start_sample, end_sample);
+               // XXX should this be transport_sample + nframes - 1 ? coverage() expects its parameter ranges to include their end points
+               // XXX also, first_recordable_sample & last_recordable_sample may both be == max_samplepos: coverage() will return OverlapNone in that case. Is thak OK?
+               calculate_record_range (ot, start_sample, nframes, rec_nframes, rec_offset);
 
-               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: this time record %2 of %3 frames, offset %4\n", _name, rec_nframes, nframes, rec_offset));
+               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: this time record %2 of %3 samples, offset %4\n", _name, rec_nframes, nframes, rec_offset));
 
                if (rec_nframes && !was_recording) {
                        capture_captured = 0;
@@ -534,22 +472,22 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                                   at the loop start and can handle time wrapping around.
                                   Otherwise, start the source right now as usual.
                                */
-                               capture_captured    = start_frame - loop_start;
-                               capture_start_frame = loop_start;
+                               capture_captured    = start_sample - loop_start;
+                               capture_start_sample = loop_start;
                        }
 
                        if (_midi_write_source) {
-                               _midi_write_source->mark_write_starting_now (capture_start_frame, capture_captured, loop_length);
+                               _midi_write_source->mark_write_starting_now (capture_start_sample, capture_captured, loop_length);
                        }
 
-                       g_atomic_int_set(const_cast<gint*> (&_frames_pending_write), 0);
+                       g_atomic_int_set(const_cast<gint*> (&_samples_pending_write), 0);
                        g_atomic_int_set(const_cast<gint*> (&_num_captured_loops), 0);
 
                        was_recording = true;
 
                }
 
-               /* For audio: not writing frames to the capture ringbuffer offsets
+               /* For audio: not writing samples to the capture ringbuffer offsets
                 * the recording. For midi: we need to keep track of the record range
                 * and subtract the accumulated difference from the event time.
                 */
@@ -571,21 +509,21 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
 
                const size_t n_buffers = bufs.count().n_audio();
 
-               for (n = 0; chan != c->end(); ++chan, ++n) {
+               for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
 
                        ChannelInfo* chaninfo (*chan);
                        AudioBuffer& buf (bufs.get_audio (n%n_buffers));
 
                        chaninfo->buf->get_write_vector (&chaninfo->rw_vector);
 
-                       if (rec_nframes <= (framecnt_t) chaninfo->rw_vector.len[0]) {
+                       if (rec_nframes <= (samplecnt_t) chaninfo->rw_vector.len[0]) {
 
                                Sample *incoming = buf.data (rec_offset);
                                memcpy (chaninfo->rw_vector.buf[0], incoming, sizeof (Sample) * rec_nframes);
 
                        } else {
 
-                               framecnt_t total = chaninfo->rw_vector.len[0] + chaninfo->rw_vector.len[1];
+                               samplecnt_t total = chaninfo->rw_vector.len[0] + chaninfo->rw_vector.len[1];
 
                                if (rec_nframes > total) {
                                         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 overrun in %2, rec_nframes = %3 total space = %4\n",
@@ -595,7 +533,7 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                                }
 
                                Sample *incoming = buf.data (rec_offset);
-                               framecnt_t first = chaninfo->rw_vector.len[0];
+                               samplecnt_t first = chaninfo->rw_vector.len[0];
 
                                memcpy (chaninfo->rw_vector.buf[0], incoming, sizeof (Sample) * first);
                                memcpy (chaninfo->rw_vector.buf[1], incoming + first, sizeof (Sample) * (rec_nframes - first));
@@ -621,7 +559,7 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                        if (DEBUG_ENABLED(DEBUG::MidiIO)) {
                                const uint8_t* __data = ev.buffer();
                                DEBUG_STR_DECL(a);
-                               DEBUG_STR_APPEND(a, string_compose ("mididiskstream %1 capture event @ %2 + %3 sz %4 ", this, ev.time(), start_frame, ev.size()));
+                               DEBUG_STR_APPEND(a, string_compose ("mididiskstream %1 capture event @ %2 + %3 sz %4 ", this, ev.time(), start_sample, ev.size()));
                                for (size_t i=0; i < ev.size(); ++i) {
                                        DEBUG_STR_APPEND(a,hex);
                                        DEBUG_STR_APPEND(a,"0x");
@@ -632,7 +570,7 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                                DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
                        }
 #endif
-                       /* Write events to the capture buffer in frames from session start,
+                       /* Write events to the capture buffer in samples from session start,
                           but ignoring looping so event time progresses monotonically.
                           The source knows the loop length so it knows exactly where the
                           event occurs in the series of recorded loops and can implement
@@ -641,9 +579,9 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                           reconstruct their actual time; future clever MIDI looping should
                           probably be implemented in the source instead of here.
                        */
-                       const framecnt_t loop_offset = _num_captured_loops * loop_length;
-                       const framepos_t event_time = start_frame + loop_offset - _accumulated_capture_offset + ev.time();
-                       if (event_time < 0 || event_time < first_recordable_frame) {
+                       const samplecnt_t loop_offset = _num_captured_loops * loop_length;
+                       const samplepos_t event_time = start_sample + loop_offset - _accumulated_capture_offset + ev.time();
+                       if (event_time < 0 || event_time < first_recordable_sample) {
                                /* Event out of range, skip */
                                continue;
                        }
@@ -652,7 +590,7 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                                _midi_buf->write (event_time, ev.event_type(), ev.size(), ev.buffer());
                        }
                }
-               g_atomic_int_add(const_cast<gint*>(&_frames_pending_write), nframes);
+               g_atomic_int_add(const_cast<gint*>(&_samples_pending_write), nframes);
 
                if (buf.size() != 0) {
                        Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex, Glib::Threads::TRY_LOCK);
@@ -667,7 +605,7 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                                        /* This may fail if buf is larger than _gui_feed_buffer, but it's not really
                                           the end of the world if it does.
                                        */
-                                       _gui_feed_buffer.push_back ((*i).time() + start_frame, (*i).size(), (*i).buffer());
+                                       _gui_feed_buffer.push_back ((*i).time() + start_sample, (*i).size(), (*i).buffer());
                                }
                        }
 
@@ -690,7 +628,7 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
        /* AUDIO BUTLER REQUIRED CODE */
 
        if (_playlists[DataType::AUDIO] && !c->empty()) {
-               if (((framecnt_t) c->front()->buf->read_space() >= _chunk_frames)) {
+               if (((samplecnt_t) c->front()->buf->read_space() >= _chunk_samples)) {
                        _need_butler = true;
                }
        }
@@ -701,15 +639,15 @@ DiskWriter::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
                _need_butler = true;
        }
 
-       DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 writer run, needs butler = %2\n", name(), _need_butler));
+       // DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 writer run, needs butler = %2\n", name(), _need_butler));
 }
 
 void
 DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c)
 {
        was_recording = false;
-       first_recordable_frame = max_framepos;
-       last_recordable_frame = max_framepos;
+       first_recordable_sample = max_samplepos;
+       last_recordable_sample = max_samplepos;
 
        if (capture_captured == 0) {
                return;
@@ -736,8 +674,10 @@ DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c)
 
        CaptureInfo* ci = new CaptureInfo;
 
-       ci->start =  capture_start_frame;
-       ci->frames = capture_captured;
+       ci->start =  capture_start_sample;
+       ci->samples = capture_captured;
+
+       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("Finish capture, add new CI, %1 + %2\n", ci->start, ci->samples));
 
        /* XXX theoretical race condition here. Need atomic exchange ?
           However, the circumstances when this is called right
@@ -748,13 +688,11 @@ DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c)
           accessors, so that invalidation will not occur (both non-realtime).
        */
 
-       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;
 
-       /* now we've finished a capture, reset first_recordable_frame for next time */
-       first_recordable_frame = max_framepos;
+       /* now we've finished a capture, reset first_recordable_sample for next time */
+       first_recordable_sample = max_samplepos;
 }
 
 void
@@ -766,7 +704,7 @@ DiskWriter::set_record_enabled (bool yn)
 
        /* can't rec-enable in destructive mode if transport is before start */
 
-       if (destructive() && yn && _session.transport_frame() < _session.current_start_frame()) {
+       if (destructive() && yn && _session.transport_sample() < _session.current_start_sample()) {
                return;
        }
 
@@ -795,7 +733,7 @@ DiskWriter::set_record_safe (bool yn)
        /* can't rec-safe in destructive mode if transport is before start ????
         REQUIRES REVIEW */
 
-       if (destructive() && yn && _session.transport_frame() < _session.current_start_frame()) {
+       if (destructive() && yn && _session.transport_sample() < _session.current_start_sample()) {
                return;
        }
 
@@ -823,7 +761,7 @@ DiskWriter::prep_record_enable ()
 
        /* can't rec-enable in destructive mode if transport is before start */
 
-       if (destructive() && _session.transport_frame() < _session.current_start_frame()) {
+       if (destructive() && _session.transport_sample() < _session.current_start_sample()) {
                return false;
        }
 
@@ -876,7 +814,7 @@ DiskWriter::set_note_mode (NoteMode m)
 }
 
 int
-DiskWriter::seek (framepos_t frame, bool complete_refill)
+DiskWriter::seek (samplepos_t sample, bool complete_refill)
 {
        uint32_t n;
        ChannelList::iterator chan;
@@ -887,17 +825,16 @@ DiskWriter::seek (framepos_t frame, bool complete_refill)
        }
 
        _midi_buf->reset ();
-       g_atomic_int_set(&_frames_read_from_ringbuffer, 0);
-       g_atomic_int_set(&_frames_written_to_ringbuffer, 0);
+       g_atomic_int_set(&_samples_read_from_ringbuffer, 0);
+       g_atomic_int_set(&_samples_written_to_ringbuffer, 0);
 
        /* can't rec-enable in destructive mode if transport is before start */
 
-       if (destructive() && record_enabled() && frame < _session.current_start_frame()) {
+       if (destructive() && record_enabled() && sample < _session.current_start_sample()) {
                disengage_record_enable ();
        }
 
-       playback_sample = frame;
-       file_frame = frame;
+       playback_sample = sample;
 
        return 0;
 }
@@ -909,7 +846,7 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush)
        int32_t ret = 0;
        RingBufferNPT<Sample>::rw_vector vector;
        RingBufferNPT<CaptureTransition>::rw_vector transvec;
-       framecnt_t total;
+       samplecnt_t total;
 
        transvec.buf[0] = 0;
        transvec.buf[1] = 0;
@@ -923,7 +860,7 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush)
 
                total = vector.len[0] + vector.len[1];
 
-               if (total == 0 || (total < _chunk_frames && !force_flush && was_recording)) {
+               if (total == 0 || (total < _chunk_samples && !force_flush && was_recording)) {
                        goto out;
                }
 
@@ -938,11 +875,11 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush)
                   let the caller know too.
                */
 
-               if (total >= 2 * _chunk_frames || ((force_flush || !was_recording) && total > _chunk_frames)) {
+               if (total >= 2 * _chunk_samples || ((force_flush || !was_recording) && total > _chunk_samples)) {
                        ret = 1;
                }
 
-               to_write = min (_chunk_frames, (framecnt_t) vector.len[0]);
+               to_write = min (_chunk_samples, (samplecnt_t) vector.len[0]);
 
                // check the transition buffer when recording destructive
                // important that we get this after the capture buf
@@ -963,7 +900,7 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush)
 
                                } else if (captrans.type == CaptureEnd) {
 
-                                       // capture end, the capture_val represents total frames in capture
+                                       // capture end, the capture_val represents total samples in capture
 
                                        if (captrans.capture_val <= (*chan)->curr_capture_cnt + to_write) {
 
@@ -1002,14 +939,14 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush)
                (*chan)->buf->increment_read_ptr (to_write);
                (*chan)->curr_capture_cnt += to_write;
 
-               if ((to_write == vector.len[0]) && (total > to_write) && (to_write < _chunk_frames) && !destructive()) {
+               if ((to_write == vector.len[0]) && (total > to_write) && (to_write < _chunk_samples) && !destructive()) {
 
                        /* we wrote all of vector.len[0] but it wasn't an entire
-                          disk_write_chunk_frames of data, so arrange for some part
+                          disk_write_chunk_samples of data, so arrange for some part
                           of vector.len[1] to be flushed to disk as well.
                        */
 
-                       to_write = min ((framecnt_t)(_chunk_frames - to_write), (framecnt_t) vector.len[1]);
+                       to_write = min ((samplecnt_t)(_chunk_samples - to_write), (samplecnt_t) vector.len[1]);
 
                         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 additional write of %2\n", name(), to_write));
 
@@ -1025,6 +962,48 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush)
 
        /* MIDI*/
 
+       if (_midi_write_source) {
+
+               const samplecnt_t total = g_atomic_int_get(const_cast<gint*> (&_samples_pending_write));
+
+               if (total == 0 ||
+                   _midi_buf->read_space() == 0 ||
+                   (!force_flush && (total < _chunk_samples) && was_recording)) {
+                       goto out;
+               }
+
+               /* 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 we are forcing a flush, then if there is* any* extra
+                  work, let the caller know.
+
+                  if we are no longer recording and there is any extra work,
+                  let the caller know too.
+               */
+
+               if (total >= 2 * _chunk_samples || ((force_flush || !was_recording) && total > _chunk_samples)) {
+                       ret = 1;
+               }
+
+               if (force_flush) {
+                       /* push out everything we have, right now */
+                       to_write = UINT32_MAX;
+               } else {
+                       to_write = _chunk_samples;
+               }
+
+               if (record_enabled() && ((total > _chunk_samples) || force_flush)) {
+                       Source::Lock lm(_midi_write_source->mutex());
+                       if (_midi_write_source->midi_write (lm, *_midi_buf, get_capture_start_sample (0), to_write) != to_write) {
+                               error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
+                               return -1;
+                       }
+                       g_atomic_int_add(const_cast<gint*> (&_samples_pending_write), -to_write);
+               }
+       }
+
   out:
        return ret;
 
@@ -1082,18 +1061,20 @@ DiskWriter::reset_write_sources (bool mark_write_complete, bool /*force*/)
                        Source::Lock lm(_midi_write_source->mutex());
                        _midi_write_source->mark_streaming_write_completed (lm);
                }
+       }
 
+       if (_playlists[DataType::MIDI]) {
                use_new_write_source (DataType::MIDI);
+       }
 
-               if (destructive() && !c->empty ()) {
+       if (destructive() && !c->empty ()) {
 
-                       /* we now have all our write sources set up, so create the
-                          playlist's single region.
-                       */
+               /* we now have all our write sources set up, so create the
+                  playlist's single region.
+               */
 
-                       if (_playlists[DataType::MIDI]->empty()) {
-                               setup_destructive_playlist ();
-                       }
+               if (_playlists[DataType::MIDI]->empty()) {
+                       setup_destructive_playlist ();
                }
        }
 }
@@ -1158,13 +1139,11 @@ DiskWriter::use_new_write_source (DataType dt, uint32_t n)
 void
 DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abort_capture)
 {
-       uint32_t buffer_position;
        bool more_work = true;
        int err = 0;
-       boost::shared_ptr<AudioRegion> region;
-       framecnt_t total_capture;
-       SourceList srcs;
-       SourceList::iterator src;
+       samplecnt_t total_capture;
+       SourceList audio_srcs;
+       SourceList midi_srcs;
        ChannelList::iterator chan;
        vector<CaptureInfo*>::iterator ci;
        boost::shared_ptr<ChannelList> c = channels.reader();
@@ -1173,7 +1152,6 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
 
        finish_capture (c);
 
-       boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> (_playlists[DataType::AUDIO]);
 
        /* butler is already stopped, but there may be work to do
           to flush remaining data to disk.
@@ -1217,128 +1195,93 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
                        /* new source set up in "out" below */
                }
 
+               if (_midi_write_source) {
+                       _midi_write_source->mark_for_remove ();
+                       _midi_write_source->drop_references ();
+                       _midi_write_source.reset();
+               }
+
                goto out;
        }
 
        for (total_capture = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
-               total_capture += (*ci)->frames;
+               total_capture += (*ci)->samples;
        }
 
        /* figure out the name for this take */
 
        for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
-               boost::shared_ptr<AudioFileSource> s = (*chan)->write_source;
+               boost::shared_ptr<AudioFileSource> as = (*chan)->write_source;
 
-               if (s) {
-                       srcs.push_back (s);
-                       s->update_header (capture_info.front()->start, when, twhen);
-                       s->set_captured_for (_name.val());
-                       s->mark_immutable ();
+               if (as) {
+                       audio_srcs.push_back (as);
+                       as->update_header (capture_info.front()->start, when, twhen);
+                       as->set_captured_for (_name.val());
+                       as->mark_immutable ();
 
                        if (Config->get_auto_analyse_audio()) {
-                               Analyser::queue_source_for_analysis (s, true);
+                               Analyser::queue_source_for_analysis (as, true);
                        }
 
-                       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", s->path(), s->length (0)));
+                       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", as->path(), as->length (0)));
                }
-       }
 
-       if (!pl) {
-               goto midi;
+               if (_midi_write_source) {
+                       midi_srcs.push_back (_midi_write_source);
+               }
        }
 
-       /* destructive tracks have a single, never changing region */
-
-       if (destructive()) {
 
-               /* send a signal that any UI can pick up to do the right thing. there is
-                  a small problem here in that a UI may need the peak data to be ready
-                  for the data that was recorded and this isn't interlocked with that
-                  process. this problem is deferred to the UI.
-                */
-
-               pl->LayeringChanged(); // XXX this may not get the UI to do the right thing
-
-       } else {
+       /* MIDI */
 
-               string whole_file_region_name;
-               whole_file_region_name = region_name_from_path (c->front()->write_source->name(), true);
-
-               /* Register a new region with the Session that
-                  describes the entire source. Do this first
-                  so that any sub-regions will obviously be
-                  children of this one (later!)
-               */
-
-               try {
-                       PropertyList plist;
-
-                       plist.add (Properties::start, c->front()->write_source->last_capture_start_frame());
-                       plist.add (Properties::length, total_capture);
-                       plist.add (Properties::name, whole_file_region_name);
-                       boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
-                       rx->set_automatic (true);
-                       rx->set_whole_file (true);
-
-                       region = boost::dynamic_pointer_cast<AudioRegion> (rx);
-                       region->special_set_position (capture_info.front()->start);
-               }
+       if (_midi_write_source) {
 
+               if (_midi_write_source->length (capture_info.front()->start) == 0) {
+                       /* No data was recorded, so this capture will
+                          effectively be aborted; do the same as we
+                          do for an explicit abort.
+                       */
+                       if (_midi_write_source) {
+                               _midi_write_source->mark_for_remove ();
+                               _midi_write_source->drop_references ();
+                               _midi_write_source.reset();
+                       }
 
-               catch (failed_constructor& err) {
-                       error << string_compose(_("%1: could not create region for complete audio file"), _name) << endmsg;
-                       /* XXX what now? */
+                       goto out;
                }
 
-               _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
-
-               pl->clear_changes ();
-               pl->set_capture_insertion_in_progress (true);
-               pl->freeze ();
+               /* phew, we have data */
 
-               const framepos_t preroll_off = _session.preroll_record_trim_len ();
-               for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+               Source::Lock source_lock(_midi_write_source->mutex());
 
-                       string region_name;
+               /* figure out the name for this take */
 
-                       RegionFactory::region_name (region_name, whole_file_region_name, false);
+               midi_srcs.push_back (_midi_write_source);
 
-                       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));
+               _midi_write_source->set_timeline_position (capture_info.front()->start);
+               _midi_write_source->set_captured_for (_name);
 
-                       try {
+               /* set length in beats to entire capture length */
 
-                               PropertyList plist;
+               BeatsSamplesConverter converter (_session.tempo_map(), capture_info.front()->start);
+               const Temporal::Beats total_capture_beats = converter.from (total_capture);
+               _midi_write_source->set_length_beats (total_capture_beats);
 
-                               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);
-                               if (preroll_off > 0) {
-                                       region->trim_front (buffer_position + preroll_off);
-                               }
-                       }
-
-                       catch (failed_constructor& err) {
-                               error << _("AudioDiskstream: could not create region for captured audio!") << endmsg;
-                               continue; /* XXX is this OK? */
-                       }
+               /* flush to disk: this step differs from the audio path,
+                  where all the data is already on disk.
+               */
 
-                       i_am_the_modifier++;
+               _midi_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Temporal::Beats>::ResolveStuckNotes, total_capture_beats);
+       }
 
-                       pl->add_region (region, (*ci)->start + preroll_off, 1, non_layered());
-                       pl->set_layer (region, DBL_MAX);
-                       i_am_the_modifier--;
+       _last_capture_sources.insert (_last_capture_sources.end(), audio_srcs.begin(), audio_srcs.end());
+       _last_capture_sources.insert (_last_capture_sources.end(), midi_srcs.begin(), midi_srcs.end());
 
-                       buffer_position += (*ci)->frames;
-               }
 
-               pl->thaw ();
-               pl->set_capture_insertion_in_progress (false);
-               _session.add_command (new StatefulDiffCommand (pl));
+       if (_route) {
+               _route->use_captured_sources (audio_srcs, capture_info);
+               _route->use_captured_sources (midi_srcs, capture_info);
        }
 
        mark_write_completed = true;
@@ -1353,218 +1296,11 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
        }
 
        capture_info.clear ();
-       capture_start_frame = 0;
-
-  midi:
-       return;
+       capture_start_sample = 0;
 }
 
-#if 0 // MIDI PART
 void
-DiskWriter::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen*/, bool abort_capture)
-{
-       bool more_work = true;
-       int err = 0;
-       boost::shared_ptr<MidiRegion> region;
-       MidiRegion::SourceList srcs;
-       MidiRegion::SourceList::iterator src;
-       vector<CaptureInfo*>::iterator ci;
-
-       finish_capture ();
-
-       /* butler is already stopped, but there may be work to do
-          to flush remaining data to disk.
-          */
-
-       while (more_work && !err) {
-               switch (do_flush (TransportContext, true)) {
-               case 0:
-                       more_work = false;
-                       break;
-               case 1:
-                       break;
-               case -1:
-                       error << string_compose(_("MidiDiskstream \"%1\": cannot flush captured data to disk!"), _name) << endmsg;
-                       err++;
-               }
-       }
-
-       /* XXX is there anything we can do if err != 0 ? */
-       Glib::Threads::Mutex::Lock lm (capture_info_lock);
-
-       if (capture_info.empty()) {
-               goto no_capture_stuff_to_do;
-       }
-
-       if (abort_capture) {
-
-               if (_write_source) {
-                       _write_source->mark_for_remove ();
-                       _write_source->drop_references ();
-                       _write_source.reset();
-               }
-
-               /* new source set up in "out" below */
-
-       } else {
-
-               framecnt_t total_capture = 0;
-               for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
-                       total_capture += (*ci)->frames;
-               }
-
-               if (_write_source->length (capture_info.front()->start) != 0) {
-
-                       /* phew, we have data */
-
-                       Source::Lock source_lock(_write_source->mutex());
-
-                       /* figure out the name for this take */
-
-                       srcs.push_back (_write_source);
-
-                       _write_source->set_timeline_position (capture_info.front()->start);
-                       _write_source->set_captured_for (_name);
-
-                       /* set length in beats to entire capture length */
-
-                       BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start);
-                       const Evoral::Beats total_capture_beats = converter.from (total_capture);
-                       _write_source->set_length_beats (total_capture_beats);
-
-                       /* flush to disk: this step differs from the audio path,
-                          where all the data is already on disk.
-                       */
-
-                       _write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, total_capture_beats);
-
-                       /* we will want to be able to keep (over)writing the source
-                          but we don't want it to be removable. this also differs
-                          from the audio situation, where the source at this point
-                          must be considered immutable. luckily, we can rely on
-                          MidiSource::mark_streaming_write_completed() to have
-                          already done the necessary work for that.
-                       */
-
-                       string whole_file_region_name;
-                       whole_file_region_name = region_name_from_path (_write_source->name(), true);
-
-                       /* Register a new region with the Session that
-                          describes the entire source. Do this first
-                          so that any sub-regions will obviously be
-                          children of this one (later!)
-                       */
-
-                       try {
-                               PropertyList plist;
-
-                               plist.add (Properties::name, whole_file_region_name);
-                               plist.add (Properties::whole_file, true);
-                               plist.add (Properties::automatic, true);
-                               plist.add (Properties::start, 0);
-                               plist.add (Properties::length, total_capture);
-                               plist.add (Properties::layer, 0);
-
-                               boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
-
-                               region = boost::dynamic_pointer_cast<MidiRegion> (rx);
-                               region->special_set_position (capture_info.front()->start);
-                       }
-
-
-                       catch (failed_constructor& err) {
-                               error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg;
-                               /* XXX what now? */
-                       }
-
-                       _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end());
-
-                       _playlist->clear_changes ();
-                       _playlist->freeze ();
-
-                       /* Session frame time of the initial capture in this pass, which is where the source starts */
-                       framepos_t initial_capture = 0;
-                       if (!capture_info.empty()) {
-                               initial_capture = capture_info.front()->start;
-                       }
-
-                       const framepos_t preroll_off = _session.preroll_record_trim_len ();
-                       for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
-
-                               string region_name;
-
-                               RegionFactory::region_name (region_name, _write_source->name(), false);
-
-                               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n",
-                                                       _name, (*ci)->start, (*ci)->frames, region_name));
-
-
-                               // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
-
-                               try {
-                                       PropertyList plist;
-
-                                       /* start of this region is the offset between the start of its capture and the start of the whole pass */
-                                       plist.add (Properties::start, (*ci)->start - initial_capture);
-                                       plist.add (Properties::length, (*ci)->frames);
-                                       plist.add (Properties::length_beats, converter.from((*ci)->frames).to_double());
-                                       plist.add (Properties::name, region_name);
-
-                                       boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist));
-                                       region = boost::dynamic_pointer_cast<MidiRegion> (rx);
-                                       if (preroll_off > 0) {
-                                               region->trim_front ((*ci)->start - initial_capture + preroll_off);
-                                       }
-                               }
-
-                               catch (failed_constructor& err) {
-                                       error << _("MidiDiskstream: could not create region for captured midi!") << endmsg;
-                                       continue; /* XXX is this OK? */
-                               }
-
-                               // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
-
-                               i_am_the_modifier++;
-                               _playlist->add_region (region, (*ci)->start + preroll_off);
-                               i_am_the_modifier--;
-                       }
-
-                       _playlist->thaw ();
-                       _session.add_command (new StatefulDiffCommand(_playlist));
-
-               } else {
-
-                       /* No data was recorded, so this capture will
-                          effectively be aborted; do the same as we
-                          do for an explicit abort.
-                       */
-
-                       if (_write_source) {
-                               _write_source->mark_for_remove ();
-                               _write_source->drop_references ();
-                               _write_source.reset();
-                       }
-               }
-
-       }
-
-       use_new_write_source (0);
-
-       for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
-               delete *ci;
-       }
-
-       capture_info.clear ();
-       capture_start_frame = 0;
-
-  no_capture_stuff_to_do:
-
-       reset_tracker ();
-}
-#endif
-
-void
-DiskWriter::transport_looped (framepos_t transport_frame)
+DiskWriter::transport_looped (samplepos_t transport_sample)
 {
        if (was_recording) {
                // all we need to do is finish this capture, with modified capture length
@@ -1575,9 +1311,9 @@ DiskWriter::transport_looped (framepos_t transport_frame)
                // 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_framepos;
+               capture_start_sample = transport_sample;
+               first_recordable_sample = transport_sample; // mild lie
+               last_recordable_sample = max_samplepos;
                was_recording = true;
 
                if (recordable() && destructive()) {
@@ -1588,7 +1324,7 @@ DiskWriter::transport_looped (framepos_t transport_frame)
 
                                if (transvec.len[0] > 0) {
                                        transvec.buf[0]->type = CaptureStart;
-                                       transvec.buf[0]->capture_val = capture_start_frame;
+                                       transvec.buf[0]->capture_val = capture_start_sample;
                                        (*chan)->capture_transition_buf->increment_write_ptr(1);
                                }
                                else {
@@ -1630,7 +1366,7 @@ DiskWriter::setup_destructive_playlist ()
        PropertyList plist;
        plist.add (Properties::name, _name.val());
        plist.add (Properties::start, 0);
-       plist.add (Properties::length, max_framepos - srcs.front()->natural_position());
+       plist.add (Properties::length, max_samplepos - srcs.front()->natural_position());
 
        boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist));
        _playlists[DataType::AUDIO]->add_region (region, srcs.front()->natural_position());
@@ -1671,7 +1407,7 @@ DiskWriter::use_destructive_playlist ()
 
        /* be sure to stretch the region out to the maximum length (non-musical)*/
 
-       region->set_length (max_framepos - region->position(), 0);
+       region->set_length (max_samplepos - region->position(), 0);
 
        uint32_t n;
        ChannelList::iterator chan;
@@ -1710,3 +1446,57 @@ DiskWriter::realtime_handle_transport_stopped ()
 {
        realtime_speed_change ();
 }
+
+bool
+DiskWriter::set_name (string const & str)
+{
+       string my_name = X_("recorder:");
+       my_name += str;
+
+       if (_name != my_name) {
+               SessionObject::set_name (my_name);
+       }
+
+       return true;
+}
+
+std::string
+DiskWriter::steal_write_source_name ()
+{
+       if (_playlists[DataType::MIDI]) {
+               string our_old_name = _midi_write_source->name();
+
+               /* this will bump the name of the current write source to the next one
+                * (e.g. "MIDI 1-1" gets renamed to "MIDI 1-2"), thus leaving the
+                * current write source name (e.g. "MIDI 1-1" available). See the
+                * comments in Session::create_midi_source_by_stealing_name() about why
+                * we do this.
+                */
+
+               try {
+                       string new_path = _session.new_midi_source_path (name());
+
+                       if (_midi_write_source->rename (new_path)) {
+                               return string();
+                       }
+               } catch (...) {
+                       return string ();
+               }
+
+               return our_old_name;
+       }
+
+       return std::string();
+}
+
+bool
+DiskWriter::configure_io (ChanCount in, ChanCount out)
+{
+       if (!DiskIOProcessor::configure_io (in, out)) {
+               return false;
+       }
+
+       reset_write_sources (false, true);
+
+       return true;
+}