Merge branch 'cairocanvas'
[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
33 #include <glibmm/threads.h>
34
35 #include "pbd/error.h"
36 #include "pbd/basename.h"
37 #include "pbd/memento_command.h"
38 #include "pbd/xml++.h"
39 #include "pbd/stacktrace.h"
40
41 #include "ardour/debug.h"
42 #include "ardour/diskstream.h"
43 #include "ardour/io.h"
44 #include "ardour/pannable.h"
45 #include "ardour/playlist.h"
46 #include "ardour/session.h"
47 #include "ardour/track.h"
48
49 #include "i18n.h"
50 #include <locale.h>
51
52 using namespace std;
53 using namespace ARDOUR;
54 using namespace PBD;
55
56 /* XXX This goes uninitialized when there is no ~/.config/ardour3 directory.
57  * I can't figure out why, so this will do for now (just stole the
58  * default from configuration_vars.h).  0 is not a good value for
59  * allocating buffer sizes..
60  */
61 ARDOUR::framecnt_t Diskstream::disk_io_chunk_frames = 1024 * 256 / sizeof (Sample);
62
63 PBD::Signal0<void>                Diskstream::DiskOverrun;
64 PBD::Signal0<void>                Diskstream::DiskUnderrun;
65
66 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
67         : SessionObject(sess, name)
68         , i_am_the_modifier (0)
69         , _track (0)
70         , _record_enabled (0)
71         , _visible_speed (1.0f)
72         , _actual_speed (1.0f)
73         , _buffer_reallocation_required (false)
74         , _seek_required (false)
75         , capture_start_frame (0)
76         , capture_captured (0)
77         , was_recording (false)
78         , adjust_capture_position (0)
79         , _capture_offset (0)
80         , _roll_delay (0)
81         , first_recordable_frame (max_framepos)
82         , last_recordable_frame (max_framepos)
83         , last_possibly_recording (0)
84         , _alignment_style (ExistingMaterial)
85         , _alignment_choice (Automatic)
86         , _slaved (false)
87         , loop_location (0)
88         , overwrite_frame (0)
89         , overwrite_offset (0)
90         , _pending_overwrite (false)
91         , overwrite_queued (false)
92         , wrap_buffer_size (0)
93         , speed_buffer_size (0)
94         , _speed (1.0)
95         , _target_speed (_speed)
96         , file_frame (0)
97         , playback_sample (0)
98         , in_set_state (false)
99         , _flags (flag)
100         , deprecated_io_node (0)
101 {
102 }
103
104 Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
105         : SessionObject(sess, "unnamed diskstream")
106         , i_am_the_modifier (0)
107         , _track (0)
108         , _record_enabled (0)
109         , _visible_speed (1.0f)
110         , _actual_speed (1.0f)
111         , _buffer_reallocation_required (false)
112         , _seek_required (false)
113         , capture_start_frame (0)
114         , capture_captured (0)
115         , was_recording (false)
116         , adjust_capture_position (0)
117         , _capture_offset (0)
118         , _roll_delay (0)
119         , first_recordable_frame (max_framepos)
120         , last_recordable_frame (max_framepos)
121         , last_possibly_recording (0)
122         , _alignment_style (ExistingMaterial)
123         , _alignment_choice (Automatic)
124         , _slaved (false)
125         , loop_location (0)
126         , overwrite_frame (0)
127         , overwrite_offset (0)
128         , _pending_overwrite (false)
129         , overwrite_queued (false)
130         , wrap_buffer_size (0)
131         , speed_buffer_size (0)
132         , _speed (1.0)
133         , _target_speed (_speed)
134         , file_frame (0)
135         , playback_sample (0)
136         , in_set_state (false)
137         , _flags (Recordable)
138         , deprecated_io_node (0)
139 {
140 }
141
142 Diskstream::~Diskstream ()
143 {
144         DEBUG_TRACE (DEBUG::Destruction, string_compose ("Diskstream %1 deleted\n", _name));
145
146         if (_playlist) {
147                 _playlist->release ();
148         }
149
150         delete deprecated_io_node;
151 }
152
153 void
154 Diskstream::set_track (Track* t)
155 {
156         _track = t;
157         _io = _track->input();
158
159         ic_connection.disconnect();
160         _io->changed.connect_same_thread (ic_connection, boost::bind (&Diskstream::handle_input_change, this, _1, _2));
161
162         if (_io->n_ports() != ChanCount::ZERO) {
163                 input_change_pending.type = IOChange::Type (IOChange::ConfigurationChanged|IOChange::ConnectionsChanged);
164                 non_realtime_input_change ();
165         }
166
167         _track->Destroyed.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this));
168 }
169
170 void
171 Diskstream::handle_input_change (IOChange change, void * /*src*/)
172 {
173         Glib::Threads::Mutex::Lock lm (state_lock);
174
175         if (change.type & (IOChange::ConfigurationChanged|IOChange::ConnectionsChanged)) {
176
177                 /* rather than handle this here on a DS-by-DS basis we defer to the
178                    session transport/butler thread, and let it tackle
179                    as many diskstreams as need it in one shot. this avoids many repeated
180                    takings of the audioengine process lock.
181                 */
182
183                 if (!(input_change_pending.type & change.type)) {
184                         input_change_pending.type = IOChange::Type (input_change_pending.type | change.type);
185                         _session.request_input_change_handling ();
186                 }
187         }
188 }
189
190 void
191 Diskstream::non_realtime_set_speed ()
192 {
193         if (_buffer_reallocation_required)
194         {
195                 Glib::Threads::Mutex::Lock lm (state_lock);
196                 allocate_temporary_buffers ();
197
198                 _buffer_reallocation_required = false;
199         }
200
201         if (_seek_required) {
202                 if (speed() != 1.0f || speed() != -1.0f) {
203                         seek ((framepos_t) (_session.transport_frame() * (double) speed()), true);
204                 }
205                 else {
206                         seek (_session.transport_frame(), true);
207                 }
208
209                 _seek_required = false;
210         }
211 }
212
213 bool
214 Diskstream::realtime_set_speed (double sp, bool global)
215 {
216         bool changed = false;
217         double new_speed = sp * _session.transport_speed();
218
219         if (_visible_speed != sp) {
220                 _visible_speed = sp;
221                 changed = true;
222         }
223
224         if (new_speed != _actual_speed) {
225
226                 framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() *
227                                                                   fabs (new_speed)) + 2;
228
229                 if (required_wrap_size > wrap_buffer_size) {
230                         _buffer_reallocation_required = true;
231                 }
232
233                 _actual_speed = new_speed;
234                 _target_speed = fabs(_actual_speed);
235         }
236
237         if (changed) {
238                 if (!global) {
239                         _seek_required = true;
240                 }
241                 SpeedChanged (); /* EMIT SIGNAL */
242         }
243
244         return _buffer_reallocation_required || _seek_required;
245 }
246
247 void
248 Diskstream::set_capture_offset ()
249 {
250         if (_io == 0) {
251                 /* can't capture, so forget it */
252                 return;
253         }
254
255         switch (_alignment_style) {
256         case ExistingMaterial:
257                 _capture_offset = _io->latency();
258                 break;
259
260         case CaptureTime:
261         default:
262                 _capture_offset = 0;
263                 break;
264         }
265
266         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: using IO latency, capture offset set to %2 with style = %3\n", name(), _capture_offset, enum_2_string (_alignment_style)));
267 }
268
269
270 void
271 Diskstream::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                 set_capture_offset ();
280                 AlignmentStyleChanged ();
281         }
282 }
283
284 void
285 Diskstream::set_align_choice (AlignChoice a, bool force)
286 {
287         if (record_enabled() && _session.actively_recording()) {
288                 return;
289         }
290
291         if ((a != _alignment_choice) || force) {
292                 _alignment_choice = a;
293
294                 switch (_alignment_choice) {
295                         case Automatic:
296                                 set_align_style_from_io ();
297                                 break;
298                         case UseExistingMaterial:
299                                 set_align_style (ExistingMaterial);
300                                 break;
301                         case UseCaptureTime:
302                                 set_align_style (CaptureTime);
303                                 break;
304                 }
305         }
306 }
307
308 int
309 Diskstream::set_loop (Location *location)
310 {
311         if (location) {
312                 if (location->start() >= location->end()) {
313                         error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl;
314                         return -1;
315                 }
316         }
317
318         loop_location = location;
319
320         LoopSet (location); /* EMIT SIGNAL */
321         return 0;
322 }
323
324 /** Get the start position (in session frames) of the nth capture in the current pass */
325 ARDOUR::framepos_t
326 Diskstream::get_capture_start_frame (uint32_t n) const
327 {
328         Glib::Threads::Mutex::Lock lm (capture_info_lock);
329
330         if (capture_info.size() > n) {
331                 /* this is a completed capture */
332                 return capture_info[n]->start;
333         } else {
334                 /* this is the currently in-progress capture */
335                 return capture_start_frame;
336         }
337 }
338
339 ARDOUR::framecnt_t
340 Diskstream::get_captured_frames (uint32_t n) const
341 {
342         Glib::Threads::Mutex::Lock lm (capture_info_lock);
343
344         if (capture_info.size() > n) {
345                 /* this is a completed capture */
346                 return capture_info[n]->frames;
347         } else {
348                 /* this is the currently in-progress capture */
349                 return capture_captured;
350         }
351 }
352
353 void
354 Diskstream::set_roll_delay (ARDOUR::framecnt_t nframes)
355 {
356         _roll_delay = nframes;
357 }
358
359 int
360 Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
361 {
362         if (!playlist) {
363                 return 0;
364         }
365
366         bool prior_playlist = false;
367
368         {
369                 Glib::Threads::Mutex::Lock lm (state_lock);
370
371                 if (playlist == _playlist) {
372                         return 0;
373                 }
374
375                 playlist_connections.drop_connections ();
376
377                 if (_playlist) {
378                         _playlist->release();
379                         prior_playlist = true;
380                 }
381
382                 _playlist = playlist;
383                 _playlist->use();
384
385                 if (!in_set_state && recordable()) {
386                         reset_write_sources (false);
387                 }
388
389                 _playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_modified, this));
390                 _playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
391                 _playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_ranges_moved, this, _1, _2));
392         }
393
394         /* don't do this if we've already asked for it *or* if we are setting up
395            the diskstream for the very first time - the input changed handling will
396            take care of the buffer refill.
397         */
398
399         if (!overwrite_queued && prior_playlist) {
400                 _session.request_overwrite_buffer (_track);
401                 overwrite_queued = true;
402         }
403
404         PlaylistChanged (); /* EMIT SIGNAL */
405         _session.set_dirty ();
406
407         return 0;
408 }
409
410 void
411 Diskstream::playlist_changed (const PropertyChange&)
412 {
413         playlist_modified ();
414 }
415
416 void
417 Diskstream::playlist_modified ()
418 {
419         if (!i_am_the_modifier && !overwrite_queued) {
420                 _session.request_overwrite_buffer (_track);
421                 overwrite_queued = true;
422         }
423 }
424
425 void
426 Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
427 {
428         boost::shared_ptr<Playlist> pl (wpl.lock());
429
430         if (pl == _playlist) {
431
432                 /* this catches an ordering issue with session destruction. playlists
433                    are destroyed before diskstreams. we have to invalidate any handles
434                    we have to the playlist.
435                 */
436
437                 if (_playlist) {
438                         _playlist.reset ();
439                 }
440         }
441 }
442
443 bool
444 Diskstream::set_name (const string& str)
445 {
446         if (_name != str) {
447                 assert(playlist());
448                 playlist()->set_name (str);
449                 SessionObject::set_name(str);
450         }
451         return true;
452 }
453
454 bool
455 Diskstream::set_write_source_name (const std::string& str) {
456         _write_source_name = str;
457         return true;
458 }
459
460 XMLNode&
461 Diskstream::get_state ()
462 {
463         XMLNode* node = new XMLNode ("Diskstream");
464         char buf[64];
465         LocaleGuard lg (X_("POSIX"));
466
467         node->add_property ("flags", enum_2_string (_flags));
468         node->add_property ("playlist", _playlist->name());
469         node->add_property("name", _name);
470         id().print (buf, sizeof (buf));
471         node->add_property("id", buf);
472         snprintf (buf, sizeof(buf), "%f", _visible_speed);
473         node->add_property ("speed", buf);
474         node->add_property ("capture-alignment", enum_2_string (_alignment_choice));
475
476         if (_extra_xml) {
477                 node->add_child_copy (*_extra_xml);
478         }
479
480         return *node;
481 }
482
483 int
484 Diskstream::set_state (const XMLNode& node, int /*version*/)
485 {
486         const XMLProperty* prop;
487
488         if ((prop = node.property ("name")) != 0) {
489                 _name = prop->value();
490         }
491
492         if (deprecated_io_node) {
493                 set_id (*deprecated_io_node);
494         } else {
495                 set_id (node);
496         }
497
498         if ((prop = node.property ("flags")) != 0) {
499                 _flags = Flag (string_2_enum (prop->value(), _flags));
500         }
501
502         if ((prop = node.property (X_("capture-alignment"))) != 0) {
503                 set_align_choice (AlignChoice (string_2_enum (prop->value(), _alignment_choice)), true);
504         } else {
505                 set_align_choice (Automatic, true);
506         }
507
508         if ((prop = node.property ("playlist")) == 0) {
509                 return -1;
510         }
511
512         if (find_and_use_playlist (prop->value())) {
513                 return -1;
514         }
515
516         if ((prop = node.property ("speed")) != 0) {
517                 double sp = atof (prop->value().c_str());
518
519                 if (realtime_set_speed (sp, false)) {
520                         non_realtime_set_speed ();
521                 }
522         }
523
524         return 0;
525 }
526
527 void
528 Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames, bool from_undo)
529 {
530         /* If we're coming from an undo, it will have handled
531            automation undo (it must, since automation-follows-regions
532            can lose automation data).  Hence we can do nothing here.
533         */
534
535         if (from_undo) {
536                 return;
537         }
538
539         if (!_track || Config->get_automation_follows_regions () == false) {
540                 return;
541         }
542
543         list< Evoral::RangeMove<double> > movements;
544
545         for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
546              i != movements_frames.end();
547              ++i) {
548
549                 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
550         }
551
552         /* move panner automation */
553         boost::shared_ptr<Pannable> pannable = _track->pannable();
554         Evoral::ControlSet::Controls& c (pannable->controls());
555
556         for (Evoral::ControlSet::Controls::iterator ci = c.begin(); ci != c.end(); ++ci) {
557                 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl>(ci->second);
558                 if (!ac) {
559                         continue;
560                 }
561                 boost::shared_ptr<AutomationList> alist = ac->alist();
562
563                 XMLNode & before = alist->get_state ();
564                 bool const things_moved = alist->move_ranges (movements);
565                 if (things_moved) {
566                         _session.add_command (new MementoCommand<AutomationList> (
567                                                       *alist.get(), &before, &alist->get_state ()));
568                 }
569         }
570
571         /* move processor automation */
572         _track->foreach_processor (boost::bind (&Diskstream::move_processor_automation, this, _1, movements_frames));
573 }
574
575 void
576 Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, list< Evoral::RangeMove<framepos_t> > const & movements_frames)
577 {
578         boost::shared_ptr<Processor> processor (p.lock ());
579         if (!processor) {
580                 return;
581         }
582
583         list< Evoral::RangeMove<double> > movements;
584         for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin(); i != movements_frames.end(); ++i) {
585                 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
586         }
587
588         set<Evoral::Parameter> const a = processor->what_can_be_automated ();
589
590         for (set<Evoral::Parameter>::const_iterator i = a.begin (); i != a.end (); ++i) {
591                 boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
592                 XMLNode & before = al->get_state ();
593                 bool const things_moved = al->move_ranges (movements);
594                 if (things_moved) {
595                         _session.add_command (
596                                 new MementoCommand<AutomationList> (
597                                         *al.get(), &before, &al->get_state ()
598                                         )
599                                 );
600                 }
601         }
602 }
603
604 void
605 Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
606 {
607         int possibly_recording;
608         int rolling;
609         int change;
610         const int transport_rolling = 0x4;
611         const int track_rec_enabled = 0x2;
612         const int global_rec_enabled = 0x1;
613         const int fully_rec_enabled = (transport_rolling|track_rec_enabled|global_rec_enabled);
614
615         /* merge together the 3 factors that affect record status, and compute
616          * what has changed.
617          */
618
619         rolling = _session.transport_speed() != 0.0f;
620         possibly_recording = (rolling << 2) | ((int)record_enabled() << 1) | (int)can_record;
621         change = possibly_recording ^ last_possibly_recording;
622
623         if (possibly_recording == last_possibly_recording) {
624                 return;
625         }
626
627         const framecnt_t existing_material_offset = _session.worst_playback_latency();
628
629         if (possibly_recording == fully_rec_enabled) {
630
631                 if (last_possibly_recording == fully_rec_enabled) {
632                         return;
633                 }
634
635                 capture_start_frame = _session.transport_frame();
636                 first_recordable_frame = capture_start_frame + _capture_offset;
637                 last_recordable_frame = max_framepos;
638
639                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 (%9) FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8 WOL %10 WTL %11\n",
640                                                                       name(), first_recordable_frame, last_recordable_frame, capture_start_frame,
641                                                                       _capture_offset,
642                                                                       existing_material_offset,
643                                                                       transport_frame,
644                                                                       _roll_delay,
645                                                                       _session.transport_frame(),
646                                                                       _session.worst_output_latency(),
647                                                                       _session.worst_track_latency()));
648
649
650                 if (_alignment_style == ExistingMaterial) {
651                         first_recordable_frame += existing_material_offset;
652                         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift FRF by EMO %1\n",
653                                                                               first_recordable_frame));
654                 }
655
656                 prepare_record_status (capture_start_frame);
657
658         } else {
659
660                 if (last_possibly_recording == fully_rec_enabled) {
661
662                         /* we were recording last time */
663
664                         if (change & transport_rolling) {
665
666                                 /* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop(). We
667                                  * had to set it there because we likely rolled past the stopping point to declick out,
668                                  * and then backed up.
669                                  */
670
671                         } else {
672                                 /* punch out */
673
674                                 last_recordable_frame = _session.transport_frame() + _capture_offset;
675
676                                 if (_alignment_style == ExistingMaterial) {
677                                         last_recordable_frame += existing_material_offset;
678                                 }
679                         }
680                 }
681         }
682
683         last_possibly_recording = possibly_recording;
684 }
685
686 void
687 Diskstream::route_going_away ()
688 {
689         _io.reset ();
690 }
691
692 void
693 Diskstream::calculate_record_range (Evoral::OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
694                                     framecnt_t & rec_nframes, framecnt_t & rec_offset)
695 {
696         switch (ot) {
697         case Evoral::OverlapNone:
698                 rec_nframes = 0;
699                 break;
700
701         case Evoral::OverlapInternal:
702                 /*     ----------    recrange
703                          |---|       transrange
704                 */
705                 rec_nframes = nframes;
706                 rec_offset = 0;
707                 break;
708
709         case Evoral::OverlapStart:
710                 /*    |--------|    recrange
711                 -----|          transrange
712                 */
713                 rec_nframes = transport_frame + nframes - first_recordable_frame;
714                 if (rec_nframes) {
715                         rec_offset = first_recordable_frame - transport_frame;
716                 }
717                 break;
718
719         case Evoral::OverlapEnd:
720                 /*    |--------|    recrange
721                          |--------  transrange
722                 */
723                 rec_nframes = last_recordable_frame - transport_frame;
724                 rec_offset = 0;
725                 break;
726
727         case Evoral::OverlapExternal:
728                 /*    |--------|    recrange
729                     --------------  transrange
730                 */
731                 rec_nframes = last_recordable_frame - first_recordable_frame;
732                 rec_offset = first_recordable_frame - transport_frame;
733                 break;
734         }
735
736         DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n",
737                                                               _name, enum_2_string (ot), transport_frame, nframes,
738                                                               first_recordable_frame, last_recordable_frame, rec_nframes, rec_offset));
739 }
740
741 void
742 Diskstream::prepare_to_stop (framepos_t transport_frame, framepos_t audible_frame)
743 {
744         switch (_alignment_style) {
745         case ExistingMaterial:
746                 last_recordable_frame = transport_frame + _capture_offset;
747                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable frame to %2 + %3 = %4\n", _name, transport_frame, _capture_offset, last_recordable_frame));
748                 break;
749
750         case CaptureTime:
751                 last_recordable_frame = audible_frame; // note that capture_offset is zero
752                 /* we may already have captured audio before the last_recordable_frame (audible frame),
753                    so deal with this.
754                 */
755                 if (last_recordable_frame > capture_start_frame) {
756                         capture_captured = min (capture_captured, last_recordable_frame - capture_start_frame);
757                 }
758                 DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable frame to audible frame @ %2\n", _name, audible_frame));
759                 break;
760         }
761
762 }
763
764 void
765 Diskstream::engage_record_enable ()
766 {
767         g_atomic_int_set (&_record_enabled, 1);
768 }
769
770 void
771 Diskstream::disengage_record_enable ()
772 {
773         g_atomic_int_set (&_record_enabled, 0);
774 }