1 /*
2 * Copyright (C) 1999-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005-2009 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2007 Jesse Chappell <jesse@essej.net>
5 * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
6 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
7 * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
8 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
10 * Copyright (C) 2015 GZharun <grygoriiz@wavesglobal.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #ifdef WAF_BUILD
28 #include "libardour-config.h"
29 #endif
30
31 #include <cmath>
32 #include <cerrno>
33 #include <unistd.h>
34
35 #include <boost/algorithm/string/erase.hpp>
36
37 #include "pbd/error.h"
38 #include "pbd/enumwriter.h"
39 #include "pbd/i18n.h"
40 #include "pbd/memento_command.h"
41 #include "pbd/pthread_utils.h"
42 #include "pbd/stacktrace.h"
43 #include "pbd/undo.h"
44
45 #include "midi++/mmc.h"
46 #include "midi++/port.h"
47
48 #include "ardour/audio_backend.h"
49 #include "ardour/audioengine.h"
50 #include "ardour/auditioner.h"
51 #include "ardour/automation_watch.h"
52 #include "ardour/butler.h"
53 #include "ardour/click.h"
54 #include "ardour/debug.h"
55 #include "ardour/disk_reader.h"
56 #include "ardour/location.h"
57 #include "ardour/playlist.h"
58 #include "ardour/profile.h"
59 #include "ardour/scene_changer.h"
60 #include "ardour/session.h"
61 #include "ardour/transport_fsm.h"
62 #include "ardour/transport_master.h"
63 #include "ardour/transport_master_manager.h"
64 #include "ardour/tempo.h"
65 #include "ardour/operations.h"
66 #include "ardour/vca.h"
67 #include "ardour/vca_manager.h"
68
69 using namespace std;
70 using namespace ARDOUR;
71 using namespace PBD;
72
73
74 #ifdef NDEBUG
75 # define ENSURE_PROCESS_THREAD do {} while (0)
76 #else
77 # define ENSURE_PROCESS_THREAD \
78 do { \
79 if (!AudioEngine::instance()->in_process_thread()) { \
80 PBD::stacktrace (std::cerr, 30); \
81 } \
82 } while (0)
83 #endif
84
85
86 #define TFSM_EVENT(evtype) { _transport_fsm->enqueue (new TransportFSM::Event (evtype)); }
87 #define TFSM_STOP(abort,clear) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::StopTransport,abort,clear)); }
88 #define TFSM_LOCATE(target,ltd,loop,force) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::Locate,target,ltd,loop,force)); }
89 #define TFSM_SPEED(speed,as_default) { _transport_fsm->enqueue (new TransportFSM::Event (speed,as_default)); }
90
91 /* *****************************************************************************
92 * REALTIME ACTIONS (to be called on state transitions)
93 * ****************************************************************************/
94
95 void
realtime_stop(bool abort,bool clear_state)96 Session::realtime_stop (bool abort, bool clear_state)
97 {
98 ENSURE_PROCESS_THREAD;
99
100 DEBUG_TRACE (DEBUG::Transport, string_compose ("realtime stop @ %1 speed = %2\n", _transport_sample, _transport_fsm->transport_speed()));
101 PostTransportWork todo = PostTransportStop;
102
103 /* we are rolling and we want to stop */
104
105 if (Config->get_monitoring_model() == HardwareMonitoring) {
106 set_track_monitor_input_status (true);
107 }
108
109 if (synced_to_engine ()) {
110 if (clear_state) {
111 /* do this here because our response to the slave won't
112 take care of it.
113 */
114 _play_range = false;
115 _count_in_once = false;
116 unset_play_loop ();
117 }
118 }
119
120 /* call routes */
121
122 boost::shared_ptr<RouteList> r = routes.reader ();
123
124 for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
125 (*i)->realtime_handle_transport_stopped ();
126 }
127
128 DEBUG_TRACE (DEBUG::Transport, string_compose ("stop complete, auto-return scheduled for return to %1\n", _requested_return_sample));
129
130 if (abort) {
131 todo = PostTransportWork (todo | PostTransportAbort);
132 }
133
134 if (clear_state) {
135 todo = PostTransportWork (todo | PostTransportClearSubstate);
136 }
137
138 if (todo) {
139 add_post_transport_work (todo);
140 }
141
142 _clear_event_type (SessionEvent::RangeStop);
143 _clear_event_type (SessionEvent::RangeLocate);
144
145 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
146 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
147
148 if (clear_state && !Config->get_loop_is_mode()) {
149 unset_play_loop ();
150 }
151
152 reset_punch_loop_constraint ();
153
154 g_atomic_int_set (&_playback_load, 100);
155 g_atomic_int_set (&_capture_load, 100);
156
157 if (config.get_use_video_sync()) {
158 waiting_for_sync_offset = true;
159 }
160
161 if (todo) {
162 TFSM_EVENT (TransportFSM::ButlerRequired);
163 }
164 }
165
166 /** @param with_mmc true to send a MMC locate command when the locate is done */
167 void
locate(samplepos_t target_sample,bool for_loop_end,bool force,bool with_mmc)168 Session::locate (samplepos_t target_sample, bool for_loop_end, bool force, bool with_mmc)
169 {
170 ENSURE_PROCESS_THREAD;
171
172 if (target_sample < 0) {
173 error << _("Locate called for negative sample position - ignored") << endmsg;
174 return;
175 }
176
177 bool need_butler = false;
178
179 /* Locates for seamless looping are fairly different from other
180 * locates. They assume that the diskstream buffers for each track
181 * already have the correct data in them, and thus there is no need to
182 * actually tell the tracks to locate. What does need to be done,
183 * though, is all the housekeeping that is associated with non-linear
184 * changes in the value of _transport_sample.
185 */
186
187 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1 ts = %7, for loop end %2 force %3 mmc %4\n",
188 target_sample, for_loop_end, force, with_mmc, _transport_sample));
189
190 if (!force && (_transport_sample == target_sample) && !for_loop_end) {
191 TFSM_EVENT (TransportFSM::LocateDone);
192 Located (); /* EMIT SIGNAL */
193 return;
194 }
195
196 // Update Timecode time
197 _transport_sample = target_sample;
198 _nominal_jack_transport_sample = boost::none;
199 // Bump seek counter so that any in-process locate in the butler
200 // thread(s?) can restart.
201 g_atomic_int_inc (&_seek_counter);
202 _last_roll_or_reversal_location = target_sample;
203 if (!for_loop_end) {
204 _remaining_latency_preroll = worst_latency_preroll_buffer_size_ceil ();
205 }
206 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
207
208 assert (_transport_fsm->locating() || _transport_fsm->declicking_for_locate());
209
210 /* Tell all routes to do the RT part of locate */
211
212 boost::shared_ptr<RouteList> r = routes.reader ();
213 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
214 (*i)->realtime_locate (for_loop_end);
215 }
216
217 if (force || !for_loop_end) {
218
219 PostTransportWork todo = PostTransportLocate;
220 add_post_transport_work (todo);
221 need_butler = true;
222
223 } else {
224
225 /* this is functionally what clear_clicks() does but with a tentative lock */
226
227 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
228
229 if (clickm.locked()) {
230
231 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
232 delete *i;
233 }
234
235 clicks.clear ();
236 }
237 }
238
239 /* cancel looped playback if transport pos outside of loop range */
240 if (get_play_loop ()) {
241
242 Location* al = _locations->auto_loop_location();
243
244 if (al) {
245 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
246
247 // located outside the loop: cancel looping directly, this is called from event handling context
248
249 have_looped = false;
250
251 if (!Config->get_loop_is_mode()) {
252 set_play_loop (false, false);
253 } else {
254 /* this will make the non_realtime_locate() in the butler
255 which then causes seek() in tracks actually do the right
256 thing.
257 */
258 set_track_loop (false);
259 }
260
261 } else if (_transport_sample == al->start()) {
262
263 // located to start of loop - this is looping, basically
264
265 boost::shared_ptr<RouteList> rl = routes.reader();
266
267 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
268 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
269
270 if (tr && tr->rec_enable_control()->get_value()) {
271 // tell it we've looped, so it can deal with the record state
272 tr->transport_looped (_transport_sample);
273 }
274 }
275
276 if (for_loop_end) {
277 have_looped = true;
278 TransportLooped(); // EMIT SIGNAL
279 }
280 }
281 }
282 }
283
284 if (need_butler) {
285 TFSM_EVENT (TransportFSM::ButlerRequired);
286 } else {
287 TFSM_EVENT (TransportFSM::LocateDone);
288 }
289
290 _send_timecode_update = true;
291
292 if (with_mmc) {
293 send_mmc_locate (_transport_sample);
294 }
295
296 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
297
298 Located (); /* EMIT SIGNAL */
299 }
300
301 void
post_locate()302 Session::post_locate ()
303 {
304 if (transport_master_is_external() && !synced_to_engine()) {
305 const samplepos_t current_master_position = TransportMasterManager::instance().get_current_position_in_process_context();
306 if (abs (current_master_position - _transport_sample) > TransportMasterManager::instance().current()->resolution()) {
307 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
308 }
309 }
310 }
311
312 /** Set the transport speed.
313 * Called from the process thread.
314 * @param speed New speed
315 */
316 void
set_transport_speed(double speed)317 Session::set_transport_speed (double speed)
318 {
319 ENSURE_PROCESS_THREAD;
320 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %1 Set transport speed to %2 from %3 (es = %4)\n", _transport_sample, speed, _transport_fsm->transport_speed(), _engine_speed));
321
322 assert (speed != 0.0);
323
324 /* the logic:
325
326 a) engine speed is not 1.0 (normal speed)
327 b) engine speed matches the requested speed (sign ignored)
328 c) speed and transport speed have the same sign (no direction change)
329
330 For (c) the correct arithmetical test is >= 0, but we care about the
331 case where at least one of them is zero. That would generate an
332 equality with zero, but if only one of them is zero, we still need
333 to change speed. So we check that the product is > 0, which implies
334 that neither of them are zero, and they have the same sign.
335
336 */
337
338 if ((_engine_speed != 1) && (_engine_speed == fabs (speed)) && ((speed * _transport_fsm->transport_speed()) > 0)) {
339 /* engine speed is not changing and no direction change, do nothing */
340 DEBUG_TRACE (DEBUG::Transport, "no reason to change speed, do nothing\n");
341 return;
342 }
343
344 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
345 and user needs. XXX We really need CD-style "skip" playback for ffwd and rewind.
346 */
347
348 if (speed > 0) {
349 speed = min ((double) Config->get_max_transport_speed(), speed);
350 } else if (speed < 0) {
351 speed = max ((double) -Config->get_max_transport_speed(), speed);
352 }
353
354 double new_engine_speed = fabs (speed);
355 // double new_transport_speed = (speed < 0) ? -1 : 1;
356
357 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
358 warning << string_compose (
359 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
360 PROGRAM_NAME)
361 << endmsg;
362 return;
363 }
364
365 clear_clicks ();
366 _engine_speed = new_engine_speed;
367
368 if (!Config->get_auto_return_after_rewind_ffwd() && fabs (speed) != 1.0 && _transport_fsm->default_speed() == 1.0) {
369 /* varispeed of any sort cancels auto-return */
370 _requested_return_sample = -1;
371 _last_roll_location = -1;
372 _last_roll_or_reversal_location = -1;
373 }
374
375
376 /* throttle signal emissions.
377 * when slaved [_last]_transport_fsm->transport_speed()
378 * usually changes every cycle (tiny amounts due to DLL).
379 * Emitting a signal every cycle is overkill and unwarranted.
380 *
381 * Using _transport_fsm->transport_speed() is not acceptable,
382 * since it allows for large changes over a long period
383 * of time. Hence we introduce a dedicated variable to keep track
384 *
385 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
386 * for TransportStateChange() here is the ShuttleControl display.
387 */
388
389 const double act_speed = actual_speed ();
390
391 if (fabs (_signalled_varispeed - act_speed) > .002
392 // still, signal hard changes to 1.0 and 0.0:
393 || (act_speed == 1.0 && _signalled_varispeed != 1.0)
394 || (act_speed == 0.0 && _signalled_varispeed != 0.0)
395 )
396 {
397 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_fsm->transport_speed()));
398 TransportStateChange (); /* EMIT SIGNAL */
399 _signalled_varispeed = act_speed;
400 }
401
402 }
403
404 /** Stop the transport. */
405 void
stop_transport(bool abort,bool clear_state)406 Session::stop_transport (bool abort, bool clear_state)
407 {
408 ENSURE_PROCESS_THREAD;
409
410 _count_in_once = false;
411
412 DEBUG_TRACE (DEBUG::Transport, string_compose ("time to actually stop with TS @ %1\n", _transport_sample));
413
414 realtime_stop (abort, clear_state);
415 }
416
417 /** Called from the process thread */
418 void
start_transport()419 Session::start_transport ()
420 {
421 ENSURE_PROCESS_THREAD;
422 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
423
424 if (Config->get_loop_is_mode() && get_play_loop ()) {
425
426 Location *location = _locations->auto_loop_location();
427
428 if (location != 0) {
429 if (_transport_sample != location->start()) {
430
431 /* force tracks to do their thing */
432 set_track_loop (true);
433
434 /* jump to start and then roll from there */
435
436 request_locate (location->start(), MustRoll);
437 return;
438 }
439 }
440 }
441
442 if (Config->get_monitoring_model() == HardwareMonitoring) {
443 set_track_monitor_input_status (!config.get_auto_input());
444 }
445
446 _last_roll_location = _transport_sample;
447 _last_roll_or_reversal_location = _transport_sample;
448 if (!have_looped && !_exporting) {
449 _remaining_latency_preroll = worst_latency_preroll_buffer_size_ceil ();
450 }
451
452 have_looped = false;
453
454 /* if record status is Enabled, move it to Recording. if its
455 already Recording, move it to Disabled.
456 */
457
458 switch (record_status()) {
459 case Enabled:
460 if (!config.get_punch_in()) {
461 /* This is only for UIs (keep blinking rec-en before
462 * punch-in, don't show rec-region etc). The UI still
463 * depends on SessionEvent::PunchIn and ensuing signals.
464 *
465 * The disk-writers handle punch in/out internally
466 * in their local delay-compensated timeframe.
467 */
468 enable_record ();
469 }
470 break;
471
472 case Recording:
473 if (!get_play_loop ()) {
474 disable_record (false);
475 }
476 break;
477
478 default:
479 break;
480 }
481
482 maybe_allow_only_loop ();
483 maybe_allow_only_punch ();
484
485 clear_clicks ();
486
487 if (!_engine.freewheeling()) {
488 Timecode::Time time;
489 timecode_time_subframes (_transport_sample, time);
490 if (transport_master()->type() != MTC) { // why not when slaved to MTC?
491 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
492 }
493
494 if ((actively_recording () || (config.get_punch_in () && get_record_enabled ()))
495 && click_data && (config.get_count_in () || _count_in_once)) {
496 _count_in_once = false;
497 /* calculate count-in duration (in audio samples)
498 * - use [fixed] tempo/meter at _transport_sample
499 * - calc duration of 1 bar + time-to-beat before or at transport_sample
500 */
501 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
502 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
503
504 const double num = meter.divisions_per_bar ();
505 const double den = meter.note_divisor ();
506 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
507 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
508
509 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
510
511 double dt = _count_in_samples / num;
512 if (bar_fract == 0) {
513 /* at bar boundary, count-in 2 bars before start. */
514 _count_in_samples *= 2;
515 } else {
516 /* beats left after full bar until roll position */
517 _count_in_samples *= 1. + bar_fract;
518 }
519
520 if (_count_in_samples > _remaining_latency_preroll) {
521 _remaining_latency_preroll = _count_in_samples;
522 }
523
524 int clickbeat = 0;
525 samplepos_t cf = _transport_sample - _count_in_samples;
526 samplecnt_t offset = _click_io->connected_latency (true);
527 clear_clicks ();
528 _clicks_cleared = cf;
529 while (cf < _transport_sample + offset) {
530 add_click (cf, clickbeat == 0);
531 cf += dt;
532 clickbeat = fmod (clickbeat + 1, num);
533 }
534
535 if (_count_in_samples < _remaining_latency_preroll) {
536 _count_in_samples = _remaining_latency_preroll;
537 }
538 }
539 }
540
541 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", transport_speed()));
542 TransportStateChange (); /* EMIT SIGNAL */
543 }
544
545 bool
need_declick_before_locate() const546 Session::need_declick_before_locate () const
547 {
548 /* At this time (July 2020) only audio playback from disk readers is
549 de-clicked. MIDI tracks with audio output really need it too.
550 */
551 return naudiotracks() > 0;
552 }
553
554 bool
should_stop_before_locate() const555 Session::should_stop_before_locate () const
556 {
557 /* do "stopped" stuff if:
558 *
559 * we are rolling AND
560 * no autoplay in effect AND
561 * we're not synced to an external transport master
562 *
563 */
564
565 if ((!auto_play_legal || !config.get_auto_play()) &&
566 !(config.get_external_sync() && !synced_to_engine())) {
567
568 return true;
569 }
570 return false;
571 }
572
573 bool
user_roll_after_locate() const574 Session::user_roll_after_locate () const
575 {
576 return auto_play_legal && config.get_auto_play();
577 }
578
579 bool
should_roll_after_locate() const580 Session::should_roll_after_locate () const
581 {
582 /* a locate must previously have been requested and completed before
583 * this answer can be considered correct
584 */
585
586 return ((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting);
587
588 }
589
590 /** Do any transport work in the audio thread that needs to be done after the
591 * butler thread is finished. Audio thread, realtime safe.
592 */
593 void
butler_completed_transport_work()594 Session::butler_completed_transport_work ()
595 {
596 ENSURE_PROCESS_THREAD;
597 PostTransportWork ptw = post_transport_work ();
598
599 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler done, RT cleanup for %1\n", enum_2_string (ptw)));
600
601 if (ptw & PostTransportAudition) {
602 if (auditioner && auditioner->auditioning()) {
603 _remaining_latency_preroll = 0;
604 process_function = &Session::process_audition;
605 } else {
606 process_function = &Session::process_with_events;
607 }
608 ptw = PostTransportWork (ptw & ~PostTransportAudition);
609 set_post_transport_work (ptw);
610 }
611
612 if (ptw & PostTransportLocate) {
613 post_locate ();
614 ptw = PostTransportWork (ptw & ~PostTransportLocate);
615 set_post_transport_work (ptw);
616 TFSM_EVENT (TransportFSM::LocateDone);
617 }
618
619 /* the butler finished its work so clear all PostTransportWork flags
620 */
621
622 set_post_transport_work (PostTransportWork (0));
623
624 set_next_event ();
625
626 if (_transport_fsm->waiting_for_butler()) {
627 TFSM_EVENT (TransportFSM::ButlerDone);
628 }
629 }
630
631 void
schedule_butler_for_transport_work()632 Session::schedule_butler_for_transport_work ()
633 {
634 assert (_transport_fsm->waiting_for_butler ());
635 DEBUG_TRACE (DEBUG::Butler, string_compose ("summon butler for transport work (%1)\n", enum_2_string (post_transport_work())));
636 _butler->schedule_transport_work ();
637 }
638
639 bool
maybe_stop(samplepos_t limit)640 Session::maybe_stop (samplepos_t limit)
641 {
642 ENSURE_PROCESS_THREAD;
643 if ((_transport_fsm->transport_speed() > 0.0f && _transport_sample >= limit) || (_transport_fsm->transport_speed() < 0.0f && _transport_sample == 0)) {
644 if (synced_to_engine ()) {
645 _engine.transport_stop ();
646 } else {
647 TFSM_STOP (false, false);
648 }
649 return true;
650 }
651 return false;
652 }
653
654 int
micro_locate(samplecnt_t distance)655 Session::micro_locate (samplecnt_t distance)
656 {
657 ENSURE_PROCESS_THREAD;
658
659 boost::shared_ptr<RouteList> rl = routes.reader();
660 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
661 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
662 if (tr && !tr->can_internal_playback_seek (distance)) {
663 return -1;
664 }
665 }
666
667 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
668
669 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
670 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
671 if (tr) {
672 tr->internal_playback_seek (distance);
673 }
674 }
675
676 _transport_sample += distance;
677 return 0;
678 }
679
680 void
flush_all_inserts()681 Session::flush_all_inserts ()
682 {
683 ENSURE_PROCESS_THREAD;
684 boost::shared_ptr<RouteList> r = routes.reader ();
685
686 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
687 (*i)->flush_processors ();
688 }
689 }
690
691 /* *****************************************************************************
692 * END REALTIME ACTIONS
693 * ****************************************************************************/
694
695 void
add_post_transport_work(PostTransportWork ptw)696 Session::add_post_transport_work (PostTransportWork ptw)
697 {
698 PostTransportWork oldval;
699 PostTransportWork newval;
700 int tries = 0;
701
702 while (tries < 8) {
703 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
704 newval = PostTransportWork (oldval | ptw);
705 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
706 /* success */
707 return;
708 }
709 }
710
711 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
712 }
713
714 bool
should_ignore_transport_request(TransportRequestSource src,TransportRequestType type)715 Session::should_ignore_transport_request (TransportRequestSource src, TransportRequestType type)
716 {
717 if (config.get_external_sync()) {
718 if (TransportMasterManager::instance().current()->allow_request (src, type)) {
719 /* accepting a command means dropping external sync first */
720 config.set_external_sync (false);
721 return true;
722 }
723 }
724 return false;
725 }
726
727 bool
synced_to_engine() const728 Session::synced_to_engine() const
729 {
730 return config.get_external_sync() && TransportMasterManager::instance().current()->type() == Engine;
731 }
732
733 void
request_sync_source(boost::shared_ptr<TransportMaster> tm)734 Session::request_sync_source (boost::shared_ptr<TransportMaster> tm)
735 {
736 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportMaster, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
737 ev->transport_master = tm;
738 DEBUG_TRACE (DEBUG::Slave, "sent request for new transport master\n");
739 queue_event (ev);
740 }
741
742 void
reset_transport_speed(TransportRequestSource origin)743 Session::reset_transport_speed (TransportRequestSource origin)
744 {
745 request_transport_speed (1.0, true, origin);
746 }
747
748 void
request_transport_speed(double speed,bool as_default,TransportRequestSource origin)749 Session::request_transport_speed (double speed, bool as_default, TransportRequestSource origin)
750 {
751 if (synced_to_engine()) {
752 if (speed != 0) {
753 _engine.transport_start ();
754 } else {
755 _engine.transport_stop ();
756 }
757 return;
758 }
759
760 if (speed == 1. || speed == 0. || speed == -1.) {
761 if (should_ignore_transport_request (origin, TR_StartStop)) {
762 return;
763 }
764 } else {
765 if (should_ignore_transport_request (origin, TR_Speed)) {
766 return;
767 }
768 }
769
770 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
771 ev->yes_or_no = as_default; // as_default
772 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
773 queue_event (ev);
774 }
775
776 /** Request a new transport speed, but if the speed parameter is exactly zero then use
777 * a very small +ve value to prevent the transport actually stopping. This method should
778 * be used by callers who are varying transport speed but don't ever want to stop it.
779 */
780 void
request_transport_speed_nonzero(double speed,bool as_default,TransportRequestSource origin)781 Session::request_transport_speed_nonzero (double speed, bool as_default, TransportRequestSource origin)
782 {
783 if (speed == 0) {
784 speed = DBL_EPSILON;
785 }
786
787 request_transport_speed (speed, as_default);
788 }
789
790 void
request_roll(TransportRequestSource origin)791 Session::request_roll (TransportRequestSource origin)
792 {
793 if (synced_to_engine()) {
794 _engine.transport_start ();
795 return;
796 }
797
798 if (should_ignore_transport_request (origin, TR_StartStop)) {
799 return;
800 }
801
802 SessionEvent* ev = new SessionEvent (SessionEvent::StartRoll, SessionEvent::Add, SessionEvent::Immediate, 0, false); /* final 2 argumment do not matter */
803 DEBUG_TRACE (DEBUG::Transport, "Request transport roll\n");
804 queue_event (ev);
805 }
806
807 void
request_stop(bool abort,bool clear_state,TransportRequestSource origin)808 Session::request_stop (bool abort, bool clear_state, TransportRequestSource origin)
809 {
810 if (synced_to_engine()) {
811 _engine.transport_stop ();
812 return;
813 }
814
815 if (should_ignore_transport_request (origin, TR_StartStop)) {
816 return;
817 }
818
819 /* clear our solo-selection, if there is one */
820 if ( solo_selection_active() ) {
821 solo_selection ( _soloSelection, false );
822 }
823
824 SessionEvent* ev = new SessionEvent (SessionEvent::EndRoll, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
825 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport stop, audible %3 transport %4 abort = %1, clear state = %2\n", abort, clear_state, audible_sample(), _transport_sample));
826 queue_event (ev);
827 }
828
829 void
request_locate(samplepos_t target_sample,LocateTransportDisposition ltd,TransportRequestSource origin)830 Session::request_locate (samplepos_t target_sample, LocateTransportDisposition ltd, TransportRequestSource origin)
831 {
832 if (synced_to_engine()) {
833 _engine.transport_locate (target_sample);
834 return;
835 }
836
837 if (should_ignore_transport_request (origin, TR_Locate)) {
838 return;
839 }
840
841 SessionEvent::Type type;
842
843 switch (ltd) {
844 case MustRoll:
845 type = SessionEvent::LocateRoll;
846 break;
847 case MustStop:
848 type = SessionEvent::Locate;
849 break;
850 case RollIfAppropriate:
851 if (config.get_auto_play()) {
852 type = SessionEvent::LocateRoll;
853 } else {
854 type = SessionEvent::Locate;
855 }
856 break;
857 }
858
859 SessionEvent *ev = new SessionEvent (type, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
860 ev->locate_transport_disposition = ltd;
861 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1 ltd = %2\n", target_sample, enum_2_string (ltd)));
862 queue_event (ev);
863 }
864
865 void
force_locate(samplepos_t target_sample,LocateTransportDisposition ltd)866 Session::force_locate (samplepos_t target_sample, LocateTransportDisposition ltd)
867 {
868 SessionEvent *ev = new SessionEvent (SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
869 ev->locate_transport_disposition = ltd;
870 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1 roll %2\n", target_sample, enum_2_string (ltd)));
871 queue_event (ev);
872 }
873
874 void
unset_preroll_record_trim()875 Session::unset_preroll_record_trim ()
876 {
877 _preroll_record_trim_len = 0;
878 }
879
880 void
request_preroll_record_trim(samplepos_t rec_in,samplecnt_t preroll)881 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
882 {
883 if (actively_recording ()) {
884 return;
885 }
886 unset_preroll_record_trim ();
887
888 config.set_punch_in (false);
889 config.set_punch_out (false);
890
891 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
892 _preroll_record_trim_len = preroll;
893 maybe_enable_record ();
894 request_locate (pos, MustRoll);
895 set_requested_return_sample (rec_in);
896 }
897
898 void
request_count_in_record()899 Session::request_count_in_record ()
900 {
901 if (actively_recording ()) {
902 return;
903 }
904 if (transport_rolling()) {
905 return;
906 }
907 maybe_enable_record ();
908 _count_in_once = true;
909 request_transport_speed (1.0, true);
910 }
911
912 void
request_play_loop(bool yn,bool change_transport_roll)913 Session::request_play_loop (bool yn, bool change_transport_roll)
914 {
915 if (transport_master_is_external() && yn) {
916 // don't attempt to loop when not using Internal Transport
917 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
918 return;
919 }
920
921 SessionEvent* ev;
922 Location *location = _locations->auto_loop_location();
923 double target_speed;
924
925 if (location == 0 && yn) {
926 error << _("Cannot loop - no loop range defined")
927 << endmsg;
928 return;
929 }
930
931 if (change_transport_roll) {
932 if (transport_rolling()) {
933 /* start looping at current speed */
934 target_speed = transport_speed ();
935 } else {
936 /* currently stopped */
937 if (yn) {
938 /* start looping at normal speed */
939 target_speed = 1.0;
940 } else {
941 target_speed = 0.0;
942 }
943 }
944 } else {
945 /* leave the speed alone */
946 target_speed = transport_speed ();
947 }
948
949 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn, change_transport_roll);
950 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
951 queue_event (ev);
952 }
953
954 void
request_play_range(list<AudioRange> * range,bool leave_rolling)955 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
956 {
957 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
958 if (range) {
959 ev->audio_range = *range;
960 } else {
961 ev->audio_range.clear ();
962 }
963 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
964 queue_event (ev);
965 }
966
967 void
request_cancel_play_range()968 Session::request_cancel_play_range ()
969 {
970 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
971 queue_event (ev);
972 }
973
974
975 bool
solo_selection_active()976 Session::solo_selection_active ()
977 {
978 if (_soloSelection.empty()) {
979 return false;
980 }
981 return true;
982 }
983
984 void
solo_selection(StripableList & list,bool new_state)985 Session::solo_selection (StripableList &list, bool new_state)
986 {
987 boost::shared_ptr<ControlList> solo_list (new ControlList);
988 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
989
990 boost::shared_ptr<RouteList> rl = get_routes();
991
992 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
993
994 if ( !(*i)->is_track() ) {
995 continue;
996 }
997
998 boost::shared_ptr<Stripable> s (*i);
999
1000 bool found = (std::find(list.begin(), list.end(), s) != list.end());
1001 if ( found ) {
1002 /* must invalidate playlists on selected track, so disk reader
1003 * will re-fill with the new selection state for solo_selection */
1004 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1005 if (track) {
1006 boost::shared_ptr<Playlist> playlist = track->playlist();
1007 if (playlist) {
1008 playlist->ContentsChanged();
1009 }
1010 }
1011 }
1012
1013 if ( found & new_state ) {
1014 solo_list->push_back (s->solo_control());
1015 } else {
1016 unsolo_list->push_back (s->solo_control());
1017 }
1018 }
1019
1020 /* set/unset solos of the associated tracks */
1021 set_controls (solo_list, 1.0, Controllable::NoGroup);
1022 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
1023
1024 if (new_state)
1025 _soloSelection = list;
1026 else
1027 _soloSelection.clear();
1028 }
1029
1030
1031 void
butler_transport_work(bool have_process_lock)1032 Session::butler_transport_work (bool have_process_lock)
1033 {
1034 /* Note: this function executes in the butler thread context */
1035
1036 restart:
1037 boost::shared_ptr<RouteList> r = routes.reader ();
1038 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
1039 bool finished = true;
1040 PostTransportWork ptw = post_transport_work();
1041 #ifndef NDEBUG
1042 uint64_t before;
1043 #endif
1044
1045 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = [%1] (0x%3%4%5) at %2\n", enum_2_string (ptw), (before = g_get_monotonic_time()), std::hex, ptw, std::dec));
1046
1047 if (ptw & PostTransportLocate) {
1048
1049 if (get_play_loop()) {
1050
1051 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
1052
1053 /* this locate might be happening while we are
1054 * loop recording.
1055 *
1056 * Non-seamless looping will require a locate (below) that
1057 * will reset capture buffers and throw away data.
1058 *
1059 * Rather than first find all tracks and see if they
1060 * have outstanding data, just do a flush anyway. It
1061 * may be cheaper this way anyway, and is certainly
1062 * more accurate.
1063 */
1064
1065 bool more_disk_io_to_do = false;
1066 uint32_t errors = 0;
1067
1068 do {
1069 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
1070
1071 if (errors) {
1072 break;
1073 }
1074
1075 if (more_disk_io_to_do) {
1076 continue;
1077 }
1078
1079 } while (false);
1080
1081 }
1082 }
1083
1084 if (ptw & PostTransportAdjustPlaybackBuffering) {
1085 /* need to prevent concurrency with ARDOUR::Reader::run(),
1086 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1087 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
1088 if (!have_process_lock) {
1089 lx.acquire ();
1090 }
1091 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1092 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1093 if (tr) {
1094 tr->adjust_playback_buffering ();
1095 /* and refill those buffers ... */
1096 }
1097 (*i)->non_realtime_locate (_transport_sample);
1098 }
1099 VCAList v = _vca_manager->vcas ();
1100 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1101 (*i)->non_realtime_locate (_transport_sample);
1102 }
1103 }
1104
1105 if (ptw & PostTransportAdjustCaptureBuffering) {
1106 /* need to prevent concurrency with ARDOUR::DiskWriter::run(),
1107 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1108 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
1109 if (!have_process_lock) {
1110 lx.acquire ();
1111 }
1112 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1113 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1114 if (tr) {
1115 tr->adjust_capture_buffering ();
1116 }
1117 }
1118 }
1119
1120 const int butler = g_atomic_int_get (&_butler_seek_counter);
1121 const int rtlocates = g_atomic_int_get (&_seek_counter);
1122
1123 if (butler != rtlocates) {
1124 DEBUG_TRACE (DEBUG::Transport, string_compose ("nonrealtime locate invoked from BTW (butler has done %1, rtlocs %2)\n", butler, rtlocates));
1125 non_realtime_locate ();
1126 }
1127
1128 if (ptw & PostTransportStop) {
1129 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
1130 if (!finished) {
1131 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1132 goto restart;
1133 }
1134 }
1135
1136 if (ptw & PostTransportOverWrite) {
1137 non_realtime_overwrite (on_entry, finished, (ptw & PostTransportLoopChanged));
1138 if (!finished) {
1139 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1140 goto restart;
1141 }
1142 }
1143
1144 if (ptw & PostTransportAudition) {
1145 non_realtime_set_audition ();
1146 }
1147
1148 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1149
1150 DEBUG_TRACE (DEBUG::Transport, string_compose (X_("Butler transport work all done after %1 usecs @ %2 ptw %3 trw = %4\n"), g_get_monotonic_time() - before, _transport_sample, enum_2_string (post_transport_work()), _butler->transport_work_requested()));
1151 }
1152
1153 void
non_realtime_overwrite(int on_entry,bool & finished,bool update_loop_declicks)1154 Session::non_realtime_overwrite (int on_entry, bool& finished, bool update_loop_declicks)
1155 {
1156 if (update_loop_declicks) {
1157 DiskReader::reset_loop_declick (_locations->auto_loop_location(), sample_rate());
1158 }
1159
1160 boost::shared_ptr<RouteList> rl = routes.reader();
1161 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1162 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1163 if (tr && tr->pending_overwrite ()) {
1164 tr->overwrite_existing_buffers ();
1165 }
1166 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1167 finished = false;
1168 return;
1169 }
1170 }
1171 }
1172
1173 void
non_realtime_locate()1174 Session::non_realtime_locate ()
1175 {
1176 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
1177
1178 if (Config->get_loop_is_mode() && get_play_loop()) {
1179
1180 Location *loc = _locations->auto_loop_location();
1181
1182 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
1183 /* jumped out of loop range: stop tracks from looping,
1184 but leave loop (mode) enabled.
1185 */
1186 set_track_loop (false);
1187
1188 } else if (loc && ((loc->start() <= _transport_sample) || (loc->end() > _transport_sample))) {
1189
1190 /* jumping to start of loop. This might have been done before but it is
1191 * idempotent and cheap. Doing it here ensures that when we start playback
1192 * outside the loop we still flip tracks into the magic seamless mode
1193 * when needed.
1194 */
1195 set_track_loop (true);
1196
1197 } else if (loc) {
1198 set_track_loop (false);
1199 }
1200
1201 } else {
1202
1203 /* no more looping .. should have been noticed elsewhere */
1204 }
1205
1206 microseconds_t start;
1207 uint32_t nt = 0;
1208
1209 samplepos_t tf;
1210 gint sc;
1211
1212 {
1213 boost::shared_ptr<RouteList> rl = routes.reader();
1214
1215 restart:
1216 sc = g_atomic_int_get (&_seek_counter);
1217 tf = _transport_sample;
1218 start = get_microseconds ();
1219
1220 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i, ++nt) {
1221 (*i)->non_realtime_locate (tf);
1222 if (sc != g_atomic_int_get (&_seek_counter)) {
1223 goto restart;
1224 }
1225 }
1226
1227 microseconds_t end = get_microseconds ();
1228 int usecs_per_track = lrintf ((end - start) / (double) nt);
1229 #ifndef NDEBUG
1230 std::cerr << "locate to " << tf << " took " << (end - start) << " usecs for " << nt << " tracks = " << usecs_per_track << " per track\n";
1231 #endif
1232 if (usecs_per_track > g_atomic_int_get (&_current_usecs_per_track)) {
1233 g_atomic_int_set (&_current_usecs_per_track, usecs_per_track);
1234 }
1235 }
1236
1237 /* we've caught up with whatever the _seek_counter was when we did the
1238 non-realtime locates.
1239 */
1240 g_atomic_int_set (&_butler_seek_counter, sc);
1241
1242 {
1243 /* VCAs are quick to locate because they have no data (except
1244 automation) associated with them. Don't bother with a
1245 restart mechanism here, but do use the same transport sample
1246 that the Routes used.
1247 */
1248 VCAList v = _vca_manager->vcas ();
1249 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1250 (*i)->non_realtime_locate (tf);
1251 }
1252 }
1253
1254 _scene_changer->locate (_transport_sample);
1255
1256 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
1257 rather than clearing them so that the RT thread has to spend time constructing
1258 them (in Session::click).
1259 */
1260 clear_clicks ();
1261 }
1262
1263 bool
select_playhead_priority_target(samplepos_t & jump_to)1264 Session::select_playhead_priority_target (samplepos_t& jump_to)
1265 {
1266 if (!transport_master_no_external_or_using_engine() || !config.get_auto_return()) {
1267 return false;
1268 }
1269
1270 jump_to = _last_roll_location;
1271 return jump_to >= 0;
1272 }
1273
1274 void
follow_playhead_priority()1275 Session::follow_playhead_priority ()
1276 {
1277 samplepos_t target;
1278
1279 if (select_playhead_priority_target (target)) {
1280 request_locate (target);
1281 }
1282 }
1283
1284 void
non_realtime_stop(bool abort,int on_entry,bool & finished)1285 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
1286 {
1287 struct tm* now;
1288 time_t xnow;
1289 bool did_record;
1290 bool saved;
1291 PostTransportWork ptw = post_transport_work();
1292
1293 did_record = false;
1294 saved = false;
1295
1296 boost::shared_ptr<RouteList> rl = routes.reader();
1297 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1298 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1299 if (tr && tr->get_captured_samples () != 0) {
1300 did_record = true;
1301 break;
1302 }
1303 }
1304
1305 /* stop and locate are merged here because they share a lot of common stuff */
1306
1307 time (&xnow);
1308 now = localtime (&xnow);
1309
1310 if (auditioner) {
1311 auditioner->cancel_audition ();
1312 }
1313
1314 if (did_record) {
1315 begin_reversible_command (Operations::capture);
1316 _have_captured = true;
1317 }
1318
1319 DEBUG_TRACE (DEBUG::Transport, X_("Butler post-transport-work, non realtime stop\n"));
1320
1321 if (abort && did_record) {
1322 /* no reason to save the session file when we remove sources
1323 */
1324 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
1325 }
1326
1327 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1328 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1329 if (tr) {
1330 tr->transport_stopped_wallclock (*now, xnow, abort);
1331 }
1332 }
1333
1334 if (abort && did_record) {
1335 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1336 }
1337
1338 boost::shared_ptr<RouteList> r = routes.reader ();
1339
1340 if (did_record) {
1341 commit_reversible_command ();
1342 /* increase take name */
1343 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
1344 string newname = config.get_take_name();
1345 config.set_take_name(bump_name_number (newname));
1346 }
1347 }
1348
1349 if (_engine.running()) {
1350 PostTransportWork ptw = post_transport_work ();
1351
1352 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1353 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1354 }
1355 VCAList v = _vca_manager->vcas ();
1356 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1357 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1358 }
1359 }
1360
1361 /* If we are not synced to a "true" external master, and we're not
1362 * handling an explicit locate, we should consider whether or not to
1363 * "auto-return". This could mean going to a specifically requested
1364 * location, or just back to the start of the last roll.
1365 */
1366
1367 if (transport_master_no_external_or_using_engine() && !locate_initiated()) {
1368
1369 bool do_locate = false;
1370
1371 if (_requested_return_sample >= 0) {
1372
1373 /* explicit return request pre-queued in event list. overrides everything else */
1374
1375 _transport_sample = _requested_return_sample;
1376
1377 /* cancel this request */
1378 _requested_return_sample = -1;
1379 do_locate = true;
1380
1381 } else if (Config->get_auto_return_target_list()) {
1382
1383 samplepos_t jump_to;
1384
1385 if (select_playhead_priority_target (jump_to)) {
1386
1387 /* there's a valid target (we don't care how it
1388 * was derived here)
1389 */
1390
1391 _transport_sample = jump_to;
1392 do_locate = true;
1393
1394 } else if (abort) {
1395
1396 /* roll aborted (typically capture) with
1397 * auto-return enabled
1398 */
1399
1400 if (_last_roll_location >= 0) {
1401 _transport_sample = _last_roll_location;
1402 do_locate = true;
1403 }
1404 }
1405 }
1406
1407
1408 if (do_locate && synced_to_engine()) {
1409
1410 /* We will unconditionally locate to _transport_sample
1411 * below, which will refill playback buffers based on
1412 * _transport_sample, and maximises the buffering they
1413 * represent.
1414 *
1415 * But if we are synced to engine (JACK), we should
1416 * locate the engine (JACK) as well. We would follow
1417 * the engine (JACK) on the next process cycle, but
1418 * since we're going to do a locate below anyway,
1419 * it seems pointless to not use just do it ourselves
1420 * right now, rather than wait for the engine (JACK) to
1421 * provide the new position on the next cycle.
1422 *
1423 * Despite the generic name of the called method
1424 * (::transport_locate()) this method only does
1425 * anything if the audio/MIDI backend is JACK.
1426 */
1427
1428 _engine.transport_locate (_transport_sample);
1429
1430 }
1431 }
1432
1433 clear_clicks();
1434 unset_preroll_record_trim ();
1435
1436 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
1437 */
1438
1439 if (ptw & (PostTransportClearSubstate|PostTransportStop)) {
1440 unset_play_range ();
1441 if (!Config->get_loop_is_mode() && get_play_loop() && !loop_changing) {
1442 unset_play_loop ();
1443 }
1444 }
1445
1446 /* reset loop_changing so it does not affect next transport action */
1447 loop_changing = false;
1448
1449 if (!_transport_fsm->declicking_for_locate()) {
1450
1451 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
1452
1453 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1454 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
1455 (*i)->non_realtime_locate (_transport_sample);
1456
1457 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1458 finished = false;
1459 /* we will be back */
1460 return;
1461 }
1462 }
1463
1464 VCAList v = _vca_manager->vcas ();
1465 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1466 (*i)->non_realtime_locate (_transport_sample);
1467 }
1468 }
1469
1470 have_looped = false;
1471
1472 /* don't bother with this stuff if we're disconnected from the engine,
1473 because there will be no process callbacks to deliver stuff from
1474 */
1475
1476 if (_engine.running() && !_engine.freewheeling()) {
1477 // need to queue this in the next RT cycle
1478 _send_timecode_update = true;
1479
1480 if (transport_master()->type() != MTC) { // why?
1481 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
1482
1483 /* This (::non_realtime_stop()) gets called by main
1484 process thread, which will lead to confusion
1485 when calling AsyncMIDIPort::write().
1486
1487 Something must be done. XXX
1488 */
1489 send_mmc_locate (_transport_sample);
1490 }
1491 }
1492
1493 if ((ptw & PostTransportLocate) && get_record_enabled()) {
1494 /* This is scheduled by realtime_stop(), which is also done
1495 * when a slave requests /locate/ for an initial sync.
1496 * We can't hold up the slave for long with a save() here,
1497 * without breaking its initial sync cycle.
1498 *
1499 * save state only if there's no slave or if it's not yet locked.
1500 */
1501 if (!transport_master_is_external() || !transport_master()->locked()) {
1502 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
1503 SaveSessionRequested (_current_snapshot_name);
1504 saved = true;
1505 }
1506 }
1507
1508 /* save the current state of things if appropriate */
1509
1510 if (did_record && !saved) {
1511 SaveSessionRequested (_current_snapshot_name);
1512 }
1513
1514 PositionChanged (_transport_sample); /* EMIT SIGNAL */
1515 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_fsm->transport_speed()));
1516 TransportStateChange (); /* EMIT SIGNAL */
1517 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
1518 }
1519
1520 void
set_play_loop(bool yn,bool change_transport_state)1521 Session::set_play_loop (bool yn, bool change_transport_state)
1522 {
1523 ENSURE_PROCESS_THREAD;
1524 /* Called from event-handling context */
1525
1526 DEBUG_TRACE (DEBUG::Transport, string_compose ("set_play_loop (%1)\n", yn));
1527
1528 Location *loc;
1529
1530 if (yn == get_play_loop () || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
1531 /* nothing to do, or can't change loop status while recording */
1532 return;
1533 }
1534
1535 if (yn && synced_to_engine()) {
1536 warning << string_compose (
1537 _("Looping cannot be supported while %1 is using JACK transport.\n"
1538 "Recommend changing the configured options"), PROGRAM_NAME)
1539 << endmsg;
1540 return;
1541 }
1542
1543 if (yn && !maybe_allow_only_loop (true)) {
1544 return;
1545 }
1546
1547 if (yn) {
1548
1549 play_loop = true;
1550 have_looped = false;
1551
1552 unset_play_range ();
1553 /* set all tracks to use internal looping */
1554 set_track_loop (true);
1555
1556 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
1557
1558 if (!Config->get_loop_is_mode()) {
1559 if (transport_rolling()) {
1560 /* set loop_changing to ensure that non_realtime_stop does not unset_play_loop */
1561 loop_changing = true;
1562 }
1563 /* args: position, disposition, for_loop_end=false, force=true */
1564 TFSM_LOCATE (loc->start(), MustRoll, false, true);
1565 } else {
1566 if (!transport_rolling()) {
1567 /* loop-is-mode: not rolling, just locate to loop start */
1568 TFSM_LOCATE (loc->start(), MustStop, false, true);
1569 }
1570 }
1571 TransportStateChange (); /* EMIT SIGNAL */
1572 } else {
1573 unset_play_loop ();
1574 }
1575
1576 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_fsm->transport_speed()));
1577 }
1578
1579 void
unset_play_loop(bool change_transport_state)1580 Session::unset_play_loop (bool change_transport_state)
1581 {
1582 if (!get_play_loop()) {
1583 return;
1584 }
1585
1586 play_loop = false;
1587 clear_events (SessionEvent::AutoLoop);
1588 set_track_loop (false);
1589
1590 /* likely need to flush track buffers: this will locate us to wherever we are */
1591
1592 if (change_transport_state && transport_rolling ()) {
1593 TFSM_STOP (false, false);
1594 }
1595
1596 overwrite_some_buffers (boost::shared_ptr<Route>(), LoopDisabled);
1597 TransportStateChange (); /* EMIT SIGNAL */
1598 }
1599
1600 void
set_track_loop(bool yn)1601 Session::set_track_loop (bool yn)
1602 {
1603 Location* loc = _locations->auto_loop_location ();
1604
1605 if (!loc) {
1606 yn = false;
1607 }
1608
1609 boost::shared_ptr<RouteList> rl = routes.reader ();
1610
1611 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1612 if (*i && !(*i)->is_private_route()) {
1613 (*i)->set_loop (yn ? loc : 0);
1614 }
1615 }
1616
1617 DiskReader::reset_loop_declick (loc, nominal_sample_rate());
1618 }
1619
1620 samplecnt_t
worst_latency_preroll() const1621 Session::worst_latency_preroll () const
1622 {
1623 return _worst_output_latency + _worst_input_latency;
1624 }
1625
1626 samplecnt_t
worst_latency_preroll_buffer_size_ceil() const1627 Session::worst_latency_preroll_buffer_size_ceil () const
1628 {
1629 return lrintf (ceil ((_worst_output_latency + _worst_input_latency) / (float) current_block_size) * current_block_size);
1630 }
1631
1632 void
unset_play_range()1633 Session::unset_play_range ()
1634 {
1635 _play_range = false;
1636 _clear_event_type (SessionEvent::RangeStop);
1637 _clear_event_type (SessionEvent::RangeLocate);
1638 }
1639
1640 void
set_play_range(list<AudioRange> & range,bool leave_rolling)1641 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1642 {
1643 SessionEvent* ev;
1644
1645 /* Called from event-processing context */
1646
1647 unset_play_range ();
1648
1649 if (range.empty()) {
1650 /* _play_range set to false in unset_play_range()
1651 */
1652 if (!leave_rolling) {
1653 /* stop transport */
1654 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1655 merge_event (ev);
1656 }
1657 return;
1658 }
1659
1660 _play_range = true;
1661
1662 /* cancel loop play */
1663 unset_play_loop ();
1664
1665 list<AudioRange>::size_type sz = range.size();
1666
1667 if (sz > 1) {
1668
1669 list<AudioRange>::iterator i = range.begin();
1670 list<AudioRange>::iterator next;
1671
1672 while (i != range.end()) {
1673
1674 next = i;
1675 ++next;
1676
1677 /* locating/stopping is subject to delays for declicking.
1678 */
1679
1680 samplepos_t requested_sample = i->end;
1681
1682 if (requested_sample > current_block_size) {
1683 requested_sample -= current_block_size;
1684 } else {
1685 requested_sample = 0;
1686 }
1687
1688 if (next == range.end()) {
1689 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1690 } else {
1691 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1692 }
1693
1694 merge_event (ev);
1695
1696 i = next;
1697 }
1698
1699 } else if (sz == 1) {
1700
1701 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1702 merge_event (ev);
1703
1704 }
1705
1706 /* save range so we can do auto-return etc. */
1707
1708 current_audio_range = range;
1709
1710 /* now start rolling at the right place */
1711
1712 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1713 merge_event (ev);
1714
1715 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_fsm->transport_speed()));
1716 TransportStateChange (); /* EMIT SIGNAL */
1717 }
1718
1719 void
request_bounded_roll(samplepos_t start,samplepos_t end)1720 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1721 {
1722 AudioRange ar (start, end, 0);
1723 list<AudioRange> lar;
1724
1725 lar.push_back (ar);
1726 request_play_range (&lar, true);
1727 }
1728
1729 void
set_requested_return_sample(samplepos_t return_to)1730 Session::set_requested_return_sample (samplepos_t return_to)
1731 {
1732 _requested_return_sample = return_to;
1733 }
1734
1735 void
request_roll_at_and_return(samplepos_t start,samplepos_t return_to)1736 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1737 {
1738 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1739 ev->target2_sample = start;
1740 queue_event (ev);
1741 }
1742
1743 void
engine_halted()1744 Session::engine_halted ()
1745 {
1746 /* there will be no more calls to process(), so
1747 we'd better clean up for ourselves, right now.
1748
1749 We can't queue SessionEvents because they only get
1750 handled from within a process callback.
1751 */
1752
1753 /* this just stops the FSM engine ... it doesn't change the state of
1754 * the FSM directly or anything else ... but the FSM will be
1755 * reinitialized when we call its ::start() method from
1756 * ::engine_running() (if we ever get there)
1757 */
1758
1759 _transport_fsm->stop ();
1760
1761 /* Synchronously do the realtime part of a transport stop.
1762 *
1763 * Calling this will cause the butler to asynchronously run
1764 * ::non_realtime_stop() where the rest of the "stop" work will be
1765 * done.
1766 */
1767
1768 realtime_stop (false, true);
1769 }
1770
1771 void
engine_running()1772 Session::engine_running ()
1773 {
1774 _transport_fsm->start ();
1775 reset_xrun_count ();
1776 }
1777
1778 void
xrun_recovery()1779 Session::xrun_recovery ()
1780 {
1781 ++_xrun_count;
1782
1783 Xrun (_transport_sample); /* EMIT SIGNAL */
1784
1785 if (actively_recording ()) {
1786 ++_capture_xruns;
1787
1788 if (Config->get_stop_recording_on_xrun()) {
1789
1790 /* it didn't actually halt, but we need
1791 * to handle things in the same way.
1792 */
1793
1794 engine_halted();
1795
1796 /* ..and start the FSM engine again */
1797 _transport_fsm->start ();
1798 } else {
1799 boost::shared_ptr<RouteList> rl = routes.reader();
1800 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1801 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1802 if (tr) {
1803 tr->mark_capture_xrun ();
1804 }
1805 }
1806
1807 }
1808 }
1809 else if (_exporting && _realtime_export && _export_rolling) {
1810 ++_export_xruns;
1811 }
1812 }
1813
1814 void
reset_xrun_count()1815 Session::reset_xrun_count ()
1816 {
1817 _xrun_count = 0;
1818 ARDOUR::reset_performance_meters (this);
1819 Xrun (-1); /* EMIT SIGNAL */
1820 }
1821
1822 void
route_processors_changed(RouteProcessorChange c)1823 Session::route_processors_changed (RouteProcessorChange c)
1824 {
1825 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1826 g_atomic_int_set (&_ignored_a_processor_change, 1);
1827 return;
1828 }
1829
1830 if (c.type == RouteProcessorChange::MeterPointChange) {
1831 set_dirty ();
1832 return;
1833 }
1834
1835 if (c.type == RouteProcessorChange::RealTimeChange) {
1836 set_dirty ();
1837 return;
1838 }
1839
1840 resort_routes ();
1841 update_latency_compensation (false, false);
1842
1843 set_dirty ();
1844 }
1845
1846 void
allow_auto_play(bool yn)1847 Session::allow_auto_play (bool yn)
1848 {
1849 auto_play_legal = yn;
1850 }
1851
1852
1853 void
send_mmc_locate(samplepos_t t)1854 Session::send_mmc_locate (samplepos_t t)
1855 {
1856 if (t < 0) {
1857 return;
1858 }
1859
1860 if (!_engine.freewheeling()) {
1861 Timecode::Time time;
1862 timecode_time_subframes (t, time);
1863 send_immediate_mmc (MIDI::MachineControlCommand (time));
1864 }
1865 }
1866
1867 /** Ask the transport to not send timecode until further notice. The suspension
1868 * will come into effect some finite time after this call, and timecode_transmission_suspended()
1869 * should be checked by the caller to find out when.
1870 */
1871 void
request_suspend_timecode_transmission()1872 Session::request_suspend_timecode_transmission ()
1873 {
1874 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
1875 queue_event (ev);
1876 }
1877
1878 void
request_resume_timecode_transmission()1879 Session::request_resume_timecode_transmission ()
1880 {
1881 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
1882 queue_event (ev);
1883 }
1884
1885 bool
timecode_transmission_suspended() const1886 Session::timecode_transmission_suspended () const
1887 {
1888 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
1889 }
1890
1891 boost::shared_ptr<TransportMaster>
transport_master() const1892 Session::transport_master() const
1893 {
1894 return TransportMasterManager::instance().current();
1895 }
1896
1897 bool
transport_master_is_external() const1898 Session::transport_master_is_external () const
1899 {
1900 return TransportMasterManager::instance().current() && config.get_external_sync();
1901 }
1902
1903 bool
transport_master_no_external_or_using_engine() const1904 Session::transport_master_no_external_or_using_engine () const
1905 {
1906 return !TransportMasterManager::instance().current() || !config.get_external_sync() || (TransportMasterManager::instance().current()->type() == Engine);
1907 }
1908
1909 void
sync_source_changed(SyncSource type,samplepos_t pos,pframes_t cycle_nframes)1910 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
1911 {
1912 /* Runs in process() context */
1913
1914 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
1915
1916 if (master->can_loop()) {
1917 request_play_loop (false);
1918 } else if (master->has_loop()) {
1919 request_play_loop (true);
1920 }
1921
1922 /* slave change, reset any DiskIO block on disk output because it is no
1923 longer valid with a new slave.
1924 */
1925
1926 TransportMasterManager::instance().unblock_disk_output ();
1927
1928 #if 0
1929 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
1930
1931 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
1932
1933 if (mtc_master) {
1934 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
1935 MTCSyncStateChanged(mtc_master->locked() );
1936 } else {
1937 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
1938 MTCSyncStateChanged( false );
1939 }
1940 mtc_status_connection.disconnect ();
1941 }
1942
1943 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
1944
1945 if (ltc_master) {
1946 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
1947 LTCSyncStateChanged (ltc_master->locked() );
1948 } else {
1949 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
1950 LTCSyncStateChanged( false );
1951 }
1952 ltc_status_connection.disconnect ();
1953 }
1954 #endif
1955
1956 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
1957
1958 // need to queue this for next process() cycle
1959 _send_timecode_update = true;
1960
1961 boost::shared_ptr<RouteList> rl = routes.reader();
1962 const bool externally_slaved = transport_master_is_external();
1963
1964 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1965 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1966 if (tr && !tr->is_private_route()) {
1967 tr->set_slaved (externally_slaved);
1968 }
1969 }
1970
1971 set_dirty();
1972 }
1973
1974 bool
transport_stopped() const1975 Session::transport_stopped() const
1976 {
1977 return _transport_fsm->stopped();
1978 }
1979
1980 bool
transport_stopped_or_stopping() const1981 Session::transport_stopped_or_stopping() const
1982 {
1983 return _transport_fsm->stopped() || _transport_fsm->stopping();
1984 }
1985
1986 bool
transport_state_rolling() const1987 Session::transport_state_rolling() const
1988 {
1989 return _transport_fsm->rolling();
1990 }
1991
1992 bool
transport_rolling() const1993 Session::transport_rolling() const
1994 {
1995 return _transport_fsm->transport_speed() != 0.0 && _count_in_samples == 0 && _remaining_latency_preroll == 0;
1996 }
1997
1998 bool
locate_pending() const1999 Session::locate_pending () const
2000 {
2001 return _transport_fsm->locating();
2002 }
2003
2004 bool
locate_initiated() const2005 Session::locate_initiated() const
2006 {
2007 return _transport_fsm->declicking_for_locate() || _transport_fsm->locating();
2008 }
2009
2010 bool
declick_in_progress() const2011 Session::declick_in_progress () const
2012 {
2013 return _transport_fsm->declick_in_progress();
2014 }
2015
2016 bool
transport_will_roll_forwards() const2017 Session::transport_will_roll_forwards () const
2018 {
2019 return _transport_fsm->will_roll_fowards ();
2020 }
2021
2022 double
transport_speed() const2023 Session::transport_speed() const
2024 {
2025 if (_transport_fsm->transport_speed() != _transport_fsm->transport_speed()) {
2026 // cerr << "\n\n!!TS " << _transport_fsm->transport_speed() << " TFSM::speed " << _transport_fsm->transport_speed() << " via " << _transport_fsm->current_state() << endl;
2027 }
2028 return _count_in_samples > 0 ? 0. : _transport_fsm->transport_speed();
2029 }
2030
2031 double
actual_speed() const2032 Session::actual_speed() const
2033 {
2034 if (_transport_fsm->transport_speed() > 0) return _engine_speed;
2035 if (_transport_fsm->transport_speed() < 0) return - _engine_speed;
2036 return 0;
2037 }
2038