possible fix for race between diskstream buffer overwrite and channel setup
[ardour2.git] / libs / ardour / diskstream.cc
bloba600cce5e2ec9f17c643616994dcc676aaebaa38
1 /*
2 Copyright (C) 2000-2006 Paul Davis
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.
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.
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.
20 #include <fstream>
21 #include <cassert>
22 #include <cstdio>
23 #include <unistd.h>
24 #include <cmath>
25 #include <cerrno>
26 #include <string>
27 #include <climits>
28 #include <fcntl.h>
29 #include <cstdlib>
30 #include <ctime>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
35 #include "pbd/error.h"
36 #include "pbd/basename.h"
37 #include <glibmm/thread.h>
38 #include "pbd/xml++.h"
39 #include "pbd/memento_command.h"
41 #include "ardour/ardour.h"
42 #include "ardour/audioengine.h"
43 #include "ardour/debug.h"
44 #include "ardour/diskstream.h"
45 #include "ardour/utils.h"
46 #include "ardour/configuration.h"
47 #include "ardour/audiofilesource.h"
48 #include "ardour/send.h"
49 #include "ardour/playlist.h"
50 #include "ardour/cycle_timer.h"
51 #include "ardour/region.h"
52 #include "ardour/panner.h"
53 #include "ardour/session.h"
54 #include "ardour/io.h"
55 #include "ardour/route.h"
57 #include "i18n.h"
58 #include <locale.h>
60 using namespace std;
61 using namespace ARDOUR;
62 using namespace PBD;
64 /* XXX This goes uninitialized when there is no ~/.config/ardour3 directory.
65 * I can't figure out why, so this will do for now (just stole the
66 * default from configuration_vars.h). 0 is not a good value for
67 * allocating buffer sizes..
69 ARDOUR::nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
71 PBD::Signal0<void> Diskstream::DiskOverrun;
72 PBD::Signal0<void> Diskstream::DiskUnderrun;
74 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
75 : SessionObject(sess, name)
76 , i_am_the_modifier (0)
77 , _route (0)
78 , _record_enabled (0)
79 , _visible_speed (1.0f)
80 , _actual_speed (1.0f)
81 , _buffer_reallocation_required (false)
82 , _seek_required (false)
83 , force_refill (false)
84 , capture_start_frame (0)
85 , capture_captured (0)
86 , was_recording (false)
87 , adjust_capture_position (0)
88 , _capture_offset (0)
89 , _roll_delay (0)
90 , first_recordable_frame (max_frames)
91 , last_recordable_frame (max_frames)
92 , last_possibly_recording (0)
93 , _alignment_style (ExistingMaterial)
94 , _scrubbing (false)
95 , _slaved (false)
96 , loop_location (0)
97 , overwrite_frame (0)
98 , overwrite_offset (0)
99 , pending_overwrite (false)
100 , overwrite_queued (false)
101 , input_change_pending (NoChange)
102 , wrap_buffer_size (0)
103 , speed_buffer_size (0)
104 , _speed (1.0)
105 , _target_speed (_speed)
106 , file_frame (0)
107 , playback_sample (0)
108 , playback_distance (0)
109 , _read_data_count (0)
110 , _write_data_count (0)
111 , in_set_state (false)
112 , _persistent_alignment_style (ExistingMaterial)
113 , first_input_change (true)
114 , scrub_start (0)
115 , scrub_buffer_size (0)
116 , scrub_offset (0)
117 , _flags (flag)
122 Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
123 : SessionObject(sess, "unnamed diskstream")
124 , i_am_the_modifier (0)
125 , _route (0)
126 , _record_enabled (0)
127 , _visible_speed (1.0f)
128 , _actual_speed (1.0f)
129 , _buffer_reallocation_required (false)
130 , _seek_required (false)
131 , force_refill (false)
132 , capture_start_frame (0)
133 , capture_captured (0)
134 , was_recording (false)
135 , adjust_capture_position (0)
136 , _capture_offset (0)
137 , _roll_delay (0)
138 , first_recordable_frame (max_frames)
139 , last_recordable_frame (max_frames)
140 , last_possibly_recording (0)
141 , _alignment_style (ExistingMaterial)
142 , _scrubbing (false)
143 , _slaved (false)
144 , loop_location (0)
145 , overwrite_frame (0)
146 , overwrite_offset (0)
147 , pending_overwrite (false)
148 , overwrite_queued (false)
149 , input_change_pending (NoChange)
150 , wrap_buffer_size (0)
151 , speed_buffer_size (0)
152 , _speed (1.0)
153 , _target_speed (_speed)
154 , file_frame (0)
155 , playback_sample (0)
156 , playback_distance (0)
157 , _read_data_count (0)
158 , _write_data_count (0)
159 , in_set_state (false)
160 , _persistent_alignment_style (ExistingMaterial)
161 , first_input_change (true)
162 , scrub_start (0)
163 , scrub_buffer_size (0)
164 , scrub_offset (0)
165 , _flags (Recordable)
169 Diskstream::~Diskstream ()
171 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Diskstream %1 deleted\n", _name));
173 if (_playlist) {
174 _playlist->release ();
178 void
179 Diskstream::set_route (Route& r)
181 _route = &r;
182 _io = _route->input();
184 ic_connection.disconnect();
185 _io->changed.connect_same_thread (ic_connection, boost::bind (&Diskstream::handle_input_change, this, _1, _2));
187 input_change_pending = ConfigurationChanged;
188 non_realtime_input_change ();
189 set_align_style_from_io ();
191 _route->Destroyed.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this));
194 void
195 Diskstream::handle_input_change (IOChange change, void * /*src*/)
197 Glib::Mutex::Lock lm (state_lock);
199 if (!(input_change_pending & change)) {
200 input_change_pending = IOChange (input_change_pending|change);
201 _session.request_input_change_handling ();
205 void
206 Diskstream::non_realtime_set_speed ()
208 if (_buffer_reallocation_required)
210 Glib::Mutex::Lock lm (state_lock);
211 allocate_temporary_buffers ();
213 _buffer_reallocation_required = false;
216 if (_seek_required) {
217 if (speed() != 1.0f || speed() != -1.0f) {
218 seek ((nframes_t) (_session.transport_frame() * (double) speed()), true);
220 else {
221 seek (_session.transport_frame(), true);
224 _seek_required = false;
228 bool
229 Diskstream::realtime_set_speed (double sp, bool global)
231 bool changed = false;
232 double new_speed = sp * _session.transport_speed();
234 if (_visible_speed != sp) {
235 _visible_speed = sp;
236 changed = true;
239 if (new_speed != _actual_speed) {
241 nframes_t required_wrap_size = (nframes_t) floor (_session.get_block_size() *
242 fabs (new_speed)) + 1;
244 if (required_wrap_size > wrap_buffer_size) {
245 _buffer_reallocation_required = true;
248 _actual_speed = new_speed;
249 _target_speed = fabs(_actual_speed);
252 if (changed) {
253 if (!global) {
254 _seek_required = true;
256 SpeedChanged (); /* EMIT SIGNAL */
259 return _buffer_reallocation_required || _seek_required;
262 void
263 Diskstream::set_capture_offset ()
265 if (_io == 0) {
266 /* can't capture, so forget it */
267 return;
270 _capture_offset = _io->latency();
273 void
274 Diskstream::set_align_style (AlignStyle a)
276 if (record_enabled() && _session.actively_recording()) {
277 return;
280 if (a != _alignment_style) {
281 _alignment_style = a;
282 AlignmentStyleChanged ();
287 Diskstream::set_loop (Location *location)
289 if (location) {
290 if (location->start() >= location->end()) {
291 error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl;
292 return -1;
296 loop_location = location;
298 LoopSet (location); /* EMIT SIGNAL */
299 return 0;
302 ARDOUR::nframes_t
303 Diskstream::get_capture_start_frame (uint32_t n)
305 Glib::Mutex::Lock lm (capture_info_lock);
307 if (capture_info.size() > n) {
308 return capture_info[n]->start;
310 else {
311 return capture_start_frame;
315 ARDOUR::nframes_t
316 Diskstream::get_captured_frames (uint32_t n)
318 Glib::Mutex::Lock lm (capture_info_lock);
320 if (capture_info.size() > n) {
321 return capture_info[n]->frames;
323 else {
324 return capture_captured;
328 void
329 Diskstream::set_roll_delay (ARDOUR::nframes_t nframes)
331 _roll_delay = nframes;
334 void
335 Diskstream::set_speed (double sp)
337 _session.request_diskstream_speed (*this, sp);
339 /* to force a rebuffering at the right place */
340 playlist_modified();
344 Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
346 if (!playlist) {
347 return;
350 bool no_prior_playlist = true;
353 Glib::Mutex::Lock lm (state_lock);
355 if (playlist == _playlist) {
356 return 0;
359 playlist_connections.drop_connections ();
361 if (_playlist) {
362 _playlist->release();
363 no_prior_playlist = false;
366 _playlist = playlist;
367 _playlist->use();
369 if (!in_set_state && recordable()) {
370 reset_write_sources (false);
373 _playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_modified, this));
374 _playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
375 _playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_ranges_moved, this, _1));
378 /* don't do this if we've already asked for it *or* if we are setting up
379 the diskstream for the very first time - the input changed handling will
380 take care of the buffer refill.
383 if (!overwrite_queued && no_prior_playlist) {
384 _session.request_overwrite_buffer (this);
385 overwrite_queued = true;
388 PlaylistChanged (); /* EMIT SIGNAL */
389 _session.set_dirty ();
391 return 0;
394 void
395 Diskstream::playlist_changed (const PropertyChange&)
397 playlist_modified ();
400 void
401 Diskstream::playlist_modified ()
403 if (!i_am_the_modifier && !overwrite_queued) {
404 _session.request_overwrite_buffer (this);
405 overwrite_queued = true;
409 void
410 Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
412 boost::shared_ptr<Playlist> pl (wpl.lock());
414 if (pl == _playlist) {
416 /* this catches an ordering issue with session destruction. playlists
417 are destroyed before diskstreams. we have to invalidate any handles
418 we have to the playlist.
421 if (_playlist) {
422 _playlist.reset ();
427 bool
428 Diskstream::set_name (const string& str)
430 if (_name != str) {
431 assert(playlist());
432 playlist()->set_name (str);
434 SessionObject::set_name(str);
436 if (!in_set_state && recordable()) {
437 /* rename existing capture files so that they have the correct name */
438 return rename_write_sources ();
439 } else {
440 return false;
444 return true;
447 void
448 Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
450 boost::shared_ptr<Region> region (wregion.lock());
452 if (!region) {
453 return;
456 _last_capture_regions.remove (region);
459 void
460 Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames)
462 if (!_route || Config->get_automation_follows_regions () == false) {
463 return;
466 list< Evoral::RangeMove<double> > movements;
468 for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
469 i != movements_frames.end();
470 ++i) {
472 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
475 /* move panner automation */
476 boost::shared_ptr<Panner> p = _route->main_outs()->panner ();
477 if (p) {
478 for (uint32_t i = 0; i < p->npanners (); ++i) {
479 boost::shared_ptr<AutomationList> pan_alist = p->streampanner(i).pan_control()->alist();
480 XMLNode & before = pan_alist->get_state ();
481 pan_alist->move_ranges (movements);
482 _session.add_command (new MementoCommand<AutomationList> (
483 *pan_alist.get(), &before, &pan_alist->get_state ()));
487 /* move processor automation */
488 _route->foreach_processor (boost::bind (&Diskstream::move_processor_automation, this, _1, movements_frames));
491 void
492 Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, list< Evoral::RangeMove<framepos_t> > const & movements_frames)
494 boost::shared_ptr<Processor> processor (p.lock ());
495 if (!processor) {
496 return;
499 list< Evoral::RangeMove<double> > movements;
500 for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
501 i != movements_frames.end(); ++i) {
502 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
505 set<Evoral::Parameter> const a = processor->what_can_be_automated ();
507 for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
508 boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
509 XMLNode & before = al->get_state ();
510 al->move_ranges (movements);
511 _session.add_command (
512 new MementoCommand<AutomationList> (
513 *al.get(), &before, &al->get_state ()
519 void
520 Diskstream::check_record_status (nframes_t transport_frame, nframes_t /*nframes*/, bool can_record)
522 int possibly_recording;
523 int rolling;
524 int change;
525 const int transport_rolling = 0x4;
526 const int track_rec_enabled = 0x2;
527 const int global_rec_enabled = 0x1;
529 /* merge together the 3 factors that affect record status, and compute
530 what has changed.
533 rolling = _session.transport_speed() != 0.0f;
534 possibly_recording = (rolling << 2) | (record_enabled() << 1) | can_record;
535 change = possibly_recording ^ last_possibly_recording;
537 if (possibly_recording == last_possibly_recording) {
538 return;
541 /* change state */
543 /* if per-track or global rec-enable turned on while the other was already on, we've started recording */
545 if (((change & track_rec_enabled) && record_enabled() && (!(change & global_rec_enabled) && can_record)) ||
546 ((change & global_rec_enabled) && can_record && (!(change & track_rec_enabled) && record_enabled()))) {
548 /* starting to record: compute first+last frames */
550 first_recordable_frame = transport_frame + _capture_offset;
551 last_recordable_frame = max_frames;
552 capture_start_frame = transport_frame;
554 if (!(last_possibly_recording & transport_rolling) && (possibly_recording & transport_rolling)) {
556 /* was stopped, now rolling (and recording) */
558 if (_alignment_style == ExistingMaterial) {
560 first_recordable_frame += _session.worst_output_latency();
562 DEBUG_TRACE (DEBUG::Latency, string_compose ("Offset rec from stop. Capture offset: %1 Worst O/P Latency: %2 Roll Delay: %3 First Recordable Frame: %4 Transport Frame: %5\n",
563 _capture_offset, _session.worst_output_latency(), _roll_delay, first_recordable_frame, transport_frame));
564 } else {
565 first_recordable_frame += _roll_delay;
568 } else {
570 /* was rolling, but record state changed */
572 if (_alignment_style == ExistingMaterial) {
574 /* manual punch in happens at the correct transport frame
575 because the user hit a button. but to get alignment correct
576 we have to back up the position of the new region to the
577 appropriate spot given the roll delay.
581 /* autopunch toggles recording at the precise
582 transport frame, and then the DS waits
583 to start recording for a time that depends
584 on the output latency.
587 first_recordable_frame += _session.worst_output_latency();
589 DEBUG_TRACE (DEBUG::Latency, string_compose ("Punch in manual/auto. Capture offset: %1 Worst O/P Latency: %2 Roll Delay: %3 First Recordable Frame: %4 Transport Frame: %5\n",
590 _capture_offset, _session.worst_output_latency(), _roll_delay, first_recordable_frame, transport_frame));
591 } else {
593 if (_session.config.get_punch_in()) {
594 first_recordable_frame += _roll_delay;
595 } else {
596 capture_start_frame -= _roll_delay;
602 prepare_record_status(capture_start_frame);
604 } else if (!record_enabled() || !can_record) {
606 /* stop recording */
608 last_recordable_frame = transport_frame + _capture_offset;
610 if (_alignment_style == ExistingMaterial) {
611 last_recordable_frame += _session.worst_output_latency();
612 } else {
613 last_recordable_frame += _roll_delay;
616 //first_recordable_frame = max_frames;
618 DEBUG_TRACE (DEBUG::Latency, string_compose ("Stop record - %6 | %7. Capture offset: %1 Worst O/P Latency: %2 Roll Delay: %3 First Recordable Frame: %4 Transport Frame: %5\n",
619 _capture_offset, _session.worst_output_latency(), _roll_delay, first_recordable_frame, transport_frame,
620 can_record, record_enabled()));
623 last_possibly_recording = possibly_recording;
626 void
627 Diskstream::route_going_away ()
629 _io.reset ();
632 void
633 Diskstream::calculate_record_range(OverlapType ot, sframes_t transport_frame, nframes_t nframes,
634 nframes_t& rec_nframes, nframes_t& rec_offset)
636 switch (ot) {
637 case OverlapNone:
638 rec_nframes = 0;
639 break;
641 case OverlapInternal:
642 /* ---------- recrange
643 |---| transrange
645 rec_nframes = nframes;
646 rec_offset = 0;
647 break;
649 case OverlapStart:
650 /* |--------| recrange
651 -----| transrange
653 rec_nframes = transport_frame + nframes - first_recordable_frame;
654 if (rec_nframes) {
655 rec_offset = first_recordable_frame - transport_frame;
657 break;
659 case OverlapEnd:
660 /* |--------| recrange
661 |-------- transrange
663 rec_nframes = last_recordable_frame - transport_frame;
664 rec_offset = 0;
665 break;
667 case OverlapExternal:
668 /* |--------| recrange
669 -------------- transrange
671 rec_nframes = last_recordable_frame - first_recordable_frame;
672 rec_offset = first_recordable_frame - transport_frame;
673 break;