remove cruft
[ardour.git] / libs / ardour / disk_writer.cc
1 /*
2     Copyright (C) 2009-2016 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "ardour/analyser.h"
21 #include "ardour/audioengine.h"
22 #include "ardour/audiofilesource.h"
23 #include "ardour/audio_buffer.h"
24 #include "ardour/audioplaylist.h"
25 #include "ardour/audioregion.h"
26 #include "ardour/butler.h"
27 #include "ardour/debug.h"
28 #include "ardour/disk_writer.h"
29 #include "ardour/midi_playlist.h"
30 #include "ardour/midi_source.h"
31 #include "ardour/midi_track.h"
32 #include "ardour/port.h"
33 #include "ardour/region_factory.h"
34 #include "ardour/session.h"
35 #include "ardour/smf_source.h"
36
37 #include "pbd/i18n.h"
38
39 using namespace ARDOUR;
40 using namespace PBD;
41 using namespace std;
42
43 ARDOUR::samplecnt_t DiskWriter::_chunk_samples = DiskWriter::default_chunk_samples ();
44 PBD::Signal0<void> DiskWriter::Overrun;
45
46 DiskWriter::DiskWriter (Session& s, string const & str, DiskIOProcessor::Flag f)
47         : DiskIOProcessor (s, str, f)
48         , _record_enabled (0)
49         , _record_safe (0)
50         , capture_start_sample (0)
51         , capture_captured (0)
52         , was_recording (false)
53         , first_recordable_sample (max_samplepos)
54         , last_recordable_sample (max_samplepos)
55         , last_possibly_recording (0)
56         , _alignment_style (ExistingMaterial)
57         , _num_captured_loops (0)
58         , _accumulated_capture_offset (0)
59         , _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
60 {
61         DiskIOProcessor::init ();
62 }
63
64 DiskWriter::~DiskWriter ()
65 {
66         DEBUG_TRACE (DEBUG::Destruction, string_compose ("DiskWriter %1 @ %2 deleted\n", _name, this));
67
68         boost::shared_ptr<ChannelList> c = channels.reader();
69
70         for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
71                 (*chan)->write_source.reset ();
72         }
73 }
74
75 samplecnt_t
76 DiskWriter::default_chunk_samples ()
77 {
78         return 65536;
79 }
80
81 bool
82 DiskWriter::set_write_source_name (string const & str)
83 {
84         _write_source_name = str;
85         return true;
86 }
87
88 void
89 DiskWriter::check_record_status (samplepos_t transport_sample, double speed, bool can_record)
90 {
91         int possibly_recording;
92         int rolling;
93         int change;
94         const int transport_rolling = 0x4;
95         const int track_rec_enabled = 0x2;
96         const int global_rec_enabled = 0x1;
97         const int fully_rec_enabled = (transport_rolling|track_rec_enabled|global_rec_enabled);
98
99         /* merge together the 3 factors that affect record status, and compute what has changed. */
100
101         rolling = speed != 0.0f;
102         possibly_recording = (rolling << 2) | ((int)record_enabled() << 1) | (int)can_record;
103         change = possibly_recording ^ last_possibly_recording;
104
105         if (possibly_recording == last_possibly_recording) {
106                 return;
107         }
108
109         if (possibly_recording == fully_rec_enabled) {
110
111                 if (last_possibly_recording == fully_rec_enabled) {
112                         return;
113                 }
114
115                 capture_start_sample = _session.transport_sample ();
116                 first_recordable_sample = capture_start_sample;
117
118                 if (_alignment_style == ExistingMaterial) {
119                         first_recordable_sample += _capture_offset + _playback_offset;
120                 }
121
122                 last_recordable_sample = max_samplepos;
123
124                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %2 (STS: %3) CS:%4 FRS: %5 IL: %7, OL: %8 CO: %r9 PO: %10 WOL: %11 WIL: %12\n",
125                                                                       name(),
126                                                                       transport_sample,
127                                                                       _session.transport_sample(),
128                                                                                                                                                                                                                                         capture_start_sample,
129                                                                                                                                                                                                                                         first_recordable_sample,
130                                                                                                                                                                                                                                         last_recordable_sample,
131                                                                       _input_latency,
132                                                                       _output_latency,
133                                                                       _capture_offset,
134                                                                       _playback_offset,
135                                                                       _session.worst_output_latency(),
136                                                                       _session.worst_input_latency()));
137
138
139                 prepare_record_status (capture_start_sample);
140
141         } else {
142
143                 if (last_possibly_recording == fully_rec_enabled) {
144
145                         /* we were recording last time */
146
147                         if (change & transport_rolling) {
148
149                                 /* transport-change (stopped rolling): last_recordable_sample was set in ::prepare_to_stop(). We
150                                  * had to set it there because we likely rolled past the stopping point to declick out,
151                                  * and then backed up.
152                                  */
153
154                         } else {
155                                 /* punch out */
156
157                                 last_recordable_sample = _session.transport_sample();
158
159                                 if (_alignment_style == ExistingMaterial) {
160                                         //XXX
161                                 }
162                         }
163                 }
164         }
165
166         last_possibly_recording = possibly_recording;
167 }
168
169 void
170 DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transport_sample, samplecnt_t nframes, samplecnt_t & rec_nframes, samplecnt_t & rec_offset)
171 {
172         switch (ot) {
173         case Evoral::OverlapNone:
174                 rec_nframes = 0;
175                 break;
176
177         case Evoral::OverlapInternal:
178                 /*     ----------    recrange
179                  *       |---|       transrange
180                  */
181                 rec_nframes = nframes;
182                 rec_offset = 0;
183                 break;
184
185         case Evoral::OverlapStart:
186                 /*    |--------|    recrange
187                  *  -----|          transrange
188                  */
189                 rec_nframes = transport_sample + nframes - first_recordable_sample;
190                 if (rec_nframes) {
191                         rec_offset = first_recordable_sample - transport_sample;
192                 }
193                 break;
194
195         case Evoral::OverlapEnd:
196                 /*    |--------|    recrange
197                  *       |--------  transrange
198                  */
199                 rec_nframes = last_recordable_sample - transport_sample;
200                 rec_offset = 0;
201                 break;
202
203         case Evoral::OverlapExternal:
204                 /*    |--------|    recrange
205                  *  --------------  transrange
206                  */
207                 rec_nframes = last_recordable_sample - first_recordable_sample;
208                 rec_offset = first_recordable_sample - transport_sample;
209                 break;
210         }
211
212         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n",
213                                                               _name, enum_2_string (ot), transport_sample, nframes,
214                                                               first_recordable_sample, last_recordable_sample, rec_nframes, rec_offset));
215 }
216
217 void
218 DiskWriter::engage_record_enable ()
219 {
220         g_atomic_int_set (&_record_enabled, 1);
221 }
222
223 void
224 DiskWriter::disengage_record_enable ()
225 {
226         g_atomic_int_set (&_record_enabled, 0);
227 }
228
229 void
230 DiskWriter::engage_record_safe ()
231 {
232         g_atomic_int_set (&_record_safe, 1);
233 }
234
235 void
236 DiskWriter::disengage_record_safe ()
237 {
238         g_atomic_int_set (&_record_safe, 0);
239 }
240
241 /** Get the start position (in session samples) of the nth capture in the current pass */
242 ARDOUR::samplepos_t
243 DiskWriter::get_capture_start_sample (uint32_t n) const
244 {
245         Glib::Threads::Mutex::Lock lm (capture_info_lock);
246
247         if (capture_info.size() > n) {
248                 /* this is a completed capture */
249                 return capture_info[n]->start;
250         } else {
251                 /* this is the currently in-progress capture */
252                 return capture_start_sample;
253         }
254 }
255
256 ARDOUR::samplecnt_t
257 DiskWriter::get_captured_samples (uint32_t n) const
258 {
259         Glib::Threads::Mutex::Lock lm (capture_info_lock);
260
261         if (capture_info.size() > n) {
262                 /* this is a completed capture */
263                 return capture_info[n]->samples;
264         } else {
265                 /* this is the currently in-progress capture */
266                 return capture_captured;
267         }
268 }
269
270 void
271 DiskWriter::set_align_style (AlignStyle a, bool force)
272 {
273         if (record_enabled() && _session.actively_recording()) {
274                 return;
275         }
276
277         if ((a != _alignment_style) || force) {
278                 _alignment_style = a;
279                 AlignmentStyleChanged ();
280         }
281 }
282
283 XMLNode&
284 DiskWriter::state (bool full)
285 {
286         XMLNode& node (DiskIOProcessor::state (full));
287         node.set_property (X_("type"), X_("diskwriter"));
288         node.set_property (X_("record-safe"), (_record_safe ? X_("yes" : "no")));
289         return node;
290 }
291
292 int
293 DiskWriter::set_state (const XMLNode& node, int version)
294 {
295         if (DiskIOProcessor::set_state (node, version)) {
296                 return -1;
297         }
298
299         if (!node.get_property (X_("record-safe"), _record_safe)) {
300                 _record_safe = false;
301         }
302
303         reset_write_sources (false, true);
304
305         return 0;
306 }
307
308 void
309 DiskWriter::non_realtime_locate (samplepos_t position)
310 {
311         if (_midi_write_source) {
312                 _midi_write_source->set_timeline_position (position);
313         }
314
315         DiskIOProcessor::non_realtime_locate (position);
316 }
317
318
319 void
320 DiskWriter::prepare_record_status (samplepos_t capture_start_sample)
321 {
322         if (recordable() && destructive()) {
323                 boost::shared_ptr<ChannelList> c = channels.reader ();
324                 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
325
326                         RingBufferNPT<CaptureTransition>::rw_vector transitions;
327                         (*chan)->capture_transition_buf->get_write_vector (&transitions);
328
329                         if (transitions.len[0] > 0) {
330                                 transitions.buf[0]->type = CaptureStart;
331                                 transitions.buf[0]->capture_val = capture_start_sample;
332                                 (*chan)->capture_transition_buf->increment_write_ptr(1);
333                         } else {
334                                 // bad!
335                                 fatal << X_("programming error: capture_transition_buf is full on rec start!  inconceivable!")
336                                         << endmsg;
337                         }
338                 }
339         }
340 }
341
342
343 /** Do some record stuff [not described in this comment!]
344  *
345  *  Also:
346  *    - Setup playback_distance with the nframes, or nframes adjusted
347  *      for current varispeed, if appropriate.
348  *    - Setup current_playback_buffer in each ChannelInfo to point to data
349  *      that someone can read playback_distance worth of data from.
350  */
351 void
352 DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
353                  double speed, pframes_t nframes, bool result_required)
354 {
355         if (!_active && !_pending_active) {
356                 return;
357         }
358         _active = _pending_active;
359
360         uint32_t n;
361         boost::shared_ptr<ChannelList> c = channels.reader();
362         ChannelList::iterator chan;
363
364         samplecnt_t rec_offset = 0;
365         samplecnt_t rec_nframes = 0;
366         bool nominally_recording;
367
368         bool re = record_enabled ();
369         bool can_record = _session.actively_recording ();
370
371         _need_butler = false;
372
373 #ifndef NDEBUG
374         if (speed != 0 && re) {
375                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: run() start: %2 end: %3 NF: %4\n", _name, start_sample, end_sample, nframes));
376         }
377 #endif
378
379         check_record_status (start_sample, speed, can_record);
380
381         if (nframes == 0) {
382                 return;
383         }
384
385         nominally_recording = (can_record && re);
386
387         // Safeguard against situations where process() goes haywire when autopunching
388         // and last_recordable_sample < first_recordable_sample
389
390         if (last_recordable_sample < first_recordable_sample) {
391                 last_recordable_sample = max_samplepos;
392         }
393
394         const Location* const loop_loc    = loop_location;
395         samplepos_t           loop_start  = 0;
396         samplepos_t           loop_end    = 0;
397         samplepos_t           loop_length = 0;
398
399         if (loop_loc) {
400                 get_location_times (loop_loc, &loop_start, &loop_end, &loop_length);
401         }
402
403         if (nominally_recording || (re && was_recording && _session.get_record_enabled() && (_session.config.get_punch_in() || _session.preroll_record_punch_enabled()))) {
404
405                 Evoral::OverlapType ot = Evoral::coverage (first_recordable_sample, last_recordable_sample, start_sample, end_sample);
406                 // XXX should this be transport_sample + nframes - 1 ? coverage() expects its parameter ranges to include their end points
407                 // XXX also, first_recordable_sample & last_recordable_sample may both be == max_samplepos: coverage() will return OverlapNone in that case. Is thak OK?
408                 calculate_record_range (ot, start_sample, nframes, rec_nframes, rec_offset);
409
410                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: this time record %2 of %3 samples, offset %4\n", _name, rec_nframes, nframes, rec_offset));
411
412                 if (rec_nframes && !was_recording) {
413                         capture_captured = 0;
414
415                         if (loop_loc) {
416                                 /* Loop recording, so pretend the capture started at the loop
417                                    start rgardless of what time it is now, so the source starts
418                                    at the loop start and can handle time wrapping around.
419                                    Otherwise, start the source right now as usual.
420                                 */
421                                 capture_captured     = start_sample - loop_start;
422                                 capture_start_sample = loop_start;
423                         }
424
425                         if (_midi_write_source) {
426                                 _midi_write_source->mark_write_starting_now (capture_start_sample, capture_captured, loop_length);
427                         }
428
429                         g_atomic_int_set (const_cast<gint*> (&_samples_pending_write), 0);
430                         g_atomic_int_set (const_cast<gint*> (&_num_captured_loops), 0);
431
432                         was_recording = true;
433
434                 }
435
436                 /* For audio: not writing samples to the capture ringbuffer offsets
437                  * the recording. For midi: we need to keep track of the record range
438                  * and subtract the accumulated difference from the event time.
439                  */
440                 if (rec_nframes) {
441                         _accumulated_capture_offset += rec_offset;
442                 } else {
443                         _accumulated_capture_offset += nframes;
444                 }
445
446         }
447
448         if (can_record && !_last_capture_sources.empty ()) {
449                 _last_capture_sources.clear ();
450         }
451
452         if (rec_nframes) {
453
454                 /* AUDIO */
455
456                 const size_t n_buffers = bufs.count().n_audio();
457
458                 for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
459
460                         ChannelInfo* chaninfo (*chan);
461                         AudioBuffer& buf (bufs.get_audio (n%n_buffers));
462
463                         chaninfo->buf->get_write_vector (&chaninfo->rw_vector);
464
465                         if (rec_nframes <= (samplecnt_t) chaninfo->rw_vector.len[0]) {
466
467                                 Sample *incoming = buf.data (rec_offset);
468                                 memcpy (chaninfo->rw_vector.buf[0], incoming, sizeof (Sample) * rec_nframes);
469
470                         } else {
471
472                                 samplecnt_t total = chaninfo->rw_vector.len[0] + chaninfo->rw_vector.len[1];
473
474                                 if (rec_nframes > total) {
475                                         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 overrun in %2, rec_nframes = %3 total space = %4\n",
476                                                                                     DEBUG_THREAD_SELF, name(), rec_nframes, total));
477                                         Overrun ();
478                                         return;
479                                 }
480
481                                 Sample *incoming = buf.data (rec_offset);
482                                 samplecnt_t first = chaninfo->rw_vector.len[0];
483
484                                 memcpy (chaninfo->rw_vector.buf[0], incoming, sizeof (Sample) * first);
485                                 memcpy (chaninfo->rw_vector.buf[1], incoming + first, sizeof (Sample) * (rec_nframes - first));
486                         }
487
488                         chaninfo->buf->increment_write_ptr (rec_nframes);
489
490                 }
491
492                 /* MIDI */
493
494                 // Pump entire port buffer into the ring buffer (TODO: split cycles?)
495                 MidiBuffer& buf    = bufs.get_midi (0);
496                 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack>(_route);
497                 MidiChannelFilter* filter = mt ? &mt->capture_filter() : 0;
498
499                 for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
500                         Evoral::Event<MidiBuffer::TimeType> ev (*i, false);
501                         if (ev.time() + rec_offset > rec_nframes) {
502                                 break;
503                         }
504 #ifndef NDEBUG
505                         if (DEBUG_ENABLED(DEBUG::MidiIO)) {
506                                 const uint8_t* __data = ev.buffer();
507                                 DEBUG_STR_DECL(a);
508                                 DEBUG_STR_APPEND(a, string_compose ("mididiskstream %1 capture event @ %2 + %3 sz %4 ", this, ev.time(), start_sample, ev.size()));
509                                 for (size_t i=0; i < ev.size(); ++i) {
510                                         DEBUG_STR_APPEND(a,hex);
511                                         DEBUG_STR_APPEND(a,"0x");
512                                         DEBUG_STR_APPEND(a,(int)__data[i]);
513                                         DEBUG_STR_APPEND(a,' ');
514                                 }
515                                 DEBUG_STR_APPEND(a,'\n');
516                                 DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
517                         }
518 #endif
519                         /* Write events to the capture buffer in samples from session start,
520                            but ignoring looping so event time progresses monotonically.
521                            The source knows the loop length so it knows exactly where the
522                            event occurs in the series of recorded loops and can implement
523                            any desirable behaviour.  We don't want to send event with
524                            transport time here since that way the source can not
525                            reconstruct their actual time; future clever MIDI looping should
526                            probably be implemented in the source instead of here.
527                         */
528                         const samplecnt_t loop_offset = _num_captured_loops * loop_length;
529                         const samplepos_t event_time = start_sample + loop_offset - _accumulated_capture_offset + ev.time();
530                         if (event_time < 0 || event_time < first_recordable_sample) {
531                                 /* Event out of range, skip */
532                                 continue;
533                         }
534
535                         if (!filter || !filter->filter(ev.buffer(), ev.size())) {
536                                 _midi_buf->write (event_time, ev.event_type(), ev.size(), ev.buffer());
537                         }
538                 }
539                 g_atomic_int_add (const_cast<gint*>(&_samples_pending_write), nframes);
540
541                 if (buf.size() != 0) {
542                         Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex, Glib::Threads::TRY_LOCK);
543
544                         if (lm.locked ()) {
545                                 /* Copy this data into our GUI feed buffer and tell the GUI
546                                    that it can read it if it likes.
547                                 */
548                                 _gui_feed_buffer.clear ();
549
550                                 for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
551                                         /* This may fail if buf is larger than _gui_feed_buffer, but it's not really
552                                            the end of the world if it does.
553                                         */
554                                         _gui_feed_buffer.push_back ((*i).time() + start_sample, (*i).size(), (*i).buffer());
555                                 }
556                         }
557
558                         DataRecorded (_midi_write_source); /* EMIT SIGNAL */
559                 }
560
561                 capture_captured += rec_nframes;
562                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 now captured %2 (by %3)\n", name(), capture_captured, rec_nframes));
563
564         } else {
565
566                 /* not recording this time, but perhaps we were before .. */
567
568                 if (was_recording) {
569                         finish_capture (c);
570                         _accumulated_capture_offset = 0;
571                 }
572         }
573
574         /* AUDIO BUTLER REQUIRED CODE */
575
576         if (_playlists[DataType::AUDIO] && !c->empty()) {
577                 if (((samplecnt_t) c->front()->buf->read_space() >= _chunk_samples)) {
578                         _need_butler = true;
579                 }
580         }
581
582         /* MIDI BUTLER REQUIRED CODE */
583
584         if (_playlists[DataType::MIDI] && (_midi_buf->read_space() < _midi_buf->bufsize() / 2)) {
585                 _need_butler = true;
586         }
587
588         // DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 writer run, needs butler = %2\n", name(), _need_butler));
589 }
590
591 void
592 DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c)
593 {
594         was_recording = false;
595         first_recordable_sample = max_samplepos;
596         last_recordable_sample = max_samplepos;
597
598         if (capture_captured == 0) {
599                 return;
600         }
601
602         if (recordable() && destructive()) {
603                 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
604
605                         RingBufferNPT<CaptureTransition>::rw_vector transvec;
606                         (*chan)->capture_transition_buf->get_write_vector(&transvec);
607
608                         if (transvec.len[0] > 0) {
609                                 transvec.buf[0]->type = CaptureEnd;
610                                 transvec.buf[0]->capture_val = capture_captured;
611                                 (*chan)->capture_transition_buf->increment_write_ptr(1);
612                         }
613                         else {
614                                 // bad!
615                                 fatal << string_compose (_("programmer error: %1"), X_("capture_transition_buf is full when stopping record!  inconceivable!")) << endmsg;
616                         }
617                 }
618         }
619
620
621         CaptureInfo* ci = new CaptureInfo;
622
623         ci->start =  capture_start_sample;
624         ci->samples = capture_captured;
625
626         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("Finish capture, add new CI, %1 + %2\n", ci->start, ci->samples));
627
628         /* XXX theoretical race condition here. Need atomic exchange ?
629            However, the circumstances when this is called right
630            now (either on record-disable or transport_stopped)
631            mean that no actual race exists. I think ...
632            We now have a capture_info_lock, but it is only to be used
633            to synchronize in the transport_stop and the capture info
634            accessors, so that invalidation will not occur (both non-realtime).
635         */
636
637         capture_info.push_back (ci);
638         capture_captured = 0;
639
640         /* now we've finished a capture, reset first_recordable_sample for next time */
641         first_recordable_sample = max_samplepos;
642 }
643
644 void
645 DiskWriter::set_record_enabled (bool yn)
646 {
647         if (!recordable() || !_session.record_enabling_legal() || record_safe ()) {
648                 return;
649         }
650
651         /* can't rec-enable in destructive mode if transport is before start */
652
653         if (destructive() && yn && _session.transport_sample() < _session.current_start_sample()) {
654                 return;
655         }
656
657         /* yes, i know that this not proof against race conditions, but its
658            good enough. i think.
659         */
660
661         if (record_enabled() != yn) {
662                 if (yn) {
663                         engage_record_enable ();
664                 } else {
665                         disengage_record_enable ();
666                 }
667
668                 RecordEnableChanged (); /* EMIT SIGNAL */
669         }
670 }
671
672 void
673 DiskWriter::set_record_safe (bool yn)
674 {
675         if (!recordable() || !_session.record_enabling_legal() || channels.reader()->empty()) {
676                 return;
677         }
678
679         /* can't rec-safe in destructive mode if transport is before start ????
680          REQUIRES REVIEW */
681
682         if (destructive() && yn && _session.transport_sample() < _session.current_start_sample()) {
683                 return;
684         }
685
686         /* yes, i know that this not proof against race conditions, but its
687          good enough. i think.
688          */
689
690         if (record_safe () != yn) {
691                 if (yn) {
692                         engage_record_safe ();
693                 } else {
694                         disengage_record_safe ();
695                 }
696
697                 RecordSafeChanged (); /* EMIT SIGNAL */
698         }
699 }
700
701 bool
702 DiskWriter::prep_record_enable ()
703 {
704         if (!recordable() || !_session.record_enabling_legal() || channels.reader()->empty() || record_safe ()) { // REQUIRES REVIEW "|| record_safe ()"
705                 return false;
706         }
707
708         /* can't rec-enable in destructive mode if transport is before start */
709
710         if (destructive() && _session.transport_sample() < _session.current_start_sample()) {
711                 return false;
712         }
713
714         boost::shared_ptr<ChannelList> c = channels.reader();
715
716         capturing_sources.clear ();
717
718         for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
719                 capturing_sources.push_back ((*chan)->write_source);
720                 Source::Lock lock((*chan)->write_source->mutex());
721                 (*chan)->write_source->mark_streaming_write_started (lock);
722         }
723
724         return true;
725 }
726
727 bool
728 DiskWriter::prep_record_disable ()
729 {
730         capturing_sources.clear ();
731         return true;
732 }
733
734 float
735 DiskWriter::buffer_load () const
736 {
737         boost::shared_ptr<ChannelList> c = channels.reader();
738
739         if (c->empty ()) {
740                 return 1.0;
741         }
742
743         return (float) ((double) c->front()->buf->write_space()/
744                         (double) c->front()->buf->bufsize());
745 }
746
747 void
748 DiskWriter::set_note_mode (NoteMode m)
749 {
750         _note_mode = m;
751
752         boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlists[DataType::MIDI]);
753
754         if (mp) {
755                 mp->set_note_mode (m);
756         }
757
758         if (_midi_write_source && _midi_write_source->model())
759                 _midi_write_source->model()->set_note_mode(m);
760 }
761
762 int
763 DiskWriter::seek (samplepos_t sample, bool complete_refill)
764 {
765         uint32_t n;
766         ChannelList::iterator chan;
767         boost::shared_ptr<ChannelList> c = channels.reader();
768
769         for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
770                 (*chan)->buf->reset ();
771         }
772
773         _midi_buf->reset ();
774         g_atomic_int_set(&_samples_read_from_ringbuffer, 0);
775         g_atomic_int_set(&_samples_written_to_ringbuffer, 0);
776
777         /* can't rec-enable in destructive mode if transport is before start */
778
779         if (destructive() && record_enabled() && sample < _session.current_start_sample()) {
780                 disengage_record_enable ();
781         }
782
783         playback_sample = sample;
784
785         return 0;
786 }
787
788 int
789 DiskWriter::do_flush (RunContext ctxt, bool force_flush)
790 {
791         uint32_t to_write;
792         int32_t ret = 0;
793         RingBufferNPT<Sample>::rw_vector vector;
794         RingBufferNPT<CaptureTransition>::rw_vector transvec;
795         samplecnt_t total;
796
797         transvec.buf[0] = 0;
798         transvec.buf[1] = 0;
799         vector.buf[0] = 0;
800         vector.buf[1] = 0;
801
802         boost::shared_ptr<ChannelList> c = channels.reader();
803         for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
804
805                 (*chan)->buf->get_read_vector (&vector);
806
807                 total = vector.len[0] + vector.len[1];
808
809                 if (total == 0 || (total < _chunk_samples && !force_flush && was_recording)) {
810                         goto out;
811                 }
812
813                 /* if there are 2+ chunks of disk i/o possible for
814                    this track, let the caller know so that it can arrange
815                    for us to be called again, ASAP.
816
817                    if we are forcing a flush, then if there is* any* extra
818                    work, let the caller know.
819
820                    if we are no longer recording and there is any extra work,
821                    let the caller know too.
822                 */
823
824                 if (total >= 2 * _chunk_samples || ((force_flush || !was_recording) && total > _chunk_samples)) {
825                         ret = 1;
826                 }
827
828                 to_write = min (_chunk_samples, (samplecnt_t) vector.len[0]);
829
830                 // check the transition buffer when recording destructive
831                 // important that we get this after the capture buf
832
833                 if (destructive()) {
834                         (*chan)->capture_transition_buf->get_read_vector(&transvec);
835                         size_t transcount = transvec.len[0] + transvec.len[1];
836                         size_t ti;
837
838                         for (ti=0; ti < transcount; ++ti) {
839                                 CaptureTransition & captrans = (ti < transvec.len[0]) ? transvec.buf[0][ti] : transvec.buf[1][ti-transvec.len[0]];
840
841                                 if (captrans.type == CaptureStart) {
842                                         // by definition, the first data we got above represents the given capture pos
843
844                                         (*chan)->write_source->mark_capture_start (captrans.capture_val);
845                                         (*chan)->curr_capture_cnt = 0;
846
847                                 } else if (captrans.type == CaptureEnd) {
848
849                                         // capture end, the capture_val represents total samples in capture
850
851                                         if (captrans.capture_val <= (*chan)->curr_capture_cnt + to_write) {
852
853                                                 // shorten to make the write a perfect fit
854                                                 uint32_t nto_write = (captrans.capture_val - (*chan)->curr_capture_cnt);
855
856                                                 if (nto_write < to_write) {
857                                                         ret = 1; // should we?
858                                                 }
859                                                 to_write = nto_write;
860
861                                                 (*chan)->write_source->mark_capture_end ();
862
863                                                 // increment past this transition, but go no further
864                                                 ++ti;
865                                                 break;
866                                         }
867                                         else {
868                                                 // actually ends just beyond this chunk, so force more work
869                                                 ret = 1;
870                                                 break;
871                                         }
872                                 }
873                         }
874
875                         if (ti > 0) {
876                                 (*chan)->capture_transition_buf->increment_read_ptr(ti);
877                         }
878                 }
879
880                 if ((!(*chan)->write_source) || (*chan)->write_source->write (vector.buf[0], to_write) != to_write) {
881                         error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg;
882                         return -1;
883                 }
884
885                 (*chan)->buf->increment_read_ptr (to_write);
886                 (*chan)->curr_capture_cnt += to_write;
887
888                 if ((to_write == vector.len[0]) && (total > to_write) && (to_write < _chunk_samples) && !destructive()) {
889
890                         /* we wrote all of vector.len[0] but it wasn't an entire
891                            disk_write_chunk_samples of data, so arrange for some part
892                            of vector.len[1] to be flushed to disk as well.
893                         */
894
895                         to_write = min ((samplecnt_t)(_chunk_samples - to_write), (samplecnt_t) vector.len[1]);
896
897                         DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 additional write of %2\n", name(), to_write));
898
899                         if ((*chan)->write_source->write (vector.buf[1], to_write) != to_write) {
900                                 error << string_compose(_("AudioDiskstream %1: cannot write to disk"), id()) << endmsg;
901                                 return -1;
902                         }
903
904                         (*chan)->buf->increment_read_ptr (to_write);
905                         (*chan)->curr_capture_cnt += to_write;
906                 }
907         }
908
909         /* MIDI*/
910
911         if (_midi_write_source) {
912
913                 const samplecnt_t total = g_atomic_int_get(const_cast<gint*> (&_samples_pending_write));
914
915                 if (total == 0 ||
916                     _midi_buf->read_space() == 0 ||
917                     (!force_flush && (total < _chunk_samples) && was_recording)) {
918                         goto out;
919                 }
920
921                 /* if there are 2+ chunks of disk i/o possible for
922                    this track), let the caller know so that it can arrange
923                    for us to be called again, ASAP.
924
925                    if we are forcing a flush, then if there is* any* extra
926                    work, let the caller know.
927
928                    if we are no longer recording and there is any extra work,
929                    let the caller know too.
930                 */
931
932                 if (total >= 2 * _chunk_samples || ((force_flush || !was_recording) && total > _chunk_samples)) {
933                         ret = 1;
934                 }
935
936                 if (force_flush) {
937                         /* push out everything we have, right now */
938                         to_write = UINT32_MAX;
939                 } else {
940                         to_write = _chunk_samples;
941                 }
942
943                 if (record_enabled() && ((total > _chunk_samples) || force_flush)) {
944                         Source::Lock lm(_midi_write_source->mutex());
945                         if (_midi_write_source->midi_write (lm, *_midi_buf, get_capture_start_sample (0), to_write) != to_write) {
946                                 error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
947                                 return -1;
948                         }
949                         g_atomic_int_add(const_cast<gint*> (&_samples_pending_write), -to_write);
950                 }
951         }
952
953   out:
954         return ret;
955
956 }
957
958 void
959 DiskWriter::reset_write_sources (bool mark_write_complete, bool /*force*/)
960 {
961         ChannelList::iterator chan;
962         boost::shared_ptr<ChannelList> c = channels.reader();
963         uint32_t n;
964
965         if (!_session.writable() || !recordable()) {
966                 return;
967         }
968
969         capturing_sources.clear ();
970
971         for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
972
973                 if (!destructive()) {
974
975                         if ((*chan)->write_source) {
976
977                                 if (mark_write_complete) {
978                                         Source::Lock lock((*chan)->write_source->mutex());
979                                         (*chan)->write_source->mark_streaming_write_completed (lock);
980                                         (*chan)->write_source->done_with_peakfile_writes ();
981                                 }
982
983                                 if ((*chan)->write_source->removable()) {
984                                         (*chan)->write_source->mark_for_remove ();
985                                         (*chan)->write_source->drop_references ();
986                                 }
987
988                                 (*chan)->write_source.reset ();
989                         }
990
991                         use_new_write_source (DataType::AUDIO, n);
992
993                         if (record_enabled()) {
994                                 capturing_sources.push_back ((*chan)->write_source);
995                         }
996
997                 } else {
998
999                         if ((*chan)->write_source == 0) {
1000                                 use_new_write_source (DataType::AUDIO, n);
1001                         }
1002                 }
1003         }
1004
1005         if (_midi_write_source) {
1006                 if (mark_write_complete) {
1007                         Source::Lock lm(_midi_write_source->mutex());
1008                         _midi_write_source->mark_streaming_write_completed (lm);
1009                 }
1010         }
1011
1012         if (_playlists[DataType::MIDI]) {
1013                 use_new_write_source (DataType::MIDI);
1014         }
1015
1016         if (destructive() && !c->empty ()) {
1017
1018                 /* we now have all our write sources set up, so create the
1019                    playlist's single region.
1020                 */
1021
1022                 if (_playlists[DataType::MIDI]->empty()) {
1023                         setup_destructive_playlist ();
1024                 }
1025         }
1026 }
1027
1028 int
1029 DiskWriter::use_new_write_source (DataType dt, uint32_t n)
1030 {
1031         if (dt == DataType::MIDI) {
1032
1033                 _accumulated_capture_offset = 0;
1034                 _midi_write_source.reset();
1035
1036                 try {
1037                         _midi_write_source = boost::dynamic_pointer_cast<SMFSource>(
1038                                 _session.create_midi_source_for_session (write_source_name ()));
1039
1040                         if (!_midi_write_source) {
1041                                 throw failed_constructor();
1042                         }
1043                 }
1044
1045                 catch (failed_constructor &err) {
1046                         error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg;
1047                         _midi_write_source.reset();
1048                         return -1;
1049                 }
1050         } else {
1051                 boost::shared_ptr<ChannelList> c = channels.reader();
1052
1053                 if (!recordable()) {
1054                         return 1;
1055                 }
1056
1057                 if (n >= c->size()) {
1058                         error << string_compose (_("AudioDiskstream: channel %1 out of range"), n) << endmsg;
1059                         return -1;
1060                 }
1061
1062                 ChannelInfo* chan = (*c)[n];
1063
1064                 try {
1065                         if ((chan->write_source = _session.create_audio_source_for_session (
1066                                      c->size(), write_source_name(), n, destructive())) == 0) {
1067                                 throw failed_constructor();
1068                         }
1069                 }
1070
1071                 catch (failed_constructor &err) {
1072                         error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg;
1073                         chan->write_source.reset ();
1074                         return -1;
1075                 }
1076
1077                 /* do not remove destructive files even if they are empty */
1078
1079                 chan->write_source->set_allow_remove_if_empty (!destructive());
1080         }
1081
1082         return 0;
1083 }
1084
1085 void
1086 DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abort_capture)
1087 {
1088         bool more_work = true;
1089         int err = 0;
1090         samplecnt_t total_capture;
1091         SourceList audio_srcs;
1092         SourceList midi_srcs;
1093         ChannelList::iterator chan;
1094         vector<CaptureInfo*>::iterator ci;
1095         boost::shared_ptr<ChannelList> c = channels.reader();
1096         uint32_t n = 0;
1097         bool mark_write_completed = false;
1098
1099         finish_capture (c);
1100
1101
1102         /* butler is already stopped, but there may be work to do
1103            to flush remaining data to disk.
1104         */
1105
1106         while (more_work && !err) {
1107                 switch (do_flush (TransportContext, true)) {
1108                 case 0:
1109                         more_work = false;
1110                         break;
1111                 case 1:
1112                         break;
1113                 case -1:
1114                         error << string_compose(_("AudioDiskstream \"%1\": cannot flush captured data to disk!"), _name) << endmsg;
1115                         err++;
1116                 }
1117         }
1118
1119         /* XXX is there anything we can do if err != 0 ? */
1120         Glib::Threads::Mutex::Lock lm (capture_info_lock);
1121
1122         if (capture_info.empty()) {
1123                 return;
1124         }
1125
1126         if (abort_capture) {
1127
1128                 if (destructive()) {
1129                         goto outout;
1130                 }
1131
1132                 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
1133
1134                         if ((*chan)->write_source) {
1135
1136                                 (*chan)->write_source->mark_for_remove ();
1137                                 (*chan)->write_source->drop_references ();
1138                                 (*chan)->write_source.reset ();
1139                         }
1140
1141                         /* new source set up in "out" below */
1142                 }
1143
1144                 if (_midi_write_source) {
1145                         _midi_write_source->mark_for_remove ();
1146                         _midi_write_source->drop_references ();
1147                         _midi_write_source.reset();
1148                 }
1149
1150                 goto out;
1151         }
1152
1153         for (total_capture = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
1154                 total_capture += (*ci)->samples;
1155         }
1156
1157         /* figure out the name for this take */
1158
1159         for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
1160
1161                 boost::shared_ptr<AudioFileSource> as = (*chan)->write_source;
1162
1163                 if (as) {
1164                         audio_srcs.push_back (as);
1165                         as->update_header (capture_info.front()->start, when, twhen);
1166                         as->set_captured_for (_name.val());
1167                         as->mark_immutable ();
1168
1169                         if (Config->get_auto_analyse_audio()) {
1170                                 Analyser::queue_source_for_analysis (as, true);
1171                         }
1172
1173                         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", as->path(), as->length (0)));
1174                 }
1175
1176                 if (_midi_write_source) {
1177                         midi_srcs.push_back (_midi_write_source);
1178                 }
1179         }
1180
1181
1182         /* MIDI */
1183
1184         if (_midi_write_source) {
1185
1186                 if (_midi_write_source->length (capture_info.front()->start) == 0) {
1187                         /* No data was recorded, so this capture will
1188                            effectively be aborted; do the same as we
1189                            do for an explicit abort.
1190                         */
1191                         if (_midi_write_source) {
1192                                 _midi_write_source->mark_for_remove ();
1193                                 _midi_write_source->drop_references ();
1194                                 _midi_write_source.reset();
1195                         }
1196
1197                         goto out;
1198                 }
1199
1200                 /* phew, we have data */
1201
1202                 Source::Lock source_lock(_midi_write_source->mutex());
1203
1204                 /* figure out the name for this take */
1205
1206                 midi_srcs.push_back (_midi_write_source);
1207
1208                 _midi_write_source->set_timeline_position (capture_info.front()->start);
1209                 _midi_write_source->set_captured_for (_name);
1210
1211                 /* set length in beats to entire capture length */
1212
1213                 BeatsSamplesConverter converter (_session.tempo_map(), capture_info.front()->start);
1214                 const Temporal::Beats total_capture_beats = converter.from (total_capture);
1215                 _midi_write_source->set_length_beats (total_capture_beats);
1216
1217                 /* flush to disk: this step differs from the audio path,
1218                    where all the data is already on disk.
1219                 */
1220
1221                 _midi_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Temporal::Beats>::ResolveStuckNotes, total_capture_beats);
1222         }
1223
1224         _last_capture_sources.insert (_last_capture_sources.end(), audio_srcs.begin(), audio_srcs.end());
1225         _last_capture_sources.insert (_last_capture_sources.end(), midi_srcs.begin(), midi_srcs.end());
1226
1227
1228         if (_route) {
1229                 _route->use_captured_sources (audio_srcs, capture_info);
1230                 _route->use_captured_sources (midi_srcs, capture_info);
1231         }
1232
1233         mark_write_completed = true;
1234
1235   out:
1236         reset_write_sources (mark_write_completed);
1237
1238   outout:
1239
1240         for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
1241                 delete *ci;
1242         }
1243
1244         capture_info.clear ();
1245         capture_start_sample = 0;
1246 }
1247
1248 void
1249 DiskWriter::transport_looped (samplepos_t transport_sample)
1250 {
1251         if (was_recording) {
1252                 // all we need to do is finish this capture, with modified capture length
1253                 boost::shared_ptr<ChannelList> c = channels.reader();
1254
1255                 finish_capture (c);
1256
1257                 // the next region will start recording via the normal mechanism
1258                 // we'll set the start position to the current transport pos
1259                 // no latency adjustment or capture offset needs to be made, as that already happened the first time
1260                 capture_start_sample = transport_sample;
1261                 first_recordable_sample = transport_sample; // mild lie
1262                 last_recordable_sample = max_samplepos;
1263                 was_recording = true;
1264
1265                 if (recordable() && destructive()) {
1266                         for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
1267
1268                                 RingBufferNPT<CaptureTransition>::rw_vector transvec;
1269                                 (*chan)->capture_transition_buf->get_write_vector(&transvec);
1270
1271                                 if (transvec.len[0] > 0) {
1272                                         transvec.buf[0]->type = CaptureStart;
1273                                         transvec.buf[0]->capture_val = capture_start_sample;
1274                                         (*chan)->capture_transition_buf->increment_write_ptr(1);
1275                                 }
1276                                 else {
1277                                         // bad!
1278                                         fatal << X_("programming error: capture_transition_buf is full on rec loop!  inconceivable!")
1279                                               << endmsg;
1280                                 }
1281                         }
1282                 }
1283
1284         }
1285
1286         /* Here we only keep track of the number of captured loops so monotonic
1287            event times can be delivered to the write source in process().  Trying
1288            to be clever here is a world of trouble, it is better to simply record
1289            the input in a straightforward non-destructive way.  In the future when
1290            we want to implement more clever MIDI looping modes it should be done in
1291            the Source and/or entirely after the capture is finished.
1292         */
1293         if (was_recording) {
1294                 g_atomic_int_add(const_cast<gint*> (&_num_captured_loops), 1);
1295         }
1296 }
1297
1298 void
1299 DiskWriter::setup_destructive_playlist ()
1300 {
1301         SourceList srcs;
1302         boost::shared_ptr<ChannelList> c = channels.reader();
1303
1304         for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
1305                 srcs.push_back ((*chan)->write_source);
1306         }
1307
1308         /* a single full-sized region */
1309
1310         assert (!srcs.empty ());
1311
1312         PropertyList plist;
1313         plist.add (Properties::name, _name.val());
1314         plist.add (Properties::start, 0);
1315         plist.add (Properties::length, max_samplepos - srcs.front()->natural_position());
1316
1317         boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist));
1318         _playlists[DataType::AUDIO]->add_region (region, srcs.front()->natural_position());
1319
1320         /* apply region properties and update write sources */
1321         use_destructive_playlist();
1322 }
1323
1324 void
1325 DiskWriter::use_destructive_playlist ()
1326 {
1327         /* this is called from the XML-based constructor or ::set_destructive. when called,
1328            we already have a playlist and a region, but we need to
1329            set up our sources for write. we use the sources associated
1330            with the (presumed single, full-extent) region.
1331         */
1332
1333         boost::shared_ptr<Region> rp;
1334         {
1335                 const RegionList& rl (_playlists[DataType::AUDIO]->region_list_property().rlist());
1336                 if (rl.size() > 0) {
1337                         /* this can happen when dragging a region onto a tape track */
1338                         assert((rl.size() == 1));
1339                         rp = rl.front();
1340                 }
1341         }
1342
1343         if (!rp) {
1344                 reset_write_sources (false, true);
1345                 return;
1346         }
1347
1348         boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (rp);
1349
1350         if (region == 0) {
1351                 throw failed_constructor();
1352         }
1353
1354         /* be sure to stretch the region out to the maximum length (non-musical)*/
1355
1356         region->set_length (max_samplepos - region->position(), 0);
1357
1358         uint32_t n;
1359         ChannelList::iterator chan;
1360         boost::shared_ptr<ChannelList> c = channels.reader();
1361
1362         for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
1363                 (*chan)->write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n));
1364                 assert((*chan)->write_source);
1365                 (*chan)->write_source->set_allow_remove_if_empty (false);
1366
1367                 /* this might be false if we switched modes, so force it */
1368
1369 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
1370                 (*chan)->write_source->set_destructive (true);
1371 #else
1372                 // should be set when creating the source or loading the state
1373                 assert ((*chan)->write_source->destructive());
1374 #endif
1375         }
1376
1377         /* the source list will never be reset for a destructive track */
1378 }
1379
1380 void
1381 DiskWriter::adjust_buffering ()
1382 {
1383         boost::shared_ptr<ChannelList> c = channels.reader();
1384
1385         for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
1386                 (*chan)->resize (_session.butler()->audio_diskstream_capture_buffer_size());
1387         }
1388 }
1389
1390 void
1391 DiskWriter::realtime_handle_transport_stopped ()
1392 {
1393         realtime_speed_change ();
1394 }
1395
1396 bool
1397 DiskWriter::set_name (string const & str)
1398 {
1399         string my_name = X_("recorder:");
1400         my_name += str;
1401
1402         if (_name != my_name) {
1403                 SessionObject::set_name (my_name);
1404         }
1405
1406         return true;
1407 }
1408
1409 std::string
1410 DiskWriter::steal_write_source_name ()
1411 {
1412         if (_playlists[DataType::MIDI]) {
1413                 string our_old_name = _midi_write_source->name();
1414
1415                 /* this will bump the name of the current write source to the next one
1416                  * (e.g. "MIDI 1-1" gets renamed to "MIDI 1-2"), thus leaving the
1417                  * current write source name (e.g. "MIDI 1-1" available). See the
1418                  * comments in Session::create_midi_source_by_stealing_name() about why
1419                  * we do this.
1420                  */
1421
1422                 try {
1423                         string new_path = _session.new_midi_source_path (name());
1424
1425                         if (_midi_write_source->rename (new_path)) {
1426                                 return string();
1427                         }
1428                 } catch (...) {
1429                         return string ();
1430                 }
1431
1432                 return our_old_name;
1433         }
1434
1435         return std::string();
1436 }
1437
1438 bool
1439 DiskWriter::configure_io (ChanCount in, ChanCount out)
1440 {
1441         if (!DiskIOProcessor::configure_io (in, out)) {
1442                 return false;
1443         }
1444
1445         reset_write_sources (false, true);
1446
1447         return true;
1448 }