remove (or attempt to remove) requirement for holding process lock when changing...
[ardour.git] / libs / ardour / diskstream.cc
1 /*
2     Copyright (C) 2000-2006 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 <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>
33
34
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"
40
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/track.h"
56
57 #include "i18n.h"
58 #include <locale.h>
59
60 using namespace std;
61 using namespace ARDOUR;
62 using namespace PBD;
63
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..
68  */
69 ARDOUR::nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
70
71 PBD::Signal0<void>                Diskstream::DiskOverrun;
72 PBD::Signal0<void>                Diskstream::DiskUnderrun;
73
74 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
75         : SessionObject(sess, name)
76         , i_am_the_modifier (0)
77         , _track (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_framepos)
91         , last_recordable_frame (max_framepos)
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         , wrap_buffer_size (0)
102         , speed_buffer_size (0)
103         , _speed (1.0)
104         , _target_speed (_speed)
105         , file_frame (0)
106         , playback_sample (0)
107         , playback_distance (0)
108         , _read_data_count (0)
109         , _write_data_count (0)
110         , in_set_state (false)
111         , _persistent_alignment_style (ExistingMaterial)
112         , first_input_change (true)
113         , scrub_start (0)
114         , scrub_buffer_size (0)
115         , scrub_offset (0)
116         , _flags (flag)
117
118 {
119 }
120
121 Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
122         : SessionObject(sess, "unnamed diskstream")
123         , i_am_the_modifier (0)
124         , _track (0)
125         , _record_enabled (0)
126         , _visible_speed (1.0f)
127         , _actual_speed (1.0f)
128         , _buffer_reallocation_required (false)
129         , _seek_required (false)
130         , force_refill (false)
131         , capture_start_frame (0)
132         , capture_captured (0)
133         , was_recording (false)
134         , adjust_capture_position (0)
135         , _capture_offset (0)
136         , _roll_delay (0)
137         , first_recordable_frame (max_framepos)
138         , last_recordable_frame (max_framepos)
139         , last_possibly_recording (0)
140         , _alignment_style (ExistingMaterial)
141         , _scrubbing (false)
142         , _slaved (false)
143         , loop_location (0)
144         , overwrite_frame (0)
145         , overwrite_offset (0)
146         , _pending_overwrite (false)
147         , overwrite_queued (false)
148         , wrap_buffer_size (0)
149         , speed_buffer_size (0)
150         , _speed (1.0)
151         , _target_speed (_speed)
152         , file_frame (0)
153         , playback_sample (0)
154         , playback_distance (0)
155         , _read_data_count (0)
156         , _write_data_count (0)
157         , in_set_state (false)
158         , _persistent_alignment_style (ExistingMaterial)
159         , first_input_change (true)
160         , scrub_start (0)
161         , scrub_buffer_size (0)
162         , scrub_offset (0)
163         , _flags (Recordable)
164 {
165 }
166
167 Diskstream::~Diskstream ()
168 {
169         DEBUG_TRACE (DEBUG::Destruction, string_compose ("Diskstream %1 deleted\n", _name));
170
171         if (_playlist) {
172                 _playlist->release ();
173         }
174 }
175
176 void
177 Diskstream::set_track (Track* t)
178 {
179         _track = t;
180         _io = _track->input();
181
182         ic_connection.disconnect();
183         _io->changed.connect_same_thread (ic_connection, boost::bind (&Diskstream::handle_input_change, this, _1, _2));
184
185         input_change_pending = IOChange::ConfigurationChanged;
186         non_realtime_input_change ();
187         set_align_style_from_io ();
188
189         _track->Destroyed.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this));
190 }
191
192 void
193 Diskstream::handle_input_change (IOChange change, void * /*src*/)
194 {
195         Glib::Mutex::Lock lm (state_lock);
196
197         if (change.type & IOChange::ConfigurationChanged) {
198                 if (!(input_change_pending.type & change.type)) {
199                         input_change_pending.type = IOChange::Type (input_change_pending.type | change.type);
200                         _session.request_input_change_handling ();
201                 }
202         }
203 }
204
205 void
206 Diskstream::non_realtime_set_speed ()
207 {
208         if (_buffer_reallocation_required)
209         {
210                 Glib::Mutex::Lock lm (state_lock);
211                 allocate_temporary_buffers ();
212
213                 _buffer_reallocation_required = false;
214         }
215
216         if (_seek_required) {
217                 if (speed() != 1.0f || speed() != -1.0f) {
218                         seek ((framepos_t) (_session.transport_frame() * (double) speed()), true);
219                 }
220                 else {
221                         seek (_session.transport_frame(), true);
222                 }
223
224                 _seek_required = false;
225         }
226 }
227
228 bool
229 Diskstream::realtime_set_speed (double sp, bool global)
230 {
231         bool changed = false;
232         double new_speed = sp * _session.transport_speed();
233
234         if (_visible_speed != sp) {
235                 _visible_speed = sp;
236                 changed = true;
237         }
238
239         if (new_speed != _actual_speed) {
240
241                 nframes_t required_wrap_size = (nframes_t) floor (_session.get_block_size() *
242                                                                   fabs (new_speed)) + 1;
243
244                 if (required_wrap_size > wrap_buffer_size) {
245                         _buffer_reallocation_required = true;
246                 }
247
248                 _actual_speed = new_speed;
249                 _target_speed = fabs(_actual_speed);
250         }
251
252         if (changed) {
253                 if (!global) {
254                         _seek_required = true;
255                 }
256                 SpeedChanged (); /* EMIT SIGNAL */
257         }
258
259         return _buffer_reallocation_required || _seek_required;
260 }
261
262 void
263 Diskstream::set_capture_offset ()
264 {
265         if (_io == 0) {
266                 /* can't capture, so forget it */
267                 return;
268         }
269
270         _capture_offset = _io->latency();
271 }
272
273 void
274 Diskstream::set_align_style (AlignStyle a)
275 {
276         if (record_enabled() && _session.actively_recording()) {
277                 return;
278         }
279
280         if (a != _alignment_style) {
281                 _alignment_style = a;
282                 AlignmentStyleChanged ();
283         }
284 }
285
286 int
287 Diskstream::set_loop (Location *location)
288 {
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;
293                 }
294         }
295
296         loop_location = location;
297
298         LoopSet (location); /* EMIT SIGNAL */
299         return 0;
300 }
301
302 /** Get the start position (in session frames) of the nth capture in the current pass */
303 ARDOUR::framepos_t
304 Diskstream::get_capture_start_frame (uint32_t n) const
305 {
306         Glib::Mutex::Lock lm (capture_info_lock);
307
308         if (capture_info.size() > n) {
309                 /* this is a completed capture */
310                 return capture_info[n]->start;
311         } else {
312                 /* this is the currently in-progress capture */
313                 return capture_start_frame;
314         }
315 }
316
317 ARDOUR::framecnt_t
318 Diskstream::get_captured_frames (uint32_t n) const
319 {
320         Glib::Mutex::Lock lm (capture_info_lock);
321
322         if (capture_info.size() > n) {
323                 /* this is a completed capture */
324                 return capture_info[n]->frames;
325         } else {  
326                 /* this is the currently in-progress capture */
327                 return capture_captured;
328         }
329 }
330
331 void
332 Diskstream::set_roll_delay (ARDOUR::nframes_t nframes)
333 {
334         _roll_delay = nframes;
335 }
336
337 int
338 Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
339 {
340         if (!playlist) {
341                 return 0;
342         }
343
344         bool prior_playlist = false;
345
346         {
347                 Glib::Mutex::Lock lm (state_lock);
348
349                 if (playlist == _playlist) {
350                         return 0;
351                 }
352
353                 playlist_connections.drop_connections ();
354
355                 if (_playlist) {
356                         _playlist->release();
357                         prior_playlist = true;
358                 }
359
360                 _playlist = playlist;
361                 _playlist->use();
362
363                 if (!in_set_state && recordable()) {
364                         reset_write_sources (false);
365                 }
366
367                 _playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_modified, this));
368                 _playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
369                 _playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_ranges_moved, this, _1, _2));
370         }
371
372         /* don't do this if we've already asked for it *or* if we are setting up
373            the diskstream for the very first time - the input changed handling will
374            take care of the buffer refill.
375         */
376
377         if (!overwrite_queued && prior_playlist) {
378                 _session.request_overwrite_buffer (_track);
379                 overwrite_queued = true;
380         }
381
382         PlaylistChanged (); /* EMIT SIGNAL */
383         _session.set_dirty ();
384
385         return 0;
386 }
387
388 void
389 Diskstream::playlist_changed (const PropertyChange&)
390 {
391         playlist_modified ();
392 }
393
394 void
395 Diskstream::playlist_modified ()
396 {
397         if (!i_am_the_modifier && !overwrite_queued) {
398                 _session.request_overwrite_buffer (_track);
399                 overwrite_queued = true;
400         }
401 }
402
403 void
404 Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
405 {
406         boost::shared_ptr<Playlist> pl (wpl.lock());
407
408         if (pl == _playlist) {
409
410                 /* this catches an ordering issue with session destruction. playlists
411                    are destroyed before diskstreams. we have to invalidate any handles
412                    we have to the playlist.
413                 */
414
415                 if (_playlist) {
416                         _playlist.reset ();
417                 }
418         }
419 }
420
421 bool
422 Diskstream::set_name (const string& str)
423 {
424         if (_name != str) {
425                 assert(playlist());
426                 playlist()->set_name (str);
427
428                 SessionObject::set_name(str);
429
430                 if (!in_set_state && recordable()) {
431                         /* rename existing capture files so that they have the correct name */
432                         return rename_write_sources ();
433                 } else {
434                         return false;
435                 }
436         }
437
438         return true;
439 }
440
441 void
442 Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames, bool from_undo)
443 {
444         /* If we're coming from an undo, it will have handled
445            automation undo (it must, since automation-follows-regions
446            can lose automation data).  Hence we can do nothing here.
447         */
448         
449         if (from_undo) {
450                 return;
451         }
452         
453         if (!_track || Config->get_automation_follows_regions () == false) {
454                 return;
455         }
456
457         list< Evoral::RangeMove<double> > movements;
458
459         for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
460              i != movements_frames.end();
461              ++i) {
462
463                 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
464         }
465
466         /* move panner automation */
467         boost::shared_ptr<Panner> p = _track->main_outs()->panner ();
468         if (p) {
469                 for (uint32_t i = 0; i < p->npanners (); ++i) {
470                         boost::shared_ptr<AutomationList> pan_alist = p->streampanner(i).pan_control()->alist();
471                         XMLNode & before = pan_alist->get_state ();
472                         bool const things_moved = pan_alist->move_ranges (movements);
473                         if (things_moved) {
474                                 _session.add_command (new MementoCommand<AutomationList> (
475                                                               *pan_alist.get(), &before, &pan_alist->get_state ()));
476                         }
477                 }
478         }
479
480         /* move processor automation */
481         _track->foreach_processor (boost::bind (&Diskstream::move_processor_automation, this, _1, movements_frames));
482 }
483
484 void
485 Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, list< Evoral::RangeMove<framepos_t> > const & movements_frames)
486 {
487         boost::shared_ptr<Processor> processor (p.lock ());
488         if (!processor) {
489                 return;
490         }
491
492         list< Evoral::RangeMove<double> > movements;
493         for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin(); i != movements_frames.end(); ++i) {
494                 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
495         }
496
497         set<Evoral::Parameter> const a = processor->what_can_be_automated ();
498
499         for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
500                 boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
501                 XMLNode & before = al->get_state ();
502                 bool const things_moved = al->move_ranges (movements);
503                 if (things_moved) {
504                         _session.add_command (
505                                 new MementoCommand<AutomationList> (
506                                         *al.get(), &before, &al->get_state ()
507                                         )
508                                 );
509                 }
510         }
511 }
512
513 void
514 Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
515 {
516         int possibly_recording;
517         int rolling;
518         int change;
519         const int transport_rolling = 0x4;
520         const int track_rec_enabled = 0x2;
521         const int global_rec_enabled = 0x1;
522         const int fully_rec_enabled = (transport_rolling|track_rec_enabled|global_rec_enabled);
523
524         /* merge together the 3 factors that affect record status, and compute
525            what has changed.
526         */
527
528         rolling = _session.transport_speed() != 0.0f;
529         possibly_recording = (rolling << 2) | (record_enabled() << 1) | can_record;
530         change = possibly_recording ^ last_possibly_recording;
531
532         if (possibly_recording == last_possibly_recording) {
533                 return;
534         }
535         if (possibly_recording == fully_rec_enabled) {
536
537                 if (last_possibly_recording == fully_rec_enabled) {
538                         return;
539                 }
540
541                 /* we transitioned to recording. lets see if its transport based or a punch */
542                 
543                 first_recordable_frame = transport_frame + _capture_offset;
544                 last_recordable_frame = max_framepos;
545                 capture_start_frame = transport_frame;
546
547                 if (change & transport_rolling) {
548
549                         /* transport-change (started rolling) */
550                         
551                         if (_alignment_style == ExistingMaterial) {
552                                 
553                                 /* there are two delays happening:
554                                    
555                                    1) inbound, represented by _capture_offset
556                                    2) outbound, represented by _session.worst_output_latency()
557
558                                    the first sample to record occurs when the larger of these
559                                    two has elapsed, since they occur in parallel.
560
561                                    since we've already added _capture_offset, just add the
562                                    difference if _session.worst_output_latency() is larger.
563                                 */
564
565                                 if (_capture_offset < _session.worst_output_latency()) {
566                                         first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
567                                 } 
568                         } else {
569                                 first_recordable_frame += _roll_delay;
570                         }
571                         
572                 } else {
573
574                         /* punch in */
575
576                         if (_alignment_style == ExistingMaterial) {
577
578                                 /* There are two kinds of punch:
579                                    
580                                    manual punch in happens at the correct transport frame
581                                    because the user hit a button. but to get alignment correct 
582                                    we have to back up the position of the new region to the 
583                                    appropriate spot given the roll delay.
584
585                                    autopunch toggles recording at the precise
586                                    transport frame, and then the DS waits
587                                    to start recording for a time that depends
588                                    on the output latency.
589
590                                    XXX: BUT THIS CODE DOESN'T DIFFERENTIATE !!!
591
592                                 */
593
594                                 if (_capture_offset < _session.worst_output_latency()) {
595                                         /* see comment in ExistingMaterial block above */
596                                         first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
597                                 }
598
599                         } else {
600                                 capture_start_frame -= _roll_delay;
601                         }
602                 }
603                 
604                 prepare_record_status (capture_start_frame);
605
606         } else {
607
608                 if (last_possibly_recording == fully_rec_enabled) {
609
610                         /* we were recording last time */
611                         
612                         if (change & transport_rolling) {
613                                 /* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop() */
614                                 
615                         } else {
616                                 /* punch out */
617                                 
618                                 last_recordable_frame = transport_frame + _capture_offset;
619                                 
620                                 if (_alignment_style == ExistingMaterial) {
621                                         if (_session.worst_output_latency() > _capture_offset) {
622                                                 last_recordable_frame += (_session.worst_output_latency() - _capture_offset);
623                                         }
624                                 } else {
625                                         last_recordable_frame += _roll_delay;
626                                 }
627                         }
628                 }
629         }
630
631         last_possibly_recording = possibly_recording;
632 }
633
634 void
635 Diskstream::route_going_away ()
636 {
637         _io.reset ();
638 }
639
640 void
641 Diskstream::calculate_record_range(OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
642                                    nframes_t& rec_nframes, nframes_t& rec_offset)
643 {
644         switch (ot) {
645         case OverlapNone:
646                 rec_nframes = 0;
647                 break;
648
649         case OverlapInternal:
650                 /*     ----------    recrange
651                          |---|       transrange
652                 */
653                 rec_nframes = nframes;
654                 rec_offset = 0;
655                 break;
656
657         case OverlapStart:
658                 /*    |--------|    recrange
659                 -----|          transrange
660                 */
661                 rec_nframes = transport_frame + nframes - first_recordable_frame;
662                 if (rec_nframes) {
663                         rec_offset = first_recordable_frame - transport_frame;
664                 }
665                 break;
666
667         case OverlapEnd:
668                 /*    |--------|    recrange
669                          |--------  transrange
670                 */
671                 rec_nframes = last_recordable_frame - transport_frame;
672                 rec_offset = 0;
673                 break;
674
675         case OverlapExternal:
676                 /*    |--------|    recrange
677                     --------------  transrange
678                 */
679                 rec_nframes = last_recordable_frame - first_recordable_frame;
680                 rec_offset = first_recordable_frame - transport_frame;
681                 break;
682         }
683 }
684
685 void
686 Diskstream::prepare_to_stop (framepos_t pos)
687 {
688         last_recordable_frame = pos + _capture_offset;
689 }