2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 #include "pbd/error.h"
36 #include "pbd/basename.h"
37 #include <glibmm/thread.h>
38 #include "pbd/xml++.h"
39 #include "pbd/memento_command.h"
41 #include "ardour/ardour.h"
42 #include "ardour/audioengine.h"
43 #include "ardour/debug.h"
44 #include "ardour/diskstream.h"
45 #include "ardour/utils.h"
46 #include "ardour/configuration.h"
47 #include "ardour/audiofilesource.h"
48 #include "ardour/send.h"
49 #include "ardour/playlist.h"
50 #include "ardour/cycle_timer.h"
51 #include "ardour/region.h"
52 #include "ardour/panner.h"
53 #include "ardour/session.h"
54 #include "ardour/io.h"
55 #include "ardour/track.h"
61 using namespace ARDOUR;
64 /* XXX This goes uninitialized when there is no ~/.config/ardour3 directory.
65 * I can't figure out why, so this will do for now (just stole the
66 * default from configuration_vars.h). 0 is not a good value for
67 * allocating buffer sizes..
69 ARDOUR::nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
71 PBD::Signal0<void> Diskstream::DiskOverrun;
72 PBD::Signal0<void> Diskstream::DiskUnderrun;
74 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
75 : SessionObject(sess, name)
76 , i_am_the_modifier (0)
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)
90 , first_recordable_frame (max_frames)
91 , last_recordable_frame (max_frames)
92 , last_possibly_recording (0)
93 , _alignment_style (ExistingMaterial)
98 , overwrite_offset (0)
99 , _pending_overwrite (false)
100 , overwrite_queued (false)
101 , input_change_pending (NoChange)
102 , wrap_buffer_size (0)
103 , speed_buffer_size (0)
105 , _target_speed (_speed)
107 , playback_sample (0)
108 , playback_distance (0)
109 , _read_data_count (0)
110 , _write_data_count (0)
111 , in_set_state (false)
112 , _persistent_alignment_style (ExistingMaterial)
113 , first_input_change (true)
115 , scrub_buffer_size (0)
122 Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/)
123 : SessionObject(sess, "unnamed diskstream")
124 , i_am_the_modifier (0)
126 , _record_enabled (0)
127 , _visible_speed (1.0f)
128 , _actual_speed (1.0f)
129 , _buffer_reallocation_required (false)
130 , _seek_required (false)
131 , force_refill (false)
132 , capture_start_frame (0)
133 , capture_captured (0)
134 , was_recording (false)
135 , adjust_capture_position (0)
136 , _capture_offset (0)
138 , first_recordable_frame (max_frames)
139 , last_recordable_frame (max_frames)
140 , last_possibly_recording (0)
141 , _alignment_style (ExistingMaterial)
145 , overwrite_frame (0)
146 , overwrite_offset (0)
147 , _pending_overwrite (false)
148 , overwrite_queued (false)
149 , input_change_pending (NoChange)
150 , wrap_buffer_size (0)
151 , speed_buffer_size (0)
153 , _target_speed (_speed)
155 , playback_sample (0)
156 , playback_distance (0)
157 , _read_data_count (0)
158 , _write_data_count (0)
159 , in_set_state (false)
160 , _persistent_alignment_style (ExistingMaterial)
161 , first_input_change (true)
163 , scrub_buffer_size (0)
165 , _flags (Recordable)
169 Diskstream::~Diskstream ()
171 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Diskstream %1 deleted\n", _name));
174 _playlist->release ();
179 Diskstream::set_track (Track* t)
182 _io = _track->input();
184 ic_connection.disconnect();
185 _io->changed.connect_same_thread (ic_connection, boost::bind (&Diskstream::handle_input_change, this, _1, _2));
187 input_change_pending = ConfigurationChanged;
188 non_realtime_input_change ();
189 set_align_style_from_io ();
191 _track->Destroyed.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this));
195 Diskstream::handle_input_change (IOChange change, void * /*src*/)
197 Glib::Mutex::Lock lm (state_lock);
199 if (!(input_change_pending & change)) {
200 input_change_pending = IOChange (input_change_pending|change);
201 _session.request_input_change_handling ();
206 Diskstream::non_realtime_set_speed ()
208 if (_buffer_reallocation_required)
210 Glib::Mutex::Lock lm (state_lock);
211 allocate_temporary_buffers ();
213 _buffer_reallocation_required = false;
216 if (_seek_required) {
217 if (speed() != 1.0f || speed() != -1.0f) {
218 seek ((nframes_t) (_session.transport_frame() * (double) speed()), true);
221 seek (_session.transport_frame(), true);
224 _seek_required = false;
229 Diskstream::realtime_set_speed (double sp, bool global)
231 bool changed = false;
232 double new_speed = sp * _session.transport_speed();
234 if (_visible_speed != sp) {
239 if (new_speed != _actual_speed) {
241 nframes_t required_wrap_size = (nframes_t) floor (_session.get_block_size() *
242 fabs (new_speed)) + 1;
244 if (required_wrap_size > wrap_buffer_size) {
245 _buffer_reallocation_required = true;
248 _actual_speed = new_speed;
249 _target_speed = fabs(_actual_speed);
254 _seek_required = true;
256 SpeedChanged (); /* EMIT SIGNAL */
259 return _buffer_reallocation_required || _seek_required;
263 Diskstream::set_capture_offset ()
266 /* can't capture, so forget it */
270 _capture_offset = _io->latency();
274 Diskstream::set_align_style (AlignStyle a)
276 if (record_enabled() && _session.actively_recording()) {
280 if (a != _alignment_style) {
281 _alignment_style = a;
282 AlignmentStyleChanged ();
287 Diskstream::set_loop (Location *location)
290 if (location->start() >= location->end()) {
291 error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl;
296 loop_location = location;
298 LoopSet (location); /* EMIT SIGNAL */
303 Diskstream::get_capture_start_frame (uint32_t n)
305 Glib::Mutex::Lock lm (capture_info_lock);
307 if (capture_info.size() > n) {
308 return capture_info[n]->start;
311 return capture_start_frame;
316 Diskstream::get_captured_frames (uint32_t n)
318 Glib::Mutex::Lock lm (capture_info_lock);
320 if (capture_info.size() > n) {
321 return capture_info[n]->frames;
324 return capture_captured;
329 Diskstream::set_roll_delay (ARDOUR::nframes_t nframes)
331 _roll_delay = nframes;
335 Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
341 bool prior_playlist = false;
344 Glib::Mutex::Lock lm (state_lock);
346 if (playlist == _playlist) {
350 playlist_connections.drop_connections ();
353 _playlist->release();
354 prior_playlist = true;
357 _playlist = playlist;
360 if (!in_set_state && recordable()) {
361 reset_write_sources (false);
364 _playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_modified, this));
365 _playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
366 _playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_ranges_moved, this, _1, _2));
369 /* don't do this if we've already asked for it *or* if we are setting up
370 the diskstream for the very first time - the input changed handling will
371 take care of the buffer refill.
374 if (!overwrite_queued && prior_playlist) {
375 _session.request_overwrite_buffer (_track);
376 overwrite_queued = true;
379 PlaylistChanged (); /* EMIT SIGNAL */
380 _session.set_dirty ();
386 Diskstream::playlist_changed (const PropertyChange&)
388 playlist_modified ();
392 Diskstream::playlist_modified ()
394 if (!i_am_the_modifier && !overwrite_queued) {
395 _session.request_overwrite_buffer (_track);
396 overwrite_queued = true;
401 Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
403 boost::shared_ptr<Playlist> pl (wpl.lock());
405 if (pl == _playlist) {
407 /* this catches an ordering issue with session destruction. playlists
408 are destroyed before diskstreams. we have to invalidate any handles
409 we have to the playlist.
419 Diskstream::set_name (const string& str)
423 playlist()->set_name (str);
425 SessionObject::set_name(str);
427 if (!in_set_state && recordable()) {
428 /* rename existing capture files so that they have the correct name */
429 return rename_write_sources ();
439 Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames, bool from_undo)
441 /* If we're coming from an undo, it will have handled
442 automation undo (it must, since automation-follows-regions
443 can lose automation data). Hence we can do nothing here.
450 if (!_track || Config->get_automation_follows_regions () == false) {
454 list< Evoral::RangeMove<double> > movements;
456 for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
457 i != movements_frames.end();
460 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
463 /* move panner automation */
464 boost::shared_ptr<Panner> p = _track->main_outs()->panner ();
466 for (uint32_t i = 0; i < p->npanners (); ++i) {
467 boost::shared_ptr<AutomationList> pan_alist = p->streampanner(i).pan_control()->alist();
468 XMLNode & before = pan_alist->get_state ();
469 bool const things_moved = pan_alist->move_ranges (movements);
471 _session.add_command (new MementoCommand<AutomationList> (
472 *pan_alist.get(), &before, &pan_alist->get_state ()));
477 /* move processor automation */
478 _track->foreach_processor (boost::bind (&Diskstream::move_processor_automation, this, _1, movements_frames));
482 Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, list< Evoral::RangeMove<framepos_t> > const & movements_frames)
484 boost::shared_ptr<Processor> processor (p.lock ());
489 list< Evoral::RangeMove<double> > movements;
490 for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin(); i != movements_frames.end(); ++i) {
491 movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
494 set<Evoral::Parameter> const a = processor->what_can_be_automated ();
496 for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
497 boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
498 XMLNode & before = al->get_state ();
499 bool const things_moved = al->move_ranges (movements);
501 _session.add_command (
502 new MementoCommand<AutomationList> (
503 *al.get(), &before, &al->get_state ()
511 Diskstream::check_record_status (nframes_t transport_frame, nframes_t /*nframes*/, bool can_record)
513 int possibly_recording;
516 const int transport_rolling = 0x4;
517 const int track_rec_enabled = 0x2;
518 const int global_rec_enabled = 0x1;
519 const int fully_rec_enabled = (transport_rolling|track_rec_enabled|global_rec_enabled);
521 /* merge together the 3 factors that affect record status, and compute
525 rolling = _session.transport_speed() != 0.0f;
526 possibly_recording = (rolling << 2) | (record_enabled() << 1) | can_record;
527 change = possibly_recording ^ last_possibly_recording;
529 if (possibly_recording == last_possibly_recording) {
532 if (possibly_recording == fully_rec_enabled) {
534 if (last_possibly_recording == fully_rec_enabled) {
538 /* we transitioned to recording. lets see if its transport based or a punch */
540 first_recordable_frame = transport_frame + _capture_offset;
541 last_recordable_frame = max_frames;
542 capture_start_frame = transport_frame;
544 if (change & transport_rolling) {
546 /* transport-change (started rolling) */
548 if (_alignment_style == ExistingMaterial) {
550 /* there are two delays happening:
552 1) inbound, represented by _capture_offset
553 2) outbound, represented by _session.worst_output_latency()
555 the first sample to record occurs when the larger of these
556 two has elapsed, since they occur in parallel.
558 since we've already added _capture_offset, just add the
559 difference if _session.worst_output_latency() is larger.
562 if (_capture_offset < _session.worst_output_latency()) {
563 first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
566 first_recordable_frame += _roll_delay;
573 if (_alignment_style == ExistingMaterial) {
575 /* There are two kinds of punch:
577 manual punch in happens at the correct transport frame
578 because the user hit a button. but to get alignment correct
579 we have to back up the position of the new region to the
580 appropriate spot given the roll delay.
582 autopunch toggles recording at the precise
583 transport frame, and then the DS waits
584 to start recording for a time that depends
585 on the output latency.
587 XXX: BUT THIS CODE DOESN'T DIFFERENTIATE !!!
591 if (_capture_offset < _session.worst_output_latency()) {
592 /* see comment in ExistingMaterial block above */
593 first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
597 capture_start_frame -= _roll_delay;
601 prepare_record_status (capture_start_frame);
605 if (last_possibly_recording == fully_rec_enabled) {
607 /* we were recording last time */
609 if (change & transport_rolling) {
610 /* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop() */
615 last_recordable_frame = transport_frame + _capture_offset;
617 if (_alignment_style == ExistingMaterial) {
618 if (_session.worst_output_latency() > _capture_offset) {
619 last_recordable_frame += (_session.worst_output_latency() - _capture_offset);
622 last_recordable_frame += _roll_delay;
628 last_possibly_recording = possibly_recording;
632 Diskstream::route_going_away ()
638 Diskstream::calculate_record_range(OverlapType ot, sframes_t transport_frame, nframes_t nframes,
639 nframes_t& rec_nframes, nframes_t& rec_offset)
646 case OverlapInternal:
647 /* ---------- recrange
650 rec_nframes = nframes;
655 /* |--------| recrange
658 rec_nframes = transport_frame + nframes - first_recordable_frame;
660 rec_offset = first_recordable_frame - transport_frame;
665 /* |--------| recrange
668 rec_nframes = last_recordable_frame - transport_frame;
672 case OverlapExternal:
673 /* |--------| recrange
674 -------------- transrange
676 rec_nframes = last_recordable_frame - first_recordable_frame;
677 rec_offset = first_recordable_frame - transport_frame;
683 Diskstream::prepare_to_stop (framepos_t pos)
685 last_recordable_frame = pos + _capture_offset;