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