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>
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.
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.
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.
28 #include "libardour-config.h"
35 #include <boost/algorithm/string/erase.hpp>
37 #include "pbd/error.h"
38 #include "pbd/enumwriter.h"
40 #include "pbd/memento_command.h"
41 #include "pbd/pthread_utils.h"
42 #include "pbd/stacktrace.h"
45 #include "midi++/mmc.h"
46 #include "midi++/port.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/auditioner.h"
50 #include "ardour/automation_watch.h"
51 #include "ardour/butler.h"
52 #include "ardour/click.h"
53 #include "ardour/debug.h"
54 #include "ardour/disk_reader.h"
55 #include "ardour/location.h"
56 #include "ardour/playlist.h"
57 #include "ardour/profile.h"
58 #include "ardour/scene_changer.h"
59 #include "ardour/session.h"
60 #include "ardour/transport_fsm.h"
61 #include "ardour/transport_master.h"
62 #include "ardour/transport_master_manager.h"
63 #include "ardour/tempo.h"
64 #include "ardour/operations.h"
65 #include "ardour/vca.h"
66 #include "ardour/vca_manager.h"
69 using namespace ARDOUR;
74 # define ENSURE_PROCESS_THREAD do {} while (0)
76 # define ENSURE_PROCESS_THREAD \
78 if (!AudioEngine::instance()->in_process_thread()) { \
79 PBD::stacktrace (std::cerr, 30); \
85 #define TFSM_EVENT(evtype) { _transport_fsm->enqueue (new TransportFSM::Event (evtype)); }
86 #define TFSM_STOP(abort,clear) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::StopTransport,abort,clear)); }
87 #define TFSM_LOCATE(target,roll,flush,loop,force) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::Locate,target,roll,flush,loop,force)); }
89 /* *****************************************************************************
90 * REALTIME ACTIONS (to be called on state transitions)
91 * ****************************************************************************/
94 Session::realtime_stop (bool abort, bool clear_state)
96 ENSURE_PROCESS_THREAD;
98 DEBUG_TRACE (DEBUG::Transport, string_compose ("realtime stop @ %1 speed = %2\n", _transport_sample, _transport_speed));
99 PostTransportWork todo = PostTransportWork (0);
101 if (_last_transport_speed < 0.0f) {
102 todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
103 _default_transport_speed = 1.0;
104 DiskReader::inc_no_disk_output (); // for the buffer reversal
106 todo = PostTransportWork (todo | PostTransportStop);
111 boost::shared_ptr<RouteList> r = routes.reader ();
113 for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
114 (*i)->realtime_handle_transport_stopped ();
117 DEBUG_TRACE (DEBUG::Transport, string_compose ("stop complete, auto-return scheduled for return to %1\n", _requested_return_sample));
119 /* the duration change is not guaranteed to have happened, but is likely */
121 todo = PostTransportWork (todo | PostTransportDuration);
124 todo = PostTransportWork (todo | PostTransportAbort);
128 todo = PostTransportWork (todo | PostTransportClearSubstate);
132 add_post_transport_work (todo);
135 _clear_event_type (SessionEvent::RangeStop);
136 _clear_event_type (SessionEvent::RangeLocate);
138 //clear our solo-selection, if there is one
139 if ( solo_selection_active() ) {
140 solo_selection ( _soloSelection, false );
143 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
144 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
146 if (clear_state && !Config->get_loop_is_mode()) {
150 reset_slave_state ();
152 _transport_speed = 0;
153 _target_transport_speed = 0;
156 g_atomic_int_set (&_playback_load, 100);
157 g_atomic_int_set (&_capture_load, 100);
159 if (config.get_use_video_sync()) {
160 waiting_for_sync_offset = true;
164 TFSM_EVENT (TransportFSM::ButlerRequired);
169 Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force, bool with_mmc)
171 ENSURE_PROCESS_THREAD;
173 if (target_sample < 0) {
174 error << _("Locate called for negative sample position - ignored") << endmsg;
178 if (synced_to_engine()) {
182 samplepos_t ignore1, ignore2;
184 transport_master()->speed_and_position (sp, pos, ignore1, ignore2, 0);
186 if (target_sample != pos) {
188 if (config.get_jack_time_master()) {
189 /* actually locate now, since otherwise jack_timebase_callback
190 will use the incorrect _transport_sample and report an old
191 and incorrect time to Jack transport
193 do_locate (target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc);
196 /* tell JACK to change transport position, and we will
197 follow along later in ::follow_slave()
200 _engine.transport_locate (target_sample);
202 if (sp != 1.0f && with_roll) {
203 _engine.transport_start ();
209 do_locate (target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc);
213 /** @param with_mmc true to send a MMC locate command when the locate is done */
215 Session::do_locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force, bool with_mmc)
217 ENSURE_PROCESS_THREAD;
219 bool need_butler = false;
221 /* Locates for seamless looping are fairly different from other
222 * locates. They assume that the diskstream buffers for each track
223 * already have the correct data in them, and thus there is no need to
224 * actually tell the tracks to locate. What does need to be done,
225 * though, is all the housekeeping that is associated with non-linear
226 * changes in the value of _transport_sample.
229 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 loop-enabled %4 force %5 mmc %6\n",
230 target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc));
232 if (!force && _transport_sample == target_sample && !loop_changing && !for_loop_enabled) {
234 /* already at the desired position. Not forced to locate,
235 the loop isn't changing, so unless we're told to
236 start rolling also, there's nothing to do but
237 tell the world where we are (again).
241 set_transport_speed (1.0, 0, false);
243 loop_changing = false;
244 TFSM_EVENT (TransportFSM::LocateDone);
245 Located (); /* EMIT SIGNAL */
249 // Update Timecode time
250 _transport_sample = target_sample;
251 // Bump seek counter so that any in-process locate in the butler
252 // thread(s?) can restart.
253 g_atomic_int_inc (&_seek_counter);
254 _last_roll_or_reversal_location = target_sample;
255 _remaining_latency_preroll = worst_latency_preroll ();
256 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
258 /* do "stopped" stuff if:
261 * no autoplay in effect AND
262 * we're not going to keep rolling after the locate AND
263 * !(playing a loop with JACK sync) AND
264 * we're not synced to an external transport master
269 /* it is important here that we use the internal state of the transport
270 FSM, not the public facing result of ::transport_rolling()
272 bool transport_was_stopped = _transport_fsm->stopped();
274 if (!transport_was_stopped &&
275 (!auto_play_legal || !config.get_auto_play()) &&
277 !(synced_to_engine() && play_loop) &&
278 (!Profile->get_trx() || !(config.get_external_sync() && !synced_to_engine()))) {
280 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
281 transport_was_stopped = true;
285 /* Tell all routes to do the RT part of locate */
287 boost::shared_ptr<RouteList> r = routes.reader ();
288 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
289 (*i)->realtime_locate ();
293 if (force || !for_loop_enabled || loop_changing) {
295 PostTransportWork todo = PostTransportLocate;
297 if (with_roll && transport_was_stopped) {
298 todo = PostTransportWork (todo | PostTransportRoll);
301 add_post_transport_work (todo);
306 /* this is functionally what clear_clicks() does but with a tentative lock */
308 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
310 if (clickm.locked()) {
312 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
321 /* switch from input if we're going to roll */
322 if (Config->get_monitoring_model() == HardwareMonitoring) {
323 set_track_monitor_input_status (!config.get_auto_input());
326 /* otherwise we're going to stop, so do the opposite */
327 if (Config->get_monitoring_model() == HardwareMonitoring) {
328 set_track_monitor_input_status (true);
332 /* cancel looped playback if transport pos outside of loop range */
335 Location* al = _locations->auto_loop_location();
338 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
340 // located outside the loop: cancel looping directly, this is called from event handling context
344 if (!Config->get_loop_is_mode()) {
345 set_play_loop (false, _transport_speed);
347 if (Config->get_seamless_loop()) {
348 /* this will make the non_realtime_locate() in the butler
349 which then causes seek() in tracks actually do the right
352 set_track_loop (false);
356 } else if (_transport_sample == al->start()) {
358 // located to start of loop - this is looping, basically
362 if (_last_roll_location != al->start()) {
363 /* didn't start at loop start - playback must have
364 * started before loop since we've now hit the loop
367 add_post_transport_work (PostTransportLocate);
373 boost::shared_ptr<RouteList> rl = routes.reader();
375 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
376 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
378 if (tr && tr->rec_enable_control()->get_value()) {
379 // tell it we've looped, so it can deal with the record state
380 tr->transport_looped (_transport_sample);
385 TransportLooped(); // EMIT SIGNAL
391 TFSM_EVENT (TransportFSM::ButlerRequired);
393 TFSM_EVENT (TransportFSM::LocateDone);
396 loop_changing = false;
398 _send_timecode_update = true;
401 send_mmc_locate (_transport_sample);
404 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
405 if (!synced_to_engine () || _transport_sample == _engine.transport_sample ()) {
406 Located (); /* EMIT SIGNAL */
411 Session::post_locate ()
413 if (transport_master_is_external() && !synced_to_engine()) {
414 const samplepos_t current_master_position = TransportMasterManager::instance().get_current_position_in_process_context();
415 if (abs (current_master_position - _transport_sample) > TransportMasterManager::instance().current()->resolution()) {
416 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
421 /** Set the transport speed.
422 * Called from the process thread.
423 * @param speed New speed
426 Session::set_transport_speed (double speed, samplepos_t destination_sample, bool abort, bool clear_state, bool as_default)
428 ENSURE_PROCESS_THREAD;
429 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
430 speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
432 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
433 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
437 speed = min ((double) Config->get_max_transport_speed(), speed);
438 } else if (speed < 0) {
439 speed = max ((double) -Config->get_max_transport_speed(), speed);
442 double new_engine_speed = 1.0;
444 new_engine_speed = fabs (speed);
445 if (speed < 0) speed = -1;
446 if (speed > 0) speed = 1;
449 if (_transport_speed == speed && new_engine_speed == _engine_speed) {
450 if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
451 _default_transport_speed = 1.0;
456 #if 0 // TODO pref: allow vari-speed recording
457 if (actively_recording() && speed != 1.0 && speed != 0.0) {
458 /* no varispeed during recording */
459 DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, sample %2\n",
460 _transport_speed, _transport_sample));
465 _target_transport_speed = fabs(speed);
466 _engine_speed = new_engine_speed;
468 if (transport_rolling() && speed == 0.0) {
470 /* we are rolling and we want to stop */
472 if (Config->get_monitoring_model() == HardwareMonitoring) {
473 set_track_monitor_input_status (true);
476 if (synced_to_engine ()) {
478 /* do this here because our response to the slave won't
482 _count_in_once = false;
485 _engine.transport_stop ();
487 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
489 if (!auto_return_enabled) {
490 _requested_return_sample = destination_sample;
493 TFSM_STOP (abort, false);
496 } else if (transport_stopped() && speed == 1.0) {
498 _default_transport_speed = speed;
500 /* we are stopped and we want to start rolling at speed 1 */
502 if (Config->get_loop_is_mode() && play_loop) {
504 Location *location = _locations->auto_loop_location();
507 if (_transport_sample != location->start()) {
509 if (Config->get_seamless_loop()) {
510 /* force tracks to do their thing */
511 set_track_loop (true);
514 /* jump to start and then roll from there */
516 request_locate (location->start(), true);
522 if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
523 set_track_monitor_input_status (false);
526 if (synced_to_engine()) {
527 _engine.transport_start ();
528 _count_in_once = false;
530 TFSM_EVENT (TransportFSM::StartTransport);
535 /* not zero, not 1.0 ... varispeed */
537 // TODO handled transport start.. _remaining_latency_preroll
538 // and reversal of playback direction.
540 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
541 warning << string_compose (
542 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
549 if (actively_recording()) {
554 if (speed > 0.0 && _transport_sample == current_end_sample()) {
558 if (speed < 0.0 && _transport_sample == 0) {
564 /* if we are reversing relative to the current speed, or relative to the speed
565 before the last stop, then we have to do extra work.
568 PostTransportWork todo = PostTransportWork (0);
570 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
571 todo = PostTransportWork (todo | PostTransportReverse);
572 DiskReader::inc_no_disk_output (); // for the buffer reversal
573 _last_roll_or_reversal_location = _transport_sample;
576 _last_transport_speed = _transport_speed;
577 _transport_speed = speed;
580 _default_transport_speed = speed;
584 add_post_transport_work (todo);
585 TFSM_EVENT (TransportFSM::ButlerRequired);
588 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
590 /* throttle signal emissions.
591 * when slaved [_last]_transport_speed
592 * usually changes every cycle (tiny amounts due to DLL).
593 * Emitting a signal every cycle is overkill and unwarranted.
595 * Using _last_transport_speed is not acceptable,
596 * since it allows for large changes over a long period
597 * of time. Hence we introduce a dedicated variable to keep track
599 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
600 * for TransportStateChange() here is the ShuttleControl display.
602 if (fabs (_signalled_varispeed - actual_speed ()) > .002
603 // still, signal hard changes to 1.0 and 0.0:
604 || (actual_speed () == 1.0 && _signalled_varispeed != 1.0)
605 || (actual_speed () == 0.0 && _signalled_varispeed != 0.0)
608 TransportStateChange (); /* EMIT SIGNAL */
609 _signalled_varispeed = actual_speed ();
614 /** Stop the transport. */
616 Session::stop_transport (bool abort, bool clear_state)
618 ENSURE_PROCESS_THREAD;
620 _count_in_once = false;
622 DEBUG_TRACE (DEBUG::Transport, string_compose ("time to actually stop with TS @ %1\n", _transport_sample));
624 realtime_stop (abort, clear_state);
627 /** Called from the process thread */
629 Session::start_transport ()
631 ENSURE_PROCESS_THREAD;
632 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
634 _last_roll_location = _transport_sample;
635 _last_roll_or_reversal_location = _transport_sample;
636 _remaining_latency_preroll = worst_latency_preroll ();
640 /* if record status is Enabled, move it to Recording. if its
641 already Recording, move it to Disabled.
644 switch (record_status()) {
646 if (!config.get_punch_in()) {
647 /* This is only for UIs (keep blinking rec-en before
648 * punch-in, don't show rec-region etc). The UI still
649 * depends on SessionEvent::PunchIn and ensuing signals.
651 * The disk-writers handle punch in/out internally
652 * in their local delay-compensated timeframe.
660 disable_record (false);
668 _transport_speed = _default_transport_speed;
669 _target_transport_speed = _transport_speed;
671 if (!_engine.freewheeling()) {
673 timecode_time_subframes (_transport_sample, time);
674 if (transport_master()->type() == MTC) {
675 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
678 if ((actively_recording () || (config.get_punch_in () && get_record_enabled ()))
679 && click_data && (config.get_count_in () || _count_in_once)) {
680 _count_in_once = false;
681 /* calculate count-in duration (in audio samples)
682 * - use [fixed] tempo/meter at _transport_sample
683 * - calc duration of 1 bar + time-to-beat before or at transport_sample
685 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
686 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
688 const double num = meter.divisions_per_bar ();
689 const double den = meter.note_divisor ();
690 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
691 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
693 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
695 double dt = _count_in_samples / num;
696 if (bar_fract == 0) {
697 /* at bar boundary, count-in 2 bars before start. */
698 _count_in_samples *= 2;
700 /* beats left after full bar until roll position */
701 _count_in_samples *= 1. + bar_fract;
704 if (_count_in_samples > _remaining_latency_preroll) {
705 _remaining_latency_preroll = _count_in_samples;
709 samplepos_t cf = _transport_sample - _count_in_samples;
710 samplecnt_t offset = _click_io->connected_latency (true);
711 while (cf < _transport_sample + offset) {
712 add_click (cf, clickbeat == 0);
714 clickbeat = fmod (clickbeat + 1, num);
717 if (_count_in_samples < _remaining_latency_preroll) {
718 _count_in_samples = _remaining_latency_preroll;
723 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
724 TransportStateChange (); /* EMIT SIGNAL */
728 Session::should_roll_after_locate () const
730 /* a locate must previously have been requested and completed */
732 return ((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (post_transport_work() & PostTransportRoll);
736 /** Do any transport work in the audio thread that needs to be done after the
737 * butler thread is finished. Audio thread, realtime safe.
740 Session::butler_completed_transport_work ()
742 ENSURE_PROCESS_THREAD;
743 PostTransportWork ptw = post_transport_work ();
745 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler done, RT cleanup for %1\n", enum_2_string (ptw)));
747 if (ptw & PostTransportAudition) {
748 if (auditioner && auditioner->auditioning()) {
749 process_function = &Session::process_audition;
751 process_function = &Session::process_with_events;
755 if (ptw & PostTransportLocate) {
757 TFSM_EVENT (TransportFSM::LocateDone);
760 if (ptw & PostTransportAdjustPlaybackBuffering) {
761 /* we blocked output while this happened */
762 DiskReader::dec_no_disk_output ();
766 /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
769 set_post_transport_work (PostTransportWork (0));
771 if (_transport_fsm->waiting_for_butler()) {
772 TFSM_EVENT (TransportFSM::ButlerDone);
775 DiskReader::dec_no_disk_output ();
779 Session::schedule_butler_for_transport_work ()
781 assert (_transport_fsm->waiting_for_butler ());
782 DEBUG_TRACE (DEBUG::Butler, "summon butler for transport work\n");
783 _butler->schedule_transport_work ();
787 Session::maybe_stop (samplepos_t limit)
789 ENSURE_PROCESS_THREAD;
790 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
791 if (synced_to_engine () && config.get_jack_time_master ()) {
792 _engine.transport_stop ();
793 } else if (!synced_to_engine ()) {
794 TFSM_EVENT (TransportFSM::StopTransport);
802 Session::micro_locate (samplecnt_t distance)
804 ENSURE_PROCESS_THREAD;
806 boost::shared_ptr<RouteList> rl = routes.reader();
807 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
808 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
809 if (tr && !tr->can_internal_playback_seek (distance)) {
814 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
816 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
817 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
819 tr->internal_playback_seek (distance);
823 _transport_sample += distance;
828 Session::flush_all_inserts ()
830 ENSURE_PROCESS_THREAD;
831 boost::shared_ptr<RouteList> r = routes.reader ();
833 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
834 (*i)->flush_processors ();
839 Session::set_play_loop (bool yn, double speed)
841 ENSURE_PROCESS_THREAD;
842 /* Called from event-handling context */
846 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
847 /* nothing to do, or can't change loop status while recording */
851 if (yn && Config->get_seamless_loop() && synced_to_engine()) {
852 warning << string_compose (
853 _("Seamless looping cannot be supported while %1 is using JACK transport.\n"
854 "Recommend changing the configured options"), PROGRAM_NAME)
868 if (Config->get_seamless_loop()) {
869 if (!Config->get_loop_is_mode()) {
870 /* set all tracks to use internal looping */
871 set_track_loop (true);
873 /* we will do this in the locate to the start OR when we hit the end
874 * of the loop for the first time
878 /* set all tracks to NOT use internal looping */
879 set_track_loop (false);
882 /* Put the delick and loop events in into the event list. The declick event will
883 cause a de-clicking fade-out just before the end of the loop, and it will also result
884 in a fade-in when the loop restarts. The AutoLoop event will peform the actual loop.
889 auto_loop_declick_range (loc, dcp, dcl);
890 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
892 /* if requested to roll, locate to start of loop and
893 * roll but ONLY if we're not already rolling.
895 args: positition, roll=true, flush=true, with_loop=false, force buffer refill if seamless looping
898 if (Config->get_loop_is_mode()) {
899 /* loop IS a transport mode: if already
900 rolling, do not locate to loop start.
902 if (!transport_rolling() && (speed != 0.0)) {
903 TFSM_LOCATE (loc->start(), true, true, false, true);
907 TFSM_LOCATE (loc->start(), true, true, false, true);
917 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
918 TransportStateChange ();
921 /* *****************************************************************************
922 * END REALTIME ACTIONS
923 * ****************************************************************************/
927 Session::add_post_transport_work (PostTransportWork ptw)
929 PostTransportWork oldval;
930 PostTransportWork newval;
934 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
935 newval = PostTransportWork (oldval | ptw);
936 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
942 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
946 Session::should_ignore_transport_request (TransportRequestSource src, TransportRequestType type) const
948 if (config.get_external_sync()) {
949 if (TransportMasterManager::instance().current()->allow_request (src, type)) {
959 Session::synced_to_engine() const {
960 return config.get_external_sync() && TransportMasterManager::instance().current()->type() == Engine;
964 Session::request_sync_source (boost::shared_ptr<TransportMaster> tm)
966 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportMaster, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
967 ev->transport_master = tm;
968 DEBUG_TRACE (DEBUG::Slave, "sent request for new transport master\n");
973 Session::request_transport_speed (double speed, bool as_default, TransportRequestSource origin)
975 if (should_ignore_transport_request (origin, TR_Speed)) {
978 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
979 ev->third_yes_or_no = as_default; // as_default
980 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
984 /** Request a new transport speed, but if the speed parameter is exactly zero then use
985 * a very small +ve value to prevent the transport actually stopping. This method should
986 * be used by callers who are varying transport speed but don't ever want to stop it.
989 Session::request_transport_speed_nonzero (double speed, bool as_default, TransportRequestSource origin)
991 if (should_ignore_transport_request (origin, TransportRequestType (TR_Speed|TR_Start))) {
999 request_transport_speed (speed, as_default);
1003 Session::request_stop (bool abort, bool clear_state, TransportRequestSource origin)
1005 if (should_ignore_transport_request (origin, TR_Stop)) {
1009 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
1010 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));
1015 Session::request_locate (samplepos_t target_sample, bool with_roll, TransportRequestSource origin)
1017 if (should_ignore_transport_request (origin, TR_Locate)) {
1021 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
1022 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_sample));
1027 Session::force_locate (samplepos_t target_sample, bool with_roll)
1029 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
1030 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_sample));
1035 Session::unset_preroll_record_trim ()
1037 _preroll_record_trim_len = 0;
1041 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
1043 if (actively_recording ()) {
1046 unset_preroll_record_trim ();
1048 config.set_punch_in (false);
1049 config.set_punch_out (false);
1051 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
1052 _preroll_record_trim_len = preroll;
1053 maybe_enable_record ();
1054 request_locate (pos, true);
1055 set_requested_return_sample (rec_in);
1059 Session::request_count_in_record ()
1061 if (actively_recording ()) {
1064 if (transport_rolling()) {
1067 maybe_enable_record ();
1068 _count_in_once = true;
1069 request_transport_speed (1.0, true);
1073 Session::request_play_loop (bool yn, bool change_transport_roll)
1075 if (transport_master_is_external() && yn) {
1076 // don't attempt to loop when not using Internal Transport
1077 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
1082 Location *location = _locations->auto_loop_location();
1083 double target_speed;
1085 if (location == 0 && yn) {
1086 error << _("Cannot loop - no loop range defined")
1091 if (change_transport_roll) {
1092 if (transport_rolling()) {
1093 /* start looping at current speed */
1094 target_speed = transport_speed ();
1096 /* currently stopped */
1098 /* start looping at normal speed */
1105 /* leave the speed alone */
1106 target_speed = transport_speed ();
1109 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn);
1110 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
1114 if (!change_transport_roll) {
1115 if (!transport_rolling()) {
1116 /* we're not changing transport state, but we do want
1117 to set up position for the new loop. Don't
1118 do this if we're rolling already.
1120 request_locate (location->start(), false);
1124 if (!change_transport_roll && Config->get_seamless_loop() && transport_rolling()) {
1125 // request an immediate locate to refresh the tracks
1126 // after disabling looping
1127 request_locate (_transport_sample-1, false);
1133 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
1135 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
1137 ev->audio_range = *range;
1139 ev->audio_range.clear ();
1141 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
1146 Session::request_cancel_play_range ()
1148 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
1154 Session::solo_selection_active ()
1156 if (_soloSelection.empty()) {
1163 Session::solo_selection (StripableList &list, bool new_state)
1165 boost::shared_ptr<ControlList> solo_list (new ControlList);
1166 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
1169 _soloSelection = list;
1171 _soloSelection.clear();
1173 boost::shared_ptr<RouteList> rl = get_routes();
1175 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1177 if ( !(*i)->is_track() ) {
1181 boost::shared_ptr<Stripable> s (*i);
1183 bool found = (std::find(list.begin(), list.end(), s) != list.end());
1184 if ( new_state && found ) {
1186 solo_list->push_back (s->solo_control());
1188 //must invalidate playlists on selected tracks, so only selected regions get heard
1189 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1191 boost::shared_ptr<Playlist> playlist = track->playlist();
1193 playlist->ContentsChanged();
1197 unsolo_list->push_back (s->solo_control());
1201 set_controls (solo_list, 1.0, Controllable::NoGroup);
1202 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
1207 Session::butler_transport_work ()
1209 /* Note: this function executes in the butler thread context */
1212 boost::shared_ptr<RouteList> r = routes.reader ();
1213 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
1214 bool finished = true;
1215 PostTransportWork ptw = post_transport_work();
1218 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));
1220 if (ptw & PostTransportLocate) {
1222 if (get_play_loop() && !Config->get_seamless_loop()) {
1224 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
1226 /* this locate might be happening while we are
1229 * Non-seamless looping will require a locate (below) that
1230 * will reset capture buffers and throw away data.
1232 * Rather than first find all tracks and see if they
1233 * have outstanding data, just do a flush anyway. It
1234 * may be cheaper this way anyway, and is certainly
1238 bool more_disk_io_to_do = false;
1239 uint32_t errors = 0;
1242 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
1248 if (more_disk_io_to_do) {
1257 if (ptw & PostTransportAdjustPlaybackBuffering) {
1258 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1259 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1261 tr->adjust_playback_buffering ();
1262 /* and refill those buffers ... */
1264 (*i)->non_realtime_locate (_transport_sample);
1266 VCAList v = _vca_manager->vcas ();
1267 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1268 (*i)->non_realtime_locate (_transport_sample);
1272 if (ptw & PostTransportAdjustCaptureBuffering) {
1273 /* need to prevent concurrency with ARDOUR::DiskWriter::run(),
1274 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1275 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
1276 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1277 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1279 tr->adjust_capture_buffering ();
1284 if (ptw & PostTransportReverse) {
1288 /* don't seek if locate will take care of that in non_realtime_stop() */
1290 if (!(ptw & PostTransportLocate)) {
1291 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1292 (*i)->non_realtime_locate (_transport_sample);
1294 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1295 /* new request, stop seeking, and start again */
1296 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1300 VCAList v = _vca_manager->vcas ();
1301 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1302 (*i)->non_realtime_locate (_transport_sample);
1307 if (ptw & PostTransportLocate) {
1308 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
1309 non_realtime_locate ();
1312 if (ptw & PostTransportStop) {
1313 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
1315 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1320 if (ptw & PostTransportOverWrite) {
1321 non_realtime_overwrite (on_entry, finished);
1323 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1328 if (ptw & PostTransportAudition) {
1329 non_realtime_set_audition ();
1332 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1334 DEBUG_TRACE (DEBUG::Transport, string_compose (X_("Butler transport work all done after %1 usecs @ %2 trw = %3\n"), g_get_monotonic_time() - before, _transport_sample, _butler->transport_work_requested()));
1338 Session::non_realtime_overwrite (int on_entry, bool& finished)
1340 boost::shared_ptr<RouteList> rl = routes.reader();
1341 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1342 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1343 if (tr && tr->pending_overwrite ()) {
1344 tr->overwrite_existing_buffers ();
1346 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1354 Session::non_realtime_locate ()
1356 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
1358 if (Config->get_loop_is_mode() && get_play_loop()) {
1360 Location *loc = _locations->auto_loop_location();
1362 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
1363 /* jumped out of loop range: stop tracks from looping,
1364 but leave loop (mode) enabled.
1366 set_track_loop (false);
1368 } else if (loc && Config->get_seamless_loop() &&
1369 ((loc->start() <= _transport_sample) || (loc->end() > _transport_sample))) {
1371 /* jumping to start of loop. This might have been done before but it is
1372 * idempotent and cheap. Doing it here ensures that when we start playback
1373 * outside the loop we still flip tracks into the magic seamless mode
1376 set_track_loop (true);
1379 set_track_loop (false);
1384 /* no more looping .. should have been noticed elsewhere */
1391 boost::shared_ptr<RouteList> rl = routes.reader();
1394 gint sc = g_atomic_int_get (&_seek_counter);
1395 tf = _transport_sample;
1397 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1398 (*i)->non_realtime_locate (tf);
1399 if (sc != g_atomic_int_get (&_seek_counter)) {
1400 std::cerr << "\n\nLOCATE INTERRUPTED BY LOCATE!!!\n\n";
1407 /* VCAs are quick to locate because they have no data (except
1408 automation) associated with them. Don't bother with a
1409 restart mechanism here, but do use the same transport sample
1410 that the Routes used.
1412 VCAList v = _vca_manager->vcas ();
1413 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1414 (*i)->non_realtime_locate (tf);
1418 _scene_changer->locate (_transport_sample);
1420 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
1421 rather than clearing them so that the RT thread has to spend time constructing
1422 them (in Session::click).
1427 #ifdef USE_TRACKS_CODE_FEATURES
1429 Session::select_playhead_priority_target (samplepos_t& jump_to)
1433 AutoReturnTarget autoreturn = Config->get_auto_return_target_list ();
1439 if (Profile->get_trx() && transport_rolling() ) {
1440 // We're playing, so do nothing.
1441 // Next stop will put us where we need to be.
1445 /* Note that the order of checking each AutoReturnTarget flag defines
1446 the priority each flag.
1448 Ardour/Mixbus: Last Locate
1453 Tracks: Range Selection
1459 if (autoreturn & RangeSelectionStart) {
1460 if (!_range_selection.empty()) {
1461 jump_to = _range_selection.from;
1463 if (transport_rolling ()) {
1464 /* Range selection no longer exists, but we're playing,
1465 so do nothing. Next stop will put us where
1473 if (jump_to < 0 && (autoreturn & Loop) && get_play_loop()) {
1474 /* don't try to handle loop play when synced to JACK */
1476 if (!synced_to_engine()) {
1477 Location *location = _locations->auto_loop_location();
1480 jump_to = location->start();
1482 if (Config->get_seamless_loop()) {
1483 /* need to get track buffers reloaded */
1484 set_track_loop (true);
1490 if (jump_to < 0 && (autoreturn & RegionSelectionStart)) {
1491 if (!_object_selection.empty()) {
1492 jump_to = _object_selection.from;
1496 if (jump_to < 0 && (autoreturn & LastLocate)) {
1497 jump_to = _last_roll_location;
1500 return jump_to >= 0;
1505 Session::select_playhead_priority_target (samplepos_t& jump_to)
1507 if (!transport_master_no_external_or_using_engine() || !config.get_auto_return()) {
1511 jump_to = _last_roll_location;
1512 return jump_to >= 0;
1518 Session::follow_playhead_priority ()
1522 if (select_playhead_priority_target (target)) {
1523 request_locate (target);
1528 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
1534 PostTransportWork ptw = post_transport_work();
1539 boost::shared_ptr<RouteList> rl = routes.reader();
1540 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1541 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1542 if (tr && tr->get_captured_samples () != 0) {
1548 /* stop and locate are merged here because they share a lot of common stuff */
1551 now = localtime (&xnow);
1554 auditioner->cancel_audition ();
1558 begin_reversible_command (Operations::capture);
1559 _have_captured = true;
1562 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
1564 if (abort && did_record) {
1565 /* no reason to save the session file when we remove sources
1567 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
1570 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1571 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1573 tr->transport_stopped_wallclock (*now, xnow, abort);
1577 if (abort && did_record) {
1578 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1581 boost::shared_ptr<RouteList> r = routes.reader ();
1584 commit_reversible_command ();
1585 /* increase take name */
1586 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
1587 string newname = config.get_take_name();
1588 config.set_take_name(bump_name_number (newname));
1592 if (_engine.running()) {
1593 PostTransportWork ptw = post_transport_work ();
1595 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1596 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1598 VCAList v = _vca_manager->vcas ();
1599 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1600 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1603 update_latency_compensation ();
1606 /* If we are not synced to a "true" external master, and we're not
1607 * handling an explicit locate, we should consider whether or not to
1608 * "auto-return". This could mean going to a specifically requested
1609 * location, or just back to the start of the last roll.
1612 if (transport_master_no_external_or_using_engine() && !(ptw & PostTransportLocate)) {
1614 bool do_locate = false;
1616 if (_requested_return_sample >= 0) {
1618 /* explicit return request pre-queued in event list. overrides everything else */
1620 _transport_sample = _requested_return_sample;
1622 /* cancel this request */
1623 _requested_return_sample = -1;
1626 } else if (Config->get_auto_return_target_list()) {
1628 samplepos_t jump_to;
1630 if (select_playhead_priority_target (jump_to)) {
1632 /* there's a valid target (we don't care how it
1636 _transport_sample = jump_to;
1641 /* roll aborted (typically capture) with
1642 * auto-return enabled
1645 _transport_sample = _last_roll_location;
1652 if (do_locate && synced_to_engine()) {
1654 /* We will unconditionally locate to _transport_sample
1655 * below, which will refill playback buffers based on
1656 * _transport_sample, and maximises the buffering they
1659 * But if we are synced to engine (JACK), we should
1660 * locate the engine (JACK) as well. We would follow
1661 * the engine (JACK) on the next process cycle, but
1662 * since we're going to do a locate below anyway,
1663 * it seems pointless to not use just do it ourselves
1664 * right now, rather than wait for the engine (JACK) to
1665 * provide the new position on the next cycle.
1667 * Despite the generic name of the called method
1668 * (::transport_locate()) this method only does
1669 * anything if the audio/MIDI backend is JACK.
1672 _engine.transport_locate (_transport_sample);
1678 unset_preroll_record_trim ();
1680 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
1683 if (ptw & PostTransportClearSubstate) {
1684 unset_play_range ();
1685 if (!Config->get_loop_is_mode()) {
1690 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
1693 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
1694 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1695 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
1696 (*i)->non_realtime_locate (_transport_sample);
1698 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1700 /* we will be back */
1707 VCAList v = _vca_manager->vcas ();
1708 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1709 (*i)->non_realtime_locate (_transport_sample);
1713 have_looped = false;
1715 /* don't bother with this stuff if we're disconnected from the engine,
1716 because there will be no process callbacks to deliver stuff from
1719 if (_engine.running() && !_engine.freewheeling()) {
1720 // need to queue this in the next RT cycle
1721 _send_timecode_update = true;
1723 if (transport_master()->type() == MTC) {
1724 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
1726 /* This (::non_realtime_stop()) gets called by main
1727 process thread, which will lead to confusion
1728 when calling AsyncMIDIPort::write().
1730 Something must be done. XXX
1732 send_mmc_locate (_transport_sample);
1736 if ((ptw & PostTransportLocate) && get_record_enabled()) {
1737 /* This is scheduled by realtime_stop(), which is also done
1738 * when a slave requests /locate/ for an initial sync.
1739 * We can't hold up the slave for long with a save() here,
1740 * without breaking its initial sync cycle.
1742 * save state only if there's no slave or if it's not yet locked.
1744 if (!transport_master_is_external() || !transport_master()->locked()) {
1745 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
1746 SaveSessionRequested (_current_snapshot_name);
1751 /* save the current state of things if appropriate */
1753 if (did_record && !saved) {
1754 SaveSessionRequested (_current_snapshot_name);
1757 if (ptw & PostTransportStop) {
1758 unset_play_range ();
1759 if (!Config->get_loop_is_mode()) {
1764 PositionChanged (_transport_sample); /* EMIT SIGNAL */
1765 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
1766 TransportStateChange (); /* EMIT SIGNAL */
1767 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
1769 /* and start it up again if relevant */
1771 if ((ptw & PostTransportLocate) && !config.get_external_sync()) {
1772 request_transport_speed (1.0);
1777 Session::unset_play_loop ()
1781 clear_events (SessionEvent::AutoLoop);
1782 set_track_loop (false);
1785 if (Config->get_seamless_loop()) {
1786 /* likely need to flush track buffers: this will locate us to wherever we are */
1787 add_post_transport_work (PostTransportLocate);
1788 TFSM_EVENT (TransportFSM::ButlerRequired);
1790 TransportStateChange (); /* EMIT SIGNAL */
1795 Session::set_track_loop (bool yn)
1797 Location* loc = _locations->auto_loop_location ();
1803 boost::shared_ptr<RouteList> rl = routes.reader ();
1805 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1806 if (*i && !(*i)->is_private_route()) {
1807 (*i)->set_loop (yn ? loc : 0);
1813 Session::worst_latency_preroll () const
1815 return _worst_output_latency + _worst_input_latency;
1819 Session::unset_play_range ()
1821 _play_range = false;
1822 _clear_event_type (SessionEvent::RangeStop);
1823 _clear_event_type (SessionEvent::RangeLocate);
1827 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1831 /* Called from event-processing context */
1833 unset_play_range ();
1835 if (range.empty()) {
1836 /* _play_range set to false in unset_play_range()
1838 if (!leave_rolling) {
1839 /* stop transport */
1840 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1848 /* cancel loop play */
1851 list<AudioRange>::size_type sz = range.size();
1855 list<AudioRange>::iterator i = range.begin();
1856 list<AudioRange>::iterator next;
1858 while (i != range.end()) {
1863 /* locating/stopping is subject to delays for declicking.
1866 samplepos_t requested_sample = i->end;
1868 if (requested_sample > current_block_size) {
1869 requested_sample -= current_block_size;
1871 requested_sample = 0;
1874 if (next == range.end()) {
1875 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1877 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1885 } else if (sz == 1) {
1887 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1892 /* save range so we can do auto-return etc. */
1894 current_audio_range = range;
1896 /* now start rolling at the right place */
1898 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1901 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1902 TransportStateChange ();
1906 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1908 AudioRange ar (start, end, 0);
1909 list<AudioRange> lar;
1912 request_play_range (&lar, true);
1916 Session::set_requested_return_sample (samplepos_t return_to)
1918 _requested_return_sample = return_to;
1922 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1924 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1925 ev->target2_sample = start;
1930 Session::engine_halted ()
1932 /* there will be no more calls to process(), so
1933 we'd better clean up for ourselves, right now.
1935 We can't queue SessionEvents because they only get
1936 handled from within a process callback.
1939 /* this just stops the FSM engine ... it doesn't change the state of
1940 * the FSM directly or anything else ... but the FSM will be
1941 * reinitialized when we call its ::start() method from
1942 * ::engine_running() (if we ever get there)
1945 _transport_fsm->stop ();
1947 /* Synchronously do the realtime part of a transport stop.
1949 * Calling this will cause the butler to asynchronously run
1950 * ::non_realtime_stop() where the rest of the "stop" work will be
1954 realtime_stop (false, true);
1958 Session::engine_running ()
1960 initialize_latencies ();
1961 _transport_fsm->start ();
1965 Session::xrun_recovery ()
1969 Xrun (_transport_sample); /* EMIT SIGNAL */
1971 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1973 /* it didn't actually halt, but we need
1974 to handle things in the same way.
1982 Session::route_processors_changed (RouteProcessorChange c)
1984 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1988 if (c.type == RouteProcessorChange::MeterPointChange) {
1993 if (c.type == RouteProcessorChange::RealTimeChange) {
1998 update_latency_compensation ();
2005 Session::allow_auto_play (bool yn)
2007 auto_play_legal = yn;
2012 Session::send_mmc_locate (samplepos_t t)
2018 if (!_engine.freewheeling()) {
2019 Timecode::Time time;
2020 timecode_time_subframes (t, time);
2021 send_immediate_mmc (MIDI::MachineControlCommand (time));
2025 /** Ask the transport to not send timecode until further notice. The suspension
2026 * will come into effect some finite time after this call, and timecode_transmission_suspended()
2027 * should be checked by the caller to find out when.
2030 Session::request_suspend_timecode_transmission ()
2032 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
2037 Session::request_resume_timecode_transmission ()
2039 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
2044 Session::timecode_transmission_suspended () const
2046 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
2049 boost::shared_ptr<TransportMaster>
2050 Session::transport_master() const
2052 return TransportMasterManager::instance().current();
2056 Session::transport_master_is_external () const
2058 return TransportMasterManager::instance().current() && config.get_external_sync();
2062 Session::transport_master_no_external_or_using_engine () const
2064 return !TransportMasterManager::instance().current() || !config.get_external_sync() || (TransportMasterManager::instance().current()->type() == Engine);
2068 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
2070 /* Runs in process() context */
2072 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
2074 /* save value of seamless from before the switch */
2075 _was_seamless = Config->get_seamless_loop ();
2077 if (type == Engine) {
2078 /* JACK cannot support seamless looping at present */
2079 Config->set_seamless_loop (false);
2081 /* reset to whatever the value was before we last switched slaves */
2082 Config->set_seamless_loop (_was_seamless);
2085 if (master->can_loop()) {
2086 request_play_loop (false);
2087 } else if (master->has_loop()) {
2088 request_play_loop (true);
2091 /* slave change, reset any DiskIO block on disk output because it is no
2092 longer valid with a new slave.
2095 DiskReader::dec_no_disk_output ();
2098 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
2100 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
2103 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
2104 MTCSyncStateChanged(mtc_master->locked() );
2106 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
2107 MTCSyncStateChanged( false );
2109 mtc_status_connection.disconnect ();
2112 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
2115 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
2116 LTCSyncStateChanged (ltc_master->locked() );
2118 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
2119 LTCSyncStateChanged( false );
2121 ltc_status_connection.disconnect ();
2125 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
2127 // need to queue this for next process() cycle
2128 _send_timecode_update = true;
2130 boost::shared_ptr<RouteList> rl = routes.reader();
2131 const bool externally_slaved = transport_master_is_external();
2133 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2134 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2135 if (tr && !tr->is_private_route()) {
2136 tr->set_slaved (externally_slaved);
2144 Session::transport_stopped() const
2146 return _transport_fsm->stopped();
2150 Session::transport_rolling() const
2152 return _transport_speed != 0.0 && _count_in_samples == 0 && _remaining_latency_preroll == 0;
2156 Session::locate_pending () const
2158 return _transport_fsm->locating();
2162 Session::declick_in_progress () const
2164 return _transport_fsm->declick_in_progress();