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));
120 todo = PostTransportWork (todo | PostTransportAbort);
124 todo = PostTransportWork (todo | PostTransportClearSubstate);
128 add_post_transport_work (todo);
131 _clear_event_type (SessionEvent::RangeStop);
132 _clear_event_type (SessionEvent::RangeLocate);
134 //clear our solo-selection, if there is one
135 if ( solo_selection_active() ) {
136 solo_selection ( _soloSelection, false );
139 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
140 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
142 if (clear_state && !Config->get_loop_is_mode()) {
146 reset_slave_state ();
148 _transport_speed = 0;
149 _target_transport_speed = 0;
152 g_atomic_int_set (&_playback_load, 100);
153 g_atomic_int_set (&_capture_load, 100);
155 if (config.get_use_video_sync()) {
156 waiting_for_sync_offset = true;
160 TFSM_EVENT (TransportFSM::ButlerRequired);
165 Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_end, bool force, bool with_mmc)
167 ENSURE_PROCESS_THREAD;
169 if (target_sample < 0) {
170 error << _("Locate called for negative sample position - ignored") << endmsg;
174 if (synced_to_engine()) {
178 samplepos_t ignore1, ignore2;
180 transport_master()->speed_and_position (sp, pos, ignore1, ignore2, 0);
182 if (target_sample != pos) {
184 if (config.get_jack_time_master()) {
185 /* actually locate now, since otherwise jack_timebase_callback
186 will use the incorrect _transport_sample and report an old
187 and incorrect time to Jack transport
189 do_locate (target_sample, with_roll, with_flush, for_loop_end, force, with_mmc);
192 /* tell JACK to change transport position, and we will
193 follow along later in ::follow_slave()
196 _engine.transport_locate (target_sample);
198 if (sp != 1.0f && with_roll) {
199 _engine.transport_start ();
205 do_locate (target_sample, with_roll, with_flush, for_loop_end, force, with_mmc);
209 /** @param with_mmc true to send a MMC locate command when the locate is done */
211 Session::do_locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_end, bool force, bool with_mmc)
213 ENSURE_PROCESS_THREAD;
215 bool need_butler = false;
217 /* Locates for seamless looping are fairly different from other
218 * locates. They assume that the diskstream buffers for each track
219 * already have the correct data in them, and thus there is no need to
220 * actually tell the tracks to locate. What does need to be done,
221 * though, is all the housekeeping that is associated with non-linear
222 * changes in the value of _transport_sample.
225 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 for loop end %4 force %5 mmc %6\n",
226 target_sample, with_roll, with_flush, for_loop_end, force, with_mmc));
228 if (!force && _transport_sample == target_sample && !loop_changing && !for_loop_end) {
230 /* already at the desired position. Not forced to locate,
231 the loop isn't changing, so unless we're told to
232 start rolling also, there's nothing to do but
233 tell the world where we are (again).
237 set_transport_speed (1.0, 0, false);
239 loop_changing = false;
240 TFSM_EVENT (TransportFSM::LocateDone);
241 Located (); /* EMIT SIGNAL */
245 // Update Timecode time
246 _transport_sample = target_sample;
247 // Bump seek counter so that any in-process locate in the butler
248 // thread(s?) can restart.
249 g_atomic_int_inc (&_seek_counter);
250 _last_roll_or_reversal_location = target_sample;
251 _remaining_latency_preroll = worst_latency_preroll ();
252 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
254 /* do "stopped" stuff if:
257 * no autoplay in effect AND
258 * we're not going to keep rolling after the locate AND
259 * !(playing a loop with JACK sync) AND
260 * we're not synced to an external transport master
265 /* it is important here that we use the internal state of the transport
266 FSM, not the public facing result of ::transport_rolling()
268 bool transport_was_stopped = _transport_fsm->stopped();
270 if (!transport_was_stopped &&
271 (!auto_play_legal || !config.get_auto_play()) &&
273 !(synced_to_engine() && play_loop) &&
274 !(config.get_external_sync() && !synced_to_engine())) {
276 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
277 transport_was_stopped = true;
281 /* Tell all routes to do the RT part of locate */
283 boost::shared_ptr<RouteList> r = routes.reader ();
284 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
285 (*i)->realtime_locate ();
289 if (force || !for_loop_end || loop_changing) {
291 PostTransportWork todo = PostTransportLocate;
293 if (with_roll && transport_was_stopped) {
294 todo = PostTransportWork (todo | PostTransportRoll);
297 add_post_transport_work (todo);
302 /* this is functionally what clear_clicks() does but with a tentative lock */
304 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
306 if (clickm.locked()) {
308 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
317 /* switch from input if we're going to roll */
318 if (Config->get_monitoring_model() == HardwareMonitoring) {
319 set_track_monitor_input_status (!config.get_auto_input());
322 /* otherwise we're going to stop, so do the opposite */
323 if (Config->get_monitoring_model() == HardwareMonitoring) {
324 set_track_monitor_input_status (true);
328 /* cancel looped playback if transport pos outside of loop range */
331 Location* al = _locations->auto_loop_location();
334 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
336 // located outside the loop: cancel looping directly, this is called from event handling context
340 if (!Config->get_loop_is_mode()) {
341 set_play_loop (false);
343 /* this will make the non_realtime_locate() in the butler
344 which then causes seek() in tracks actually do the right
347 set_track_loop (false);
350 } else if (_transport_sample == al->start()) {
352 // located to start of loop - this is looping, basically
356 if (_last_roll_location != al->start()) {
357 /* didn't start at loop start - playback must have
358 * started before loop since we've now hit the loop
361 add_post_transport_work (PostTransportLocate);
367 boost::shared_ptr<RouteList> rl = routes.reader();
369 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
370 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
372 if (tr && tr->rec_enable_control()->get_value()) {
373 // tell it we've looped, so it can deal with the record state
374 tr->transport_looped (_transport_sample);
379 TransportLooped(); // EMIT SIGNAL
385 TFSM_EVENT (TransportFSM::ButlerRequired);
387 TFSM_EVENT (TransportFSM::LocateDone);
390 loop_changing = false;
392 _send_timecode_update = true;
395 send_mmc_locate (_transport_sample);
398 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
399 if (!synced_to_engine () || _transport_sample == _engine.transport_sample ()) {
400 Located (); /* EMIT SIGNAL */
405 Session::post_locate ()
407 if (transport_master_is_external() && !synced_to_engine()) {
408 const samplepos_t current_master_position = TransportMasterManager::instance().get_current_position_in_process_context();
409 if (abs (current_master_position - _transport_sample) > TransportMasterManager::instance().current()->resolution()) {
410 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
415 /** Set the transport speed.
416 * Called from the process thread.
417 * @param speed New speed
420 Session::set_transport_speed (double speed, samplepos_t destination_sample, bool abort, bool clear_state, bool as_default)
422 ENSURE_PROCESS_THREAD;
423 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
424 speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
426 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
427 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
431 speed = min ((double) Config->get_max_transport_speed(), speed);
432 } else if (speed < 0) {
433 speed = max ((double) -Config->get_max_transport_speed(), speed);
436 double new_engine_speed = 1.0;
438 new_engine_speed = fabs (speed);
439 if (speed < 0) speed = -1;
440 if (speed > 0) speed = 1;
443 if (_transport_speed == speed && new_engine_speed == _engine_speed) {
444 if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
445 _default_transport_speed = 1.0;
450 #if 0 // TODO pref: allow vari-speed recording
451 if (actively_recording() && speed != 1.0 && speed != 0.0) {
452 /* no varispeed during recording */
453 DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, sample %2\n",
454 _transport_speed, _transport_sample));
459 _target_transport_speed = fabs(speed);
460 _engine_speed = new_engine_speed;
462 if (transport_rolling() && speed == 0.0) {
464 /* we are rolling and we want to stop */
466 if (Config->get_monitoring_model() == HardwareMonitoring) {
467 set_track_monitor_input_status (true);
470 if (synced_to_engine ()) {
472 /* do this here because our response to the slave won't
476 _count_in_once = false;
479 _engine.transport_stop ();
481 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
483 if (!auto_return_enabled) {
484 _requested_return_sample = destination_sample;
487 TFSM_STOP (abort, false);
490 } else if (transport_stopped() && speed == 1.0) {
492 _default_transport_speed = speed;
494 /* we are stopped and we want to start rolling at speed 1 */
496 if (Config->get_loop_is_mode() && play_loop) {
498 Location *location = _locations->auto_loop_location();
501 if (_transport_sample != location->start()) {
503 /* force tracks to do their thing */
504 set_track_loop (true);
506 /* jump to start and then roll from there */
508 request_locate (location->start(), true);
514 if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
515 set_track_monitor_input_status (false);
518 if (synced_to_engine()) {
519 _engine.transport_start ();
520 _count_in_once = false;
522 TFSM_EVENT (TransportFSM::StartTransport);
527 /* not zero, not 1.0 ... varispeed */
529 // TODO handled transport start.. _remaining_latency_preroll
530 // and reversal of playback direction.
532 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
533 warning << string_compose (
534 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
541 if (actively_recording()) {
546 if (speed > 0.0 && _transport_sample == current_end_sample()) {
550 if (speed < 0.0 && _transport_sample == 0) {
556 /* if we are reversing relative to the current speed, or relative to the speed
557 before the last stop, then we have to do extra work.
560 PostTransportWork todo = PostTransportWork (0);
562 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
563 todo = PostTransportWork (todo | PostTransportReverse);
564 DiskReader::inc_no_disk_output (); // for the buffer reversal
565 _last_roll_or_reversal_location = _transport_sample;
568 _last_transport_speed = _transport_speed;
569 _transport_speed = speed;
572 _default_transport_speed = speed;
576 add_post_transport_work (todo);
577 TFSM_EVENT (TransportFSM::ButlerRequired);
580 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
582 /* throttle signal emissions.
583 * when slaved [_last]_transport_speed
584 * usually changes every cycle (tiny amounts due to DLL).
585 * Emitting a signal every cycle is overkill and unwarranted.
587 * Using _last_transport_speed is not acceptable,
588 * since it allows for large changes over a long period
589 * of time. Hence we introduce a dedicated variable to keep track
591 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
592 * for TransportStateChange() here is the ShuttleControl display.
594 if (fabs (_signalled_varispeed - actual_speed ()) > .002
595 // still, signal hard changes to 1.0 and 0.0:
596 || (actual_speed () == 1.0 && _signalled_varispeed != 1.0)
597 || (actual_speed () == 0.0 && _signalled_varispeed != 0.0)
600 TransportStateChange (); /* EMIT SIGNAL */
601 _signalled_varispeed = actual_speed ();
606 /** Stop the transport. */
608 Session::stop_transport (bool abort, bool clear_state)
610 ENSURE_PROCESS_THREAD;
612 _count_in_once = false;
614 DEBUG_TRACE (DEBUG::Transport, string_compose ("time to actually stop with TS @ %1\n", _transport_sample));
616 realtime_stop (abort, clear_state);
619 /** Called from the process thread */
621 Session::start_transport ()
623 ENSURE_PROCESS_THREAD;
624 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
626 _last_roll_location = _transport_sample;
627 _last_roll_or_reversal_location = _transport_sample;
628 _remaining_latency_preroll = worst_latency_preroll ();
632 /* if record status is Enabled, move it to Recording. if its
633 already Recording, move it to Disabled.
636 switch (record_status()) {
638 if (!config.get_punch_in()) {
639 /* This is only for UIs (keep blinking rec-en before
640 * punch-in, don't show rec-region etc). The UI still
641 * depends on SessionEvent::PunchIn and ensuing signals.
643 * The disk-writers handle punch in/out internally
644 * in their local delay-compensated timeframe.
652 disable_record (false);
660 _transport_speed = _default_transport_speed;
661 _target_transport_speed = _transport_speed;
663 if (!_engine.freewheeling()) {
665 timecode_time_subframes (_transport_sample, time);
666 if (transport_master()->type() == MTC) {
667 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
670 if ((actively_recording () || (config.get_punch_in () && get_record_enabled ()))
671 && click_data && (config.get_count_in () || _count_in_once)) {
672 _count_in_once = false;
673 /* calculate count-in duration (in audio samples)
674 * - use [fixed] tempo/meter at _transport_sample
675 * - calc duration of 1 bar + time-to-beat before or at transport_sample
677 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
678 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
680 const double num = meter.divisions_per_bar ();
681 const double den = meter.note_divisor ();
682 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
683 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
685 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
687 double dt = _count_in_samples / num;
688 if (bar_fract == 0) {
689 /* at bar boundary, count-in 2 bars before start. */
690 _count_in_samples *= 2;
692 /* beats left after full bar until roll position */
693 _count_in_samples *= 1. + bar_fract;
696 if (_count_in_samples > _remaining_latency_preroll) {
697 _remaining_latency_preroll = _count_in_samples;
701 samplepos_t cf = _transport_sample - _count_in_samples;
702 samplecnt_t offset = _click_io->connected_latency (true);
703 while (cf < _transport_sample + offset) {
704 add_click (cf, clickbeat == 0);
706 clickbeat = fmod (clickbeat + 1, num);
709 if (_count_in_samples < _remaining_latency_preroll) {
710 _count_in_samples = _remaining_latency_preroll;
715 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
716 TransportStateChange (); /* EMIT SIGNAL */
720 Session::should_roll_after_locate () const
722 /* a locate must previously have been requested and completed */
724 return ((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (post_transport_work() & PostTransportRoll);
728 /** Do any transport work in the audio thread that needs to be done after the
729 * butler thread is finished. Audio thread, realtime safe.
732 Session::butler_completed_transport_work ()
734 ENSURE_PROCESS_THREAD;
735 PostTransportWork ptw = post_transport_work ();
737 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler done, RT cleanup for %1\n", enum_2_string (ptw)));
739 if (ptw & PostTransportAudition) {
740 if (auditioner && auditioner->auditioning()) {
741 process_function = &Session::process_audition;
743 process_function = &Session::process_with_events;
745 ptw = PostTransportWork (ptw & ~PostTransportAudition);
746 set_post_transport_work (ptw);
749 if (ptw & PostTransportLocate) {
751 ptw = PostTransportWork (ptw & ~PostTransportLocate);
752 set_post_transport_work (ptw);
753 TFSM_EVENT (TransportFSM::LocateDone);
756 if (ptw & PostTransportAdjustPlaybackBuffering) {
757 /* we blocked output while this happened */
758 DiskReader::dec_no_disk_output ();
759 ptw = PostTransportWork (ptw & ~PostTransportAdjustPlaybackBuffering);
760 set_post_transport_work (ptw);
763 bool start_after_butler_done_msg = false;
765 if ((ptw & (PostTransportReverse|PostTransportRoll))) {
766 start_after_butler_done_msg = true;
769 ptw = PostTransportWork (ptw & ~(PostTransportAdjustCaptureBuffering|PostTransportOverWrite|PostTransportReverse|PostTransportRoll));
770 set_post_transport_work (ptw);
774 if (_transport_fsm->waiting_for_butler()) {
775 TFSM_EVENT (TransportFSM::ButlerDone);
778 DiskReader::dec_no_disk_output ();
780 if (start_after_butler_done_msg) {
781 if (_transport_speed) {
782 /* reversal is done ... tell TFSM that it is time to start*/
783 TFSM_EVENT (TransportFSM::StartTransport);
789 Session::schedule_butler_for_transport_work ()
791 assert (_transport_fsm->waiting_for_butler ());
792 DEBUG_TRACE (DEBUG::Butler, "summon butler for transport work\n");
793 _butler->schedule_transport_work ();
797 Session::maybe_stop (samplepos_t limit)
799 ENSURE_PROCESS_THREAD;
800 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
801 if (synced_to_engine () && config.get_jack_time_master ()) {
802 _engine.transport_stop ();
803 } else if (!synced_to_engine ()) {
804 TFSM_EVENT (TransportFSM::StopTransport);
812 Session::micro_locate (samplecnt_t distance)
814 ENSURE_PROCESS_THREAD;
816 boost::shared_ptr<RouteList> rl = routes.reader();
817 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
818 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
819 if (tr && !tr->can_internal_playback_seek (distance)) {
824 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
826 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
827 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
829 tr->internal_playback_seek (distance);
833 _transport_sample += distance;
838 Session::flush_all_inserts ()
840 ENSURE_PROCESS_THREAD;
841 boost::shared_ptr<RouteList> r = routes.reader ();
843 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
844 (*i)->flush_processors ();
849 Session::set_play_loop (bool yn)
851 ENSURE_PROCESS_THREAD;
852 /* Called from event-handling context */
854 DEBUG_TRACE (DEBUG::Transport, string_compose ("set_play_loop (%1)\n", yn));
858 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
859 /* nothing to do, or can't change loop status while recording */
863 if (yn && synced_to_engine()) {
864 warning << string_compose (
865 _("Looping cannot be supported while %1 is using JACK transport.\n"
866 "Recommend changing the configured options"), PROGRAM_NAME)
879 /* set all tracks to use internal looping */
880 set_track_loop (true);
882 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
884 if (!Config->get_loop_is_mode()) {
885 /* args: positition, roll=true, flush=true, for_loop_end=false, force buffer, refill looping */
887 TFSM_LOCATE (loc->start(), true, true, false, true);
896 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
897 TransportStateChange ();
900 /* *****************************************************************************
901 * END REALTIME ACTIONS
902 * ****************************************************************************/
906 Session::add_post_transport_work (PostTransportWork ptw)
908 PostTransportWork oldval;
909 PostTransportWork newval;
913 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
914 newval = PostTransportWork (oldval | ptw);
915 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
921 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
925 Session::should_ignore_transport_request (TransportRequestSource src, TransportRequestType type) const
927 if (config.get_external_sync()) {
928 if (TransportMasterManager::instance().current()->allow_request (src, type)) {
938 Session::synced_to_engine() const {
939 return config.get_external_sync() && TransportMasterManager::instance().current()->type() == Engine;
943 Session::request_sync_source (boost::shared_ptr<TransportMaster> tm)
945 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportMaster, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
946 ev->transport_master = tm;
947 DEBUG_TRACE (DEBUG::Slave, "sent request for new transport master\n");
952 Session::request_transport_speed (double speed, bool as_default, TransportRequestSource origin)
954 if (should_ignore_transport_request (origin, TR_Speed)) {
957 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
958 ev->third_yes_or_no = as_default; // as_default
959 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
963 /** Request a new transport speed, but if the speed parameter is exactly zero then use
964 * a very small +ve value to prevent the transport actually stopping. This method should
965 * be used by callers who are varying transport speed but don't ever want to stop it.
968 Session::request_transport_speed_nonzero (double speed, bool as_default, TransportRequestSource origin)
970 if (should_ignore_transport_request (origin, TransportRequestType (TR_Speed|TR_Start))) {
978 request_transport_speed (speed, as_default);
982 Session::request_stop (bool abort, bool clear_state, TransportRequestSource origin)
984 if (should_ignore_transport_request (origin, TR_Stop)) {
988 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
989 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));
994 Session::request_locate (samplepos_t target_sample, bool with_roll, TransportRequestSource origin)
996 if (should_ignore_transport_request (origin, TR_Locate)) {
1000 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
1001 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_sample));
1006 Session::force_locate (samplepos_t target_sample, bool with_roll)
1008 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
1009 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_sample));
1014 Session::unset_preroll_record_trim ()
1016 _preroll_record_trim_len = 0;
1020 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
1022 if (actively_recording ()) {
1025 unset_preroll_record_trim ();
1027 config.set_punch_in (false);
1028 config.set_punch_out (false);
1030 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
1031 _preroll_record_trim_len = preroll;
1032 maybe_enable_record ();
1033 request_locate (pos, true);
1034 set_requested_return_sample (rec_in);
1038 Session::request_count_in_record ()
1040 if (actively_recording ()) {
1043 if (transport_rolling()) {
1046 maybe_enable_record ();
1047 _count_in_once = true;
1048 request_transport_speed (1.0, true);
1052 Session::request_play_loop (bool yn, bool change_transport_roll)
1054 if (transport_master_is_external() && yn) {
1055 // don't attempt to loop when not using Internal Transport
1056 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
1061 Location *location = _locations->auto_loop_location();
1062 double target_speed;
1064 if (location == 0 && yn) {
1065 error << _("Cannot loop - no loop range defined")
1070 if (change_transport_roll) {
1071 if (transport_rolling()) {
1072 /* start looping at current speed */
1073 target_speed = transport_speed ();
1075 /* currently stopped */
1077 /* start looping at normal speed */
1084 /* leave the speed alone */
1085 target_speed = transport_speed ();
1088 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn);
1089 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
1094 if (!change_transport_roll) {
1095 if (!Config->get_loop_is_mode() && !transport_rolling()) {
1096 /* we're not changing transport state, but we do want
1097 to set up position for the new loop. Don't
1098 do this if we're rolling already.
1100 request_locate (location->start(), false);
1104 if (!change_transport_roll && transport_rolling()) {
1105 // request an immediate locate to refresh the tracks
1106 // after disabling looping
1107 request_locate (_transport_sample-1, false);
1113 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
1115 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
1117 ev->audio_range = *range;
1119 ev->audio_range.clear ();
1121 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
1126 Session::request_cancel_play_range ()
1128 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
1134 Session::solo_selection_active ()
1136 if (_soloSelection.empty()) {
1143 Session::solo_selection (StripableList &list, bool new_state)
1145 boost::shared_ptr<ControlList> solo_list (new ControlList);
1146 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
1149 _soloSelection = list;
1151 _soloSelection.clear();
1153 boost::shared_ptr<RouteList> rl = get_routes();
1155 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1157 if ( !(*i)->is_track() ) {
1161 boost::shared_ptr<Stripable> s (*i);
1163 bool found = (std::find(list.begin(), list.end(), s) != list.end());
1164 if ( new_state && found ) {
1166 solo_list->push_back (s->solo_control());
1168 //must invalidate playlists on selected tracks, so only selected regions get heard
1169 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1171 boost::shared_ptr<Playlist> playlist = track->playlist();
1173 playlist->ContentsChanged();
1177 unsolo_list->push_back (s->solo_control());
1181 set_controls (solo_list, 1.0, Controllable::NoGroup);
1182 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
1187 Session::butler_transport_work ()
1189 /* Note: this function executes in the butler thread context */
1192 boost::shared_ptr<RouteList> r = routes.reader ();
1193 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
1194 bool finished = true;
1195 PostTransportWork ptw = post_transport_work();
1198 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));
1200 if (ptw & PostTransportLocate) {
1202 if (get_play_loop()) {
1204 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
1206 /* this locate might be happening while we are
1209 * Non-seamless looping will require a locate (below) that
1210 * will reset capture buffers and throw away data.
1212 * Rather than first find all tracks and see if they
1213 * have outstanding data, just do a flush anyway. It
1214 * may be cheaper this way anyway, and is certainly
1218 bool more_disk_io_to_do = false;
1219 uint32_t errors = 0;
1222 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
1228 if (more_disk_io_to_do) {
1237 if (ptw & PostTransportAdjustPlaybackBuffering) {
1238 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1239 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1241 tr->adjust_playback_buffering ();
1242 /* and refill those buffers ... */
1244 (*i)->non_realtime_locate (_transport_sample);
1246 VCAList v = _vca_manager->vcas ();
1247 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1248 (*i)->non_realtime_locate (_transport_sample);
1252 if (ptw & PostTransportAdjustCaptureBuffering) {
1253 /* need to prevent concurrency with ARDOUR::DiskWriter::run(),
1254 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1255 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
1256 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1257 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1259 tr->adjust_capture_buffering ();
1264 if (ptw & PostTransportReverse) {
1268 /* don't seek if locate will take care of that in non_realtime_stop() */
1270 if (!(ptw & PostTransportLocate)) {
1271 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1272 (*i)->non_realtime_locate (_transport_sample);
1274 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1275 /* new request, stop seeking, and start again */
1276 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1280 VCAList v = _vca_manager->vcas ();
1281 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1282 (*i)->non_realtime_locate (_transport_sample);
1287 if (ptw & PostTransportLocate) {
1288 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
1289 non_realtime_locate ();
1292 if (ptw & PostTransportStop) {
1293 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
1295 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1300 if (ptw & PostTransportOverWrite) {
1301 non_realtime_overwrite (on_entry, finished);
1303 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1308 if (ptw & PostTransportAudition) {
1309 non_realtime_set_audition ();
1312 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1314 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()));
1318 Session::non_realtime_overwrite (int on_entry, bool& finished)
1320 boost::shared_ptr<RouteList> rl = routes.reader();
1321 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1322 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1323 if (tr && tr->pending_overwrite ()) {
1324 tr->overwrite_existing_buffers ();
1326 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1334 Session::non_realtime_locate ()
1336 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
1338 if (Config->get_loop_is_mode() && get_play_loop()) {
1340 Location *loc = _locations->auto_loop_location();
1342 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
1343 /* jumped out of loop range: stop tracks from looping,
1344 but leave loop (mode) enabled.
1346 set_track_loop (false);
1348 } else if (loc && ((loc->start() <= _transport_sample) || (loc->end() > _transport_sample))) {
1350 /* jumping to start of loop. This might have been done before but it is
1351 * idempotent and cheap. Doing it here ensures that when we start playback
1352 * outside the loop we still flip tracks into the magic seamless mode
1355 set_track_loop (true);
1358 set_track_loop (false);
1363 /* no more looping .. should have been noticed elsewhere */
1370 boost::shared_ptr<RouteList> rl = routes.reader();
1373 gint sc = g_atomic_int_get (&_seek_counter);
1374 tf = _transport_sample;
1376 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1377 (*i)->non_realtime_locate (tf);
1378 if (sc != g_atomic_int_get (&_seek_counter)) {
1379 std::cerr << "\n\nLOCATE INTERRUPTED BY LOCATE!!!\n\n";
1386 /* VCAs are quick to locate because they have no data (except
1387 automation) associated with them. Don't bother with a
1388 restart mechanism here, but do use the same transport sample
1389 that the Routes used.
1391 VCAList v = _vca_manager->vcas ();
1392 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1393 (*i)->non_realtime_locate (tf);
1397 _scene_changer->locate (_transport_sample);
1399 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
1400 rather than clearing them so that the RT thread has to spend time constructing
1401 them (in Session::click).
1407 Session::select_playhead_priority_target (samplepos_t& jump_to)
1409 if (!transport_master_no_external_or_using_engine() || !config.get_auto_return()) {
1413 jump_to = _last_roll_location;
1414 return jump_to >= 0;
1418 Session::follow_playhead_priority ()
1422 if (select_playhead_priority_target (target)) {
1423 request_locate (target);
1428 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
1434 PostTransportWork ptw = post_transport_work();
1439 boost::shared_ptr<RouteList> rl = routes.reader();
1440 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1441 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1442 if (tr && tr->get_captured_samples () != 0) {
1448 /* stop and locate are merged here because they share a lot of common stuff */
1451 now = localtime (&xnow);
1454 auditioner->cancel_audition ();
1458 begin_reversible_command (Operations::capture);
1459 _have_captured = true;
1462 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
1464 if (abort && did_record) {
1465 /* no reason to save the session file when we remove sources
1467 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
1470 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1471 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1473 tr->transport_stopped_wallclock (*now, xnow, abort);
1477 if (abort && did_record) {
1478 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1481 boost::shared_ptr<RouteList> r = routes.reader ();
1484 commit_reversible_command ();
1485 /* increase take name */
1486 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
1487 string newname = config.get_take_name();
1488 config.set_take_name(bump_name_number (newname));
1492 if (_engine.running()) {
1493 PostTransportWork ptw = post_transport_work ();
1495 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1496 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1498 VCAList v = _vca_manager->vcas ();
1499 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1500 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1503 update_latency_compensation (false, false);
1506 /* If we are not synced to a "true" external master, and we're not
1507 * handling an explicit locate, we should consider whether or not to
1508 * "auto-return". This could mean going to a specifically requested
1509 * location, or just back to the start of the last roll.
1512 if (transport_master_no_external_or_using_engine() && !(ptw & PostTransportLocate)) {
1514 bool do_locate = false;
1516 if (_requested_return_sample >= 0) {
1518 /* explicit return request pre-queued in event list. overrides everything else */
1520 _transport_sample = _requested_return_sample;
1522 /* cancel this request */
1523 _requested_return_sample = -1;
1526 } else if (Config->get_auto_return_target_list()) {
1528 samplepos_t jump_to;
1530 if (select_playhead_priority_target (jump_to)) {
1532 /* there's a valid target (we don't care how it
1536 _transport_sample = jump_to;
1541 /* roll aborted (typically capture) with
1542 * auto-return enabled
1545 _transport_sample = _last_roll_location;
1552 if (do_locate && synced_to_engine()) {
1554 /* We will unconditionally locate to _transport_sample
1555 * below, which will refill playback buffers based on
1556 * _transport_sample, and maximises the buffering they
1559 * But if we are synced to engine (JACK), we should
1560 * locate the engine (JACK) as well. We would follow
1561 * the engine (JACK) on the next process cycle, but
1562 * since we're going to do a locate below anyway,
1563 * it seems pointless to not use just do it ourselves
1564 * right now, rather than wait for the engine (JACK) to
1565 * provide the new position on the next cycle.
1567 * Despite the generic name of the called method
1568 * (::transport_locate()) this method only does
1569 * anything if the audio/MIDI backend is JACK.
1572 _engine.transport_locate (_transport_sample);
1578 unset_preroll_record_trim ();
1580 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
1583 if (ptw & (PostTransportClearSubstate|PostTransportStop)) {
1584 unset_play_range ();
1585 if (!Config->get_loop_is_mode()) {
1590 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
1593 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
1594 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1595 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
1596 (*i)->non_realtime_locate (_transport_sample);
1598 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1600 /* we will be back */
1607 VCAList v = _vca_manager->vcas ();
1608 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1609 (*i)->non_realtime_locate (_transport_sample);
1613 have_looped = false;
1615 /* don't bother with this stuff if we're disconnected from the engine,
1616 because there will be no process callbacks to deliver stuff from
1619 if (_engine.running() && !_engine.freewheeling()) {
1620 // need to queue this in the next RT cycle
1621 _send_timecode_update = true;
1623 if (transport_master()->type() == MTC) {
1624 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
1626 /* This (::non_realtime_stop()) gets called by main
1627 process thread, which will lead to confusion
1628 when calling AsyncMIDIPort::write().
1630 Something must be done. XXX
1632 send_mmc_locate (_transport_sample);
1636 if ((ptw & PostTransportLocate) && get_record_enabled()) {
1637 /* This is scheduled by realtime_stop(), which is also done
1638 * when a slave requests /locate/ for an initial sync.
1639 * We can't hold up the slave for long with a save() here,
1640 * without breaking its initial sync cycle.
1642 * save state only if there's no slave or if it's not yet locked.
1644 if (!transport_master_is_external() || !transport_master()->locked()) {
1645 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
1646 SaveSessionRequested (_current_snapshot_name);
1651 /* save the current state of things if appropriate */
1653 if (did_record && !saved) {
1654 SaveSessionRequested (_current_snapshot_name);
1657 PositionChanged (_transport_sample); /* EMIT SIGNAL */
1658 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
1659 TransportStateChange (); /* EMIT SIGNAL */
1660 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
1662 ptw = PostTransportWork (ptw & ~(PostTransportStop|PostTransportClearSubstate));
1663 set_post_transport_work (ptw);
1667 Session::unset_play_loop ()
1671 clear_events (SessionEvent::AutoLoop);
1672 set_track_loop (false);
1673 /* likely need to flush track buffers: this will locate us to wherever we are */
1674 add_post_transport_work (PostTransportLocate);
1675 TFSM_EVENT (TransportFSM::ButlerRequired);
1676 TransportStateChange (); /* EMIT SIGNAL */
1681 Session::set_track_loop (bool yn)
1683 Location* loc = _locations->auto_loop_location ();
1689 boost::shared_ptr<RouteList> rl = routes.reader ();
1691 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1692 if (*i && !(*i)->is_private_route()) {
1693 (*i)->set_loop (yn ? loc : 0);
1699 Session::worst_latency_preroll () const
1701 return _worst_output_latency + _worst_input_latency;
1705 Session::unset_play_range ()
1707 _play_range = false;
1708 _clear_event_type (SessionEvent::RangeStop);
1709 _clear_event_type (SessionEvent::RangeLocate);
1713 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1717 /* Called from event-processing context */
1719 unset_play_range ();
1721 if (range.empty()) {
1722 /* _play_range set to false in unset_play_range()
1724 if (!leave_rolling) {
1725 /* stop transport */
1726 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1734 /* cancel loop play */
1737 list<AudioRange>::size_type sz = range.size();
1741 list<AudioRange>::iterator i = range.begin();
1742 list<AudioRange>::iterator next;
1744 while (i != range.end()) {
1749 /* locating/stopping is subject to delays for declicking.
1752 samplepos_t requested_sample = i->end;
1754 if (requested_sample > current_block_size) {
1755 requested_sample -= current_block_size;
1757 requested_sample = 0;
1760 if (next == range.end()) {
1761 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1763 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1771 } else if (sz == 1) {
1773 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1778 /* save range so we can do auto-return etc. */
1780 current_audio_range = range;
1782 /* now start rolling at the right place */
1784 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1787 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1788 TransportStateChange ();
1792 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1794 AudioRange ar (start, end, 0);
1795 list<AudioRange> lar;
1798 request_play_range (&lar, true);
1802 Session::set_requested_return_sample (samplepos_t return_to)
1804 _requested_return_sample = return_to;
1808 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1810 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1811 ev->target2_sample = start;
1816 Session::engine_halted ()
1818 /* there will be no more calls to process(), so
1819 we'd better clean up for ourselves, right now.
1821 We can't queue SessionEvents because they only get
1822 handled from within a process callback.
1825 /* this just stops the FSM engine ... it doesn't change the state of
1826 * the FSM directly or anything else ... but the FSM will be
1827 * reinitialized when we call its ::start() method from
1828 * ::engine_running() (if we ever get there)
1831 _transport_fsm->stop ();
1833 /* Synchronously do the realtime part of a transport stop.
1835 * Calling this will cause the butler to asynchronously run
1836 * ::non_realtime_stop() where the rest of the "stop" work will be
1840 realtime_stop (false, true);
1844 Session::engine_running ()
1846 _transport_fsm->start ();
1850 Session::xrun_recovery ()
1854 Xrun (_transport_sample); /* EMIT SIGNAL */
1856 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1858 /* it didn't actually halt, but we need
1859 to handle things in the same way.
1867 Session::route_processors_changed (RouteProcessorChange c)
1869 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1873 if (c.type == RouteProcessorChange::MeterPointChange) {
1878 if (c.type == RouteProcessorChange::RealTimeChange) {
1884 update_latency_compensation (false, false);
1890 Session::allow_auto_play (bool yn)
1892 auto_play_legal = yn;
1897 Session::send_mmc_locate (samplepos_t t)
1903 if (!_engine.freewheeling()) {
1904 Timecode::Time time;
1905 timecode_time_subframes (t, time);
1906 send_immediate_mmc (MIDI::MachineControlCommand (time));
1910 /** Ask the transport to not send timecode until further notice. The suspension
1911 * will come into effect some finite time after this call, and timecode_transmission_suspended()
1912 * should be checked by the caller to find out when.
1915 Session::request_suspend_timecode_transmission ()
1917 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
1922 Session::request_resume_timecode_transmission ()
1924 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
1929 Session::timecode_transmission_suspended () const
1931 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
1934 boost::shared_ptr<TransportMaster>
1935 Session::transport_master() const
1937 return TransportMasterManager::instance().current();
1941 Session::transport_master_is_external () const
1943 return TransportMasterManager::instance().current() && config.get_external_sync();
1947 Session::transport_master_no_external_or_using_engine () const
1949 return !TransportMasterManager::instance().current() || !config.get_external_sync() || (TransportMasterManager::instance().current()->type() == Engine);
1953 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
1955 /* Runs in process() context */
1957 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
1959 if (master->can_loop()) {
1960 request_play_loop (false);
1961 } else if (master->has_loop()) {
1962 request_play_loop (true);
1965 /* slave change, reset any DiskIO block on disk output because it is no
1966 longer valid with a new slave.
1969 DiskReader::dec_no_disk_output ();
1972 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
1974 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
1977 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
1978 MTCSyncStateChanged(mtc_master->locked() );
1980 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
1981 MTCSyncStateChanged( false );
1983 mtc_status_connection.disconnect ();
1986 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
1989 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
1990 LTCSyncStateChanged (ltc_master->locked() );
1992 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
1993 LTCSyncStateChanged( false );
1995 ltc_status_connection.disconnect ();
1999 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
2001 // need to queue this for next process() cycle
2002 _send_timecode_update = true;
2004 boost::shared_ptr<RouteList> rl = routes.reader();
2005 const bool externally_slaved = transport_master_is_external();
2007 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2008 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2009 if (tr && !tr->is_private_route()) {
2010 tr->set_slaved (externally_slaved);
2018 Session::transport_stopped() const
2020 return _transport_fsm->stopped();
2024 Session::transport_rolling() const
2026 return _transport_speed != 0.0 && _count_in_samples == 0 && _remaining_latency_preroll == 0;
2030 Session::locate_pending () const
2032 return _transport_fsm->locating();
2036 Session::declick_in_progress () const
2038 return _transport_fsm->declick_in_progress();