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