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/audio_backend.h"
49 #include "ardour/audioengine.h"
50 #include "ardour/auditioner.h"
51 #include "ardour/automation_watch.h"
52 #include "ardour/butler.h"
53 #include "ardour/click.h"
54 #include "ardour/debug.h"
55 #include "ardour/disk_reader.h"
56 #include "ardour/location.h"
57 #include "ardour/playlist.h"
58 #include "ardour/profile.h"
59 #include "ardour/scene_changer.h"
60 #include "ardour/session.h"
61 #include "ardour/transport_fsm.h"
62 #include "ardour/transport_master.h"
63 #include "ardour/transport_master_manager.h"
64 #include "ardour/tempo.h"
65 #include "ardour/operations.h"
66 #include "ardour/vca.h"
67 #include "ardour/vca_manager.h"
70 using namespace ARDOUR;
75 # define ENSURE_PROCESS_THREAD do {} while (0)
77 # define ENSURE_PROCESS_THREAD \
79 if (!AudioEngine::instance()->in_process_thread()) { \
80 PBD::stacktrace (std::cerr, 30); \
86 #define TFSM_EVENT(evtype) { _transport_fsm->enqueue (new TransportFSM::Event (evtype)); }
87 #define TFSM_STOP(abort,clear) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::StopTransport,abort,clear)); }
88 #define TFSM_LOCATE(target,roll,flush,loop,force) { _transport_fsm->enqueue (new TransportFSM::Event (TransportFSM::Locate,target,roll,flush,loop,force)); }
90 /* *****************************************************************************
91 * REALTIME ACTIONS (to be called on state transitions)
92 * ****************************************************************************/
95 Session::realtime_stop (bool abort, bool clear_state)
97 ENSURE_PROCESS_THREAD;
99 DEBUG_TRACE (DEBUG::Transport, string_compose ("realtime stop @ %1 speed = %2\n", _transport_sample, _transport_speed));
100 PostTransportWork todo = PostTransportWork (0);
102 if (_last_transport_speed < 0.0f) {
103 todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
104 _default_transport_speed = 1.0;
105 DiskReader::inc_no_disk_output (); // for the buffer reversal
107 todo = PostTransportWork (todo | PostTransportStop);
112 boost::shared_ptr<RouteList> r = routes.reader ();
114 for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
115 (*i)->realtime_handle_transport_stopped ();
118 DEBUG_TRACE (DEBUG::Transport, string_compose ("stop complete, auto-return scheduled for return to %1\n", _requested_return_sample));
121 todo = PostTransportWork (todo | PostTransportAbort);
125 todo = PostTransportWork (todo | PostTransportClearSubstate);
129 add_post_transport_work (todo);
132 _clear_event_type (SessionEvent::RangeStop);
133 _clear_event_type (SessionEvent::RangeLocate);
135 //clear our solo-selection, if there is one
136 if ( solo_selection_active() ) {
137 solo_selection ( _soloSelection, false );
140 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
141 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
143 if (clear_state && !Config->get_loop_is_mode()) {
147 reset_slave_state ();
149 _transport_speed = 0;
150 _target_transport_speed = 0;
153 g_atomic_int_set (&_playback_load, 100);
154 g_atomic_int_set (&_capture_load, 100);
156 if (config.get_use_video_sync()) {
157 waiting_for_sync_offset = true;
161 TFSM_EVENT (TransportFSM::ButlerRequired);
165 /** @param with_mmc true to send a MMC locate command when the locate is done */
167 Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_end, bool force, bool with_mmc)
169 ENSURE_PROCESS_THREAD;
171 if (target_sample < 0) {
172 error << _("Locate called for negative sample position - ignored") << endmsg;
176 bool need_butler = false;
178 /* Locates for seamless looping are fairly different from other
179 * locates. They assume that the diskstream buffers for each track
180 * already have the correct data in them, and thus there is no need to
181 * actually tell the tracks to locate. What does need to be done,
182 * though, is all the housekeeping that is associated with non-linear
183 * changes in the value of _transport_sample.
186 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 for loop end %4 force %5 mmc %6\n",
187 target_sample, with_roll, with_flush, for_loop_end, force, with_mmc));
189 if (!force && _transport_sample == target_sample && !loop_changing && !for_loop_end) {
191 /* already at the desired position. Not forced to locate,
192 the loop isn't changing, so unless we're told to
193 start rolling also, there's nothing to do but
194 tell the world where we are (again).
198 set_transport_speed (1.0, 0, false);
200 loop_changing = false;
201 TFSM_EVENT (TransportFSM::LocateDone);
202 Located (); /* EMIT SIGNAL */
206 // Update Timecode time
207 _transport_sample = target_sample;
208 _nominal_jack_transport_sample = boost::none;
209 // Bump seek counter so that any in-process locate in the butler
210 // thread(s?) can restart.
211 g_atomic_int_inc (&_seek_counter);
212 _last_roll_or_reversal_location = target_sample;
214 _remaining_latency_preroll = worst_latency_preroll_buffer_size_ceil ();
216 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
218 /* do "stopped" stuff if:
221 * no autoplay in effect AND
222 * we're not going to keep rolling after the locate AND
223 * !(playing a loop with JACK sync) AND
224 * we're not synced to an external transport master
229 /* it is important here that we use the internal state of the transport
230 FSM, not the public facing result of ::transport_rolling()
232 bool transport_was_stopped = _transport_fsm->stopped();
234 if (!transport_was_stopped &&
235 (!auto_play_legal || !config.get_auto_play()) &&
237 !(synced_to_engine() && play_loop) &&
238 !(config.get_external_sync() && !synced_to_engine())) {
240 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
241 transport_was_stopped = true;
245 /* Tell all routes to do the RT part of locate */
247 boost::shared_ptr<RouteList> r = routes.reader ();
248 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
249 (*i)->realtime_locate (for_loop_end);
253 if (force || !for_loop_end || loop_changing) {
255 PostTransportWork todo = PostTransportLocate;
257 if (with_roll && transport_was_stopped) {
258 todo = PostTransportWork (todo | PostTransportRoll);
261 add_post_transport_work (todo);
266 /* this is functionally what clear_clicks() does but with a tentative lock */
268 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
270 if (clickm.locked()) {
272 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
281 /* switch from input if we're going to roll */
282 if (Config->get_monitoring_model() == HardwareMonitoring) {
283 set_track_monitor_input_status (!config.get_auto_input());
286 /* otherwise we're going to stop, so do the opposite */
287 if (Config->get_monitoring_model() == HardwareMonitoring) {
288 set_track_monitor_input_status (true);
292 /* cancel looped playback if transport pos outside of loop range */
295 Location* al = _locations->auto_loop_location();
298 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
300 // located outside the loop: cancel looping directly, this is called from event handling context
304 if (!Config->get_loop_is_mode()) {
305 set_play_loop (false, false);
307 /* this will make the non_realtime_locate() in the butler
308 which then causes seek() in tracks actually do the right
311 set_track_loop (false);
314 } else if (_transport_sample == al->start()) {
316 // located to start of loop - this is looping, basically
320 if (_last_roll_location != al->start()) {
321 /* didn't start at loop start - playback must have
322 * started before loop since we've now hit the loop
325 add_post_transport_work (PostTransportLocate);
331 boost::shared_ptr<RouteList> rl = routes.reader();
333 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
334 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
336 if (tr && tr->rec_enable_control()->get_value()) {
337 // tell it we've looped, so it can deal with the record state
338 tr->transport_looped (_transport_sample);
343 TransportLooped(); // EMIT SIGNAL
349 TFSM_EVENT (TransportFSM::ButlerRequired);
351 TFSM_EVENT (TransportFSM::LocateDone);
352 loop_changing = false;
355 _send_timecode_update = true;
358 send_mmc_locate (_transport_sample);
361 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
362 if (!synced_to_engine () || _transport_sample == _engine.transport_sample ()) {
363 Located (); /* EMIT SIGNAL */
368 Session::post_locate ()
370 if (transport_master_is_external() && !synced_to_engine()) {
371 const samplepos_t current_master_position = TransportMasterManager::instance().get_current_position_in_process_context();
372 if (abs (current_master_position - _transport_sample) > TransportMasterManager::instance().current()->resolution()) {
373 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
378 /** Set the transport speed.
379 * Called from the process thread.
380 * @param speed New speed
383 Session::set_transport_speed (double speed, samplepos_t destination_sample, bool abort, bool clear_state, bool as_default)
385 ENSURE_PROCESS_THREAD;
386 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
387 speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
389 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
390 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
394 speed = min ((double) Config->get_max_transport_speed(), speed);
395 } else if (speed < 0) {
396 speed = max ((double) -Config->get_max_transport_speed(), speed);
399 double new_engine_speed = 1.0;
401 new_engine_speed = fabs (speed);
402 if (speed < 0) speed = -1;
403 if (speed > 0) speed = 1;
406 if (_transport_speed == speed && new_engine_speed == _engine_speed) {
407 if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
408 _default_transport_speed = 1.0;
413 #if 0 // TODO pref: allow vari-speed recording
414 if (actively_recording() && speed != 1.0 && speed != 0.0) {
415 /* no varispeed during recording */
416 DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, sample %2\n",
417 _transport_speed, _transport_sample));
422 _target_transport_speed = fabs(speed);
423 _engine_speed = new_engine_speed;
425 if (transport_rolling() && speed == 0.0) {
427 /* we are rolling and we want to stop */
429 if (Config->get_monitoring_model() == HardwareMonitoring) {
430 set_track_monitor_input_status (true);
433 if (synced_to_engine ()) {
435 /* do this here because our response to the slave won't
439 _count_in_once = false;
443 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
445 if (!auto_return_enabled) {
446 _requested_return_sample = destination_sample;
451 TFSM_STOP (abort, false);
453 } else if (transport_stopped() && speed == 1.0) {
456 _default_transport_speed = speed;
459 /* we are stopped and we want to start rolling at speed 1 */
461 if (Config->get_loop_is_mode() && play_loop) {
463 Location *location = _locations->auto_loop_location();
466 if (_transport_sample != location->start()) {
468 /* force tracks to do their thing */
469 set_track_loop (true);
471 /* jump to start and then roll from there */
473 request_locate (location->start(), true);
479 if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
480 set_track_monitor_input_status (false);
483 TFSM_EVENT (TransportFSM::StartTransport);
487 /* not zero, not 1.0 ... varispeed */
489 // TODO handled transport start.. _remaining_latency_preroll
490 // and reversal of playback direction.
492 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
493 warning << string_compose (
494 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
501 if (actively_recording()) {
506 if (speed > 0.0 && _transport_sample == current_end_sample()) {
510 if (speed < 0.0 && _transport_sample == 0) {
516 /* if we are reversing relative to the current speed, or relative to the speed
517 before the last stop, then we have to do extra work.
520 PostTransportWork todo = PostTransportWork (0);
522 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
523 todo = PostTransportWork (todo | PostTransportReverse);
524 DiskReader::inc_no_disk_output (); // for the buffer reversal
525 _last_roll_or_reversal_location = _transport_sample;
528 _last_transport_speed = _transport_speed;
529 _transport_speed = speed;
532 _default_transport_speed = speed;
536 add_post_transport_work (todo);
537 TFSM_EVENT (TransportFSM::ButlerRequired);
540 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
542 /* throttle signal emissions.
543 * when slaved [_last]_transport_speed
544 * usually changes every cycle (tiny amounts due to DLL).
545 * Emitting a signal every cycle is overkill and unwarranted.
547 * Using _last_transport_speed is not acceptable,
548 * since it allows for large changes over a long period
549 * of time. Hence we introduce a dedicated variable to keep track
551 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
552 * for TransportStateChange() here is the ShuttleControl display.
554 if (fabs (_signalled_varispeed - actual_speed ()) > .002
555 // still, signal hard changes to 1.0 and 0.0:
556 || (actual_speed () == 1.0 && _signalled_varispeed != 1.0)
557 || (actual_speed () == 0.0 && _signalled_varispeed != 0.0)
560 TransportStateChange (); /* EMIT SIGNAL */
561 _signalled_varispeed = actual_speed ();
566 /** Stop the transport. */
568 Session::stop_transport (bool abort, bool clear_state)
570 ENSURE_PROCESS_THREAD;
572 _count_in_once = false;
574 DEBUG_TRACE (DEBUG::Transport, string_compose ("time to actually stop with TS @ %1\n", _transport_sample));
576 realtime_stop (abort, clear_state);
579 /** Called from the process thread */
581 Session::start_transport ()
583 ENSURE_PROCESS_THREAD;
584 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
586 _last_roll_location = _transport_sample;
587 _last_roll_or_reversal_location = _transport_sample;
588 _remaining_latency_preroll = worst_latency_preroll_buffer_size_ceil ();
592 /* if record status is Enabled, move it to Recording. if its
593 already Recording, move it to Disabled.
596 switch (record_status()) {
598 if (!config.get_punch_in()) {
599 /* This is only for UIs (keep blinking rec-en before
600 * punch-in, don't show rec-region etc). The UI still
601 * depends on SessionEvent::PunchIn and ensuing signals.
603 * The disk-writers handle punch in/out internally
604 * in their local delay-compensated timeframe.
612 disable_record (false);
620 _transport_speed = _default_transport_speed;
621 _target_transport_speed = _transport_speed;
623 if (!_engine.freewheeling()) {
625 timecode_time_subframes (_transport_sample, time);
626 if (transport_master()->type() == MTC) {
627 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
630 if ((actively_recording () || (config.get_punch_in () && get_record_enabled ()))
631 && click_data && (config.get_count_in () || _count_in_once)) {
632 _count_in_once = false;
633 /* calculate count-in duration (in audio samples)
634 * - use [fixed] tempo/meter at _transport_sample
635 * - calc duration of 1 bar + time-to-beat before or at transport_sample
637 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
638 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
640 const double num = meter.divisions_per_bar ();
641 const double den = meter.note_divisor ();
642 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
643 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
645 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
647 double dt = _count_in_samples / num;
648 if (bar_fract == 0) {
649 /* at bar boundary, count-in 2 bars before start. */
650 _count_in_samples *= 2;
652 /* beats left after full bar until roll position */
653 _count_in_samples *= 1. + bar_fract;
656 if (_count_in_samples > _remaining_latency_preroll) {
657 _remaining_latency_preroll = _count_in_samples;
661 samplepos_t cf = _transport_sample - _count_in_samples;
662 samplecnt_t offset = _click_io->connected_latency (true);
663 while (cf < _transport_sample + offset) {
664 add_click (cf, clickbeat == 0);
666 clickbeat = fmod (clickbeat + 1, num);
669 if (_count_in_samples < _remaining_latency_preroll) {
670 _count_in_samples = _remaining_latency_preroll;
675 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
676 TransportStateChange (); /* EMIT SIGNAL */
680 Session::should_roll_after_locate () const
682 /* a locate must previously have been requested and completed before
683 * this answer can be considered correct
686 return ((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (post_transport_work() & PostTransportRoll);
690 /** Do any transport work in the audio thread that needs to be done after the
691 * butler thread is finished. Audio thread, realtime safe.
694 Session::butler_completed_transport_work ()
696 ENSURE_PROCESS_THREAD;
697 PostTransportWork ptw = post_transport_work ();
699 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler done, RT cleanup for %1\n", enum_2_string (ptw)));
701 if (ptw & PostTransportAudition) {
702 if (auditioner && auditioner->auditioning()) {
703 process_function = &Session::process_audition;
705 process_function = &Session::process_with_events;
707 ptw = PostTransportWork (ptw & ~PostTransportAudition);
708 set_post_transport_work (ptw);
711 if (ptw & PostTransportLocate) {
713 ptw = PostTransportWork (ptw & ~PostTransportLocate);
714 set_post_transport_work (ptw);
715 loop_changing = false;
716 TFSM_EVENT (TransportFSM::LocateDone);
719 bool start_after_butler_done_msg = false;
721 if ((ptw & (PostTransportReverse|PostTransportRoll))) {
722 start_after_butler_done_msg = true;
725 ptw = PostTransportWork (ptw & ~(PostTransportAdjustPlaybackBuffering|PostTransportAdjustCaptureBuffering|PostTransportOverWrite|PostTransportReverse|PostTransportRoll));
726 set_post_transport_work (ptw);
730 if (_transport_fsm->waiting_for_butler()) {
731 TFSM_EVENT (TransportFSM::ButlerDone);
734 DiskReader::dec_no_disk_output ();
736 if (start_after_butler_done_msg) {
737 if (_transport_speed) {
738 /* reversal is done ... tell TFSM that it is time to start*/
739 TFSM_EVENT (TransportFSM::StartTransport);
745 Session::schedule_butler_for_transport_work ()
747 assert (_transport_fsm->waiting_for_butler ());
748 DEBUG_TRACE (DEBUG::Butler, "summon butler for transport work\n");
749 _butler->schedule_transport_work ();
753 Session::maybe_stop (samplepos_t limit)
755 ENSURE_PROCESS_THREAD;
756 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
757 if (synced_to_engine ()) {
758 _engine.transport_stop ();
760 TFSM_EVENT (TransportFSM::StopTransport);
768 Session::micro_locate (samplecnt_t distance)
770 ENSURE_PROCESS_THREAD;
772 boost::shared_ptr<RouteList> rl = routes.reader();
773 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
774 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
775 if (tr && !tr->can_internal_playback_seek (distance)) {
780 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
782 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
783 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
785 tr->internal_playback_seek (distance);
789 _transport_sample += distance;
794 Session::flush_all_inserts ()
796 ENSURE_PROCESS_THREAD;
797 boost::shared_ptr<RouteList> r = routes.reader ();
799 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
800 (*i)->flush_processors ();
804 /* *****************************************************************************
805 * END REALTIME ACTIONS
806 * ****************************************************************************/
809 Session::add_post_transport_work (PostTransportWork ptw)
811 PostTransportWork oldval;
812 PostTransportWork newval;
816 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
817 newval = PostTransportWork (oldval | ptw);
818 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
824 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
828 Session::should_ignore_transport_request (TransportRequestSource src, TransportRequestType type) const
830 if (config.get_external_sync()) {
831 if (TransportMasterManager::instance().current()->allow_request (src, type)) {
841 Session::synced_to_engine() const
843 return config.get_external_sync() && TransportMasterManager::instance().current()->type() == Engine;
847 Session::request_sync_source (boost::shared_ptr<TransportMaster> tm)
849 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportMaster, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
850 ev->transport_master = tm;
851 DEBUG_TRACE (DEBUG::Slave, "sent request for new transport master\n");
856 Session::request_transport_speed (double speed, bool as_default, TransportRequestSource origin)
858 if (synced_to_engine()) {
860 _engine.transport_start ();
862 _engine.transport_stop ();
867 if (should_ignore_transport_request (origin, TR_Speed)) {
871 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
872 ev->third_yes_or_no = as_default; // as_default
873 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
877 /** Request a new transport speed, but if the speed parameter is exactly zero then use
878 * a very small +ve value to prevent the transport actually stopping. This method should
879 * be used by callers who are varying transport speed but don't ever want to stop it.
882 Session::request_transport_speed_nonzero (double speed, bool as_default, TransportRequestSource origin)
884 if (should_ignore_transport_request (origin, TransportRequestType (TR_Speed|TR_Start))) {
892 request_transport_speed (speed, as_default);
896 Session::request_stop (bool abort, bool clear_state, TransportRequestSource origin)
898 if (synced_to_engine()) {
899 _engine.transport_stop ();
903 if (should_ignore_transport_request (origin, TR_Stop)) {
907 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
908 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));
913 Session::request_locate (samplepos_t target_sample, bool with_roll, TransportRequestSource origin)
915 if (synced_to_engine()) {
916 _engine.transport_locate (target_sample);
920 if (should_ignore_transport_request (origin, TR_Locate)) {
924 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
925 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_sample));
930 Session::force_locate (samplepos_t target_sample, bool with_roll)
932 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
933 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_sample));
938 Session::unset_preroll_record_trim ()
940 _preroll_record_trim_len = 0;
944 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
946 if (actively_recording ()) {
949 unset_preroll_record_trim ();
951 config.set_punch_in (false);
952 config.set_punch_out (false);
954 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
955 _preroll_record_trim_len = preroll;
956 maybe_enable_record ();
957 request_locate (pos, true);
958 set_requested_return_sample (rec_in);
962 Session::request_count_in_record ()
964 if (actively_recording ()) {
967 if (transport_rolling()) {
970 maybe_enable_record ();
971 _count_in_once = true;
972 request_transport_speed (1.0, true);
976 Session::request_play_loop (bool yn, bool change_transport_roll)
978 if (transport_master_is_external() && yn) {
979 // don't attempt to loop when not using Internal Transport
980 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
985 Location *location = _locations->auto_loop_location();
988 if (location == 0 && yn) {
989 error << _("Cannot loop - no loop range defined")
994 if (change_transport_roll) {
995 if (transport_rolling()) {
996 /* start looping at current speed */
997 target_speed = transport_speed ();
999 /* currently stopped */
1001 /* start looping at normal speed */
1008 /* leave the speed alone */
1009 target_speed = transport_speed ();
1012 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn, change_transport_roll);
1013 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
1018 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
1020 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
1022 ev->audio_range = *range;
1024 ev->audio_range.clear ();
1026 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
1031 Session::request_cancel_play_range ()
1033 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
1039 Session::solo_selection_active ()
1041 if (_soloSelection.empty()) {
1048 Session::solo_selection (StripableList &list, bool new_state)
1050 boost::shared_ptr<ControlList> solo_list (new ControlList);
1051 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
1054 _soloSelection = list;
1056 _soloSelection.clear();
1058 boost::shared_ptr<RouteList> rl = get_routes();
1060 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1062 if ( !(*i)->is_track() ) {
1066 boost::shared_ptr<Stripable> s (*i);
1068 bool found = (std::find(list.begin(), list.end(), s) != list.end());
1069 if ( new_state && found ) {
1071 solo_list->push_back (s->solo_control());
1073 //must invalidate playlists on selected tracks, so only selected regions get heard
1074 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1076 boost::shared_ptr<Playlist> playlist = track->playlist();
1078 playlist->ContentsChanged();
1082 unsolo_list->push_back (s->solo_control());
1086 set_controls (solo_list, 1.0, Controllable::NoGroup);
1087 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
1092 Session::butler_transport_work ()
1094 /* Note: this function executes in the butler thread context */
1097 boost::shared_ptr<RouteList> r = routes.reader ();
1098 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
1099 bool finished = true;
1100 PostTransportWork ptw = post_transport_work();
1103 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));
1105 if (ptw & PostTransportLocate) {
1107 if (get_play_loop()) {
1109 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
1111 /* this locate might be happening while we are
1114 * Non-seamless looping will require a locate (below) that
1115 * will reset capture buffers and throw away data.
1117 * Rather than first find all tracks and see if they
1118 * have outstanding data, just do a flush anyway. It
1119 * may be cheaper this way anyway, and is certainly
1123 bool more_disk_io_to_do = false;
1124 uint32_t errors = 0;
1127 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
1133 if (more_disk_io_to_do) {
1142 if (ptw & PostTransportAdjustPlaybackBuffering) {
1143 /* need to prevent concurrency with ARDOUR::Reader::run(),
1144 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1145 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
1146 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1147 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1149 tr->adjust_playback_buffering ();
1150 /* and refill those buffers ... */
1152 (*i)->non_realtime_locate (_transport_sample);
1154 VCAList v = _vca_manager->vcas ();
1155 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1156 (*i)->non_realtime_locate (_transport_sample);
1160 if (ptw & PostTransportAdjustCaptureBuffering) {
1161 /* need to prevent concurrency with ARDOUR::DiskWriter::run(),
1162 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1163 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
1164 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1165 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1167 tr->adjust_capture_buffering ();
1172 if (ptw & PostTransportReverse) {
1176 /* don't seek if locate will take care of that in non_realtime_stop() */
1178 if (!(ptw & PostTransportLocate)) {
1179 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1180 (*i)->non_realtime_locate (_transport_sample);
1182 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1183 /* new request, stop seeking, and start again */
1184 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1188 VCAList v = _vca_manager->vcas ();
1189 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1190 (*i)->non_realtime_locate (_transport_sample);
1195 if (ptw & PostTransportLocate) {
1196 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
1197 non_realtime_locate ();
1200 if (ptw & PostTransportStop) {
1201 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
1203 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1208 if (ptw & PostTransportOverWrite) {
1209 non_realtime_overwrite (on_entry, finished);
1211 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1216 if (ptw & PostTransportAudition) {
1217 non_realtime_set_audition ();
1220 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1222 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()));
1226 Session::non_realtime_overwrite (int on_entry, bool& finished)
1228 boost::shared_ptr<RouteList> rl = routes.reader();
1229 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1230 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1231 if (tr && tr->pending_overwrite ()) {
1232 tr->overwrite_existing_buffers ();
1234 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1242 Session::non_realtime_locate ()
1244 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
1246 if (Config->get_loop_is_mode() && get_play_loop()) {
1248 Location *loc = _locations->auto_loop_location();
1250 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
1251 /* jumped out of loop range: stop tracks from looping,
1252 but leave loop (mode) enabled.
1254 set_track_loop (false);
1256 } else if (loc && ((loc->start() <= _transport_sample) || (loc->end() > _transport_sample))) {
1258 /* jumping to start of loop. This might have been done before but it is
1259 * idempotent and cheap. Doing it here ensures that when we start playback
1260 * outside the loop we still flip tracks into the magic seamless mode
1263 set_track_loop (true);
1266 set_track_loop (false);
1271 /* no more looping .. should have been noticed elsewhere */
1278 boost::shared_ptr<RouteList> rl = routes.reader();
1281 gint sc = g_atomic_int_get (&_seek_counter);
1282 tf = _transport_sample;
1284 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1285 (*i)->non_realtime_locate (tf);
1286 if (sc != g_atomic_int_get (&_seek_counter)) {
1287 std::cerr << "\n\nLOCATE INTERRUPTED BY LOCATE!!!\n\n";
1294 /* VCAs are quick to locate because they have no data (except
1295 automation) associated with them. Don't bother with a
1296 restart mechanism here, but do use the same transport sample
1297 that the Routes used.
1299 VCAList v = _vca_manager->vcas ();
1300 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1301 (*i)->non_realtime_locate (tf);
1305 _scene_changer->locate (_transport_sample);
1307 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
1308 rather than clearing them so that the RT thread has to spend time constructing
1309 them (in Session::click).
1315 Session::select_playhead_priority_target (samplepos_t& jump_to)
1317 if (!transport_master_no_external_or_using_engine() || !config.get_auto_return()) {
1321 jump_to = _last_roll_location;
1322 return jump_to >= 0;
1326 Session::follow_playhead_priority ()
1330 if (select_playhead_priority_target (target)) {
1331 request_locate (target);
1336 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
1342 PostTransportWork ptw = post_transport_work();
1347 boost::shared_ptr<RouteList> rl = routes.reader();
1348 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1349 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1350 if (tr && tr->get_captured_samples () != 0) {
1356 /* stop and locate are merged here because they share a lot of common stuff */
1359 now = localtime (&xnow);
1362 auditioner->cancel_audition ();
1366 begin_reversible_command (Operations::capture);
1367 _have_captured = true;
1370 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
1372 if (abort && did_record) {
1373 /* no reason to save the session file when we remove sources
1375 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
1378 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1379 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1381 tr->transport_stopped_wallclock (*now, xnow, abort);
1385 if (abort && did_record) {
1386 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1389 boost::shared_ptr<RouteList> r = routes.reader ();
1392 commit_reversible_command ();
1393 /* increase take name */
1394 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
1395 string newname = config.get_take_name();
1396 config.set_take_name(bump_name_number (newname));
1400 if (_engine.running()) {
1401 PostTransportWork ptw = post_transport_work ();
1403 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1404 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1406 VCAList v = _vca_manager->vcas ();
1407 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1408 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1412 /* If we are not synced to a "true" external master, and we're not
1413 * handling an explicit locate, we should consider whether or not to
1414 * "auto-return". This could mean going to a specifically requested
1415 * location, or just back to the start of the last roll.
1418 if (transport_master_no_external_or_using_engine() && !(ptw & PostTransportLocate)) {
1420 bool do_locate = false;
1422 if (_requested_return_sample >= 0) {
1424 /* explicit return request pre-queued in event list. overrides everything else */
1426 _transport_sample = _requested_return_sample;
1428 /* cancel this request */
1429 _requested_return_sample = -1;
1432 } else if (Config->get_auto_return_target_list()) {
1434 samplepos_t jump_to;
1436 if (select_playhead_priority_target (jump_to)) {
1438 /* there's a valid target (we don't care how it
1442 _transport_sample = jump_to;
1447 /* roll aborted (typically capture) with
1448 * auto-return enabled
1451 _transport_sample = _last_roll_location;
1458 if (do_locate && synced_to_engine()) {
1460 /* We will unconditionally locate to _transport_sample
1461 * below, which will refill playback buffers based on
1462 * _transport_sample, and maximises the buffering they
1465 * But if we are synced to engine (JACK), we should
1466 * locate the engine (JACK) as well. We would follow
1467 * the engine (JACK) on the next process cycle, but
1468 * since we're going to do a locate below anyway,
1469 * it seems pointless to not use just do it ourselves
1470 * right now, rather than wait for the engine (JACK) to
1471 * provide the new position on the next cycle.
1473 * Despite the generic name of the called method
1474 * (::transport_locate()) this method only does
1475 * anything if the audio/MIDI backend is JACK.
1478 _engine.transport_locate (_transport_sample);
1484 unset_preroll_record_trim ();
1486 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
1489 if (ptw & (PostTransportClearSubstate|PostTransportStop)) {
1490 unset_play_range ();
1491 if (!loop_changing && !Config->get_loop_is_mode()) {
1496 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
1499 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
1500 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1501 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
1502 (*i)->non_realtime_locate (_transport_sample);
1504 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1506 /* we will be back */
1513 VCAList v = _vca_manager->vcas ();
1514 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1515 (*i)->non_realtime_locate (_transport_sample);
1519 have_looped = false;
1521 /* don't bother with this stuff if we're disconnected from the engine,
1522 because there will be no process callbacks to deliver stuff from
1525 if (_engine.running() && !_engine.freewheeling()) {
1526 // need to queue this in the next RT cycle
1527 _send_timecode_update = true;
1529 if (transport_master()->type() == MTC) {
1530 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
1532 /* This (::non_realtime_stop()) gets called by main
1533 process thread, which will lead to confusion
1534 when calling AsyncMIDIPort::write().
1536 Something must be done. XXX
1538 send_mmc_locate (_transport_sample);
1542 if ((ptw & PostTransportLocate) && get_record_enabled()) {
1543 /* This is scheduled by realtime_stop(), which is also done
1544 * when a slave requests /locate/ for an initial sync.
1545 * We can't hold up the slave for long with a save() here,
1546 * without breaking its initial sync cycle.
1548 * save state only if there's no slave or if it's not yet locked.
1550 if (!transport_master_is_external() || !transport_master()->locked()) {
1551 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
1552 SaveSessionRequested (_current_snapshot_name);
1557 /* save the current state of things if appropriate */
1559 if (did_record && !saved) {
1560 SaveSessionRequested (_current_snapshot_name);
1563 PositionChanged (_transport_sample); /* EMIT SIGNAL */
1564 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
1565 TransportStateChange (); /* EMIT SIGNAL */
1566 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
1568 ptw = PostTransportWork (ptw & ~(PostTransportAbort|PostTransportStop|PostTransportClearSubstate));
1569 set_post_transport_work (ptw);
1573 Session::set_play_loop (bool yn, bool change_transport_state)
1575 ENSURE_PROCESS_THREAD;
1576 /* Called from event-handling context */
1578 DEBUG_TRACE (DEBUG::Transport, string_compose ("set_play_loop (%1)\n", yn));
1582 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
1583 /* nothing to do, or can't change loop status while recording */
1587 if (yn && synced_to_engine()) {
1588 warning << string_compose (
1589 _("Looping cannot be supported while %1 is using JACK transport.\n"
1590 "Recommend changing the configured options"), PROGRAM_NAME)
1598 have_looped = false;
1602 unset_play_range ();
1603 /* set all tracks to use internal looping */
1604 set_track_loop (true);
1606 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
1608 if (!Config->get_loop_is_mode()) {
1609 /* args: positition, roll=true, flush=true, for_loop_end=false, force buffer, refill looping */
1610 /* set this so that when/if we stop for locate,
1611 we do not call unset_play_loop(). This is a
1612 crude mechanism. Got a better idea?
1614 loop_changing = true;
1615 TFSM_LOCATE (loc->start(), true, true, false, true);
1616 } else if (!transport_rolling()) {
1617 /* loop-is-mode: not rolling, just locate to loop start */
1618 TFSM_LOCATE (loc->start(), false, true, false, true);
1627 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
1628 TransportStateChange ();
1632 Session::unset_play_loop (bool change_transport_state)
1637 clear_events (SessionEvent::AutoLoop);
1638 set_track_loop (false);
1640 /* likely need to flush track buffers: this will locate us to wherever we are */
1642 if (change_transport_state && transport_rolling ()) {
1643 TFSM_EVENT (TransportFSM::StopTransport);
1646 overwrite_some_buffers (boost::shared_ptr<Route>(), LoopDisabled);
1648 TransportStateChange (); /* EMIT SIGNAL */
1653 Session::set_track_loop (bool yn)
1655 Location* loc = _locations->auto_loop_location ();
1661 boost::shared_ptr<RouteList> rl = routes.reader ();
1663 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1664 if (*i && !(*i)->is_private_route()) {
1665 (*i)->set_loop (yn ? loc : 0);
1669 DiskReader::reset_loop_declick (loc, nominal_sample_rate());
1673 Session::worst_latency_preroll () const
1675 return _worst_output_latency + _worst_input_latency;
1679 Session::worst_latency_preroll_buffer_size_ceil () const
1681 return lrintf (ceil ((_worst_output_latency + _worst_input_latency) / (float) current_block_size) * current_block_size);
1685 Session::unset_play_range ()
1687 _play_range = false;
1688 _clear_event_type (SessionEvent::RangeStop);
1689 _clear_event_type (SessionEvent::RangeLocate);
1693 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1697 /* Called from event-processing context */
1699 unset_play_range ();
1701 if (range.empty()) {
1702 /* _play_range set to false in unset_play_range()
1704 if (!leave_rolling) {
1705 /* stop transport */
1706 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1714 /* cancel loop play */
1717 list<AudioRange>::size_type sz = range.size();
1721 list<AudioRange>::iterator i = range.begin();
1722 list<AudioRange>::iterator next;
1724 while (i != range.end()) {
1729 /* locating/stopping is subject to delays for declicking.
1732 samplepos_t requested_sample = i->end;
1734 if (requested_sample > current_block_size) {
1735 requested_sample -= current_block_size;
1737 requested_sample = 0;
1740 if (next == range.end()) {
1741 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1743 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1751 } else if (sz == 1) {
1753 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1758 /* save range so we can do auto-return etc. */
1760 current_audio_range = range;
1762 /* now start rolling at the right place */
1764 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1767 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1768 TransportStateChange ();
1772 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1774 AudioRange ar (start, end, 0);
1775 list<AudioRange> lar;
1778 request_play_range (&lar, true);
1782 Session::set_requested_return_sample (samplepos_t return_to)
1784 _requested_return_sample = return_to;
1788 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1790 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1791 ev->target2_sample = start;
1796 Session::engine_halted ()
1798 /* there will be no more calls to process(), so
1799 we'd better clean up for ourselves, right now.
1801 We can't queue SessionEvents because they only get
1802 handled from within a process callback.
1805 /* this just stops the FSM engine ... it doesn't change the state of
1806 * the FSM directly or anything else ... but the FSM will be
1807 * reinitialized when we call its ::start() method from
1808 * ::engine_running() (if we ever get there)
1811 _transport_fsm->stop ();
1813 /* Synchronously do the realtime part of a transport stop.
1815 * Calling this will cause the butler to asynchronously run
1816 * ::non_realtime_stop() where the rest of the "stop" work will be
1820 realtime_stop (false, true);
1824 Session::engine_running ()
1826 _transport_fsm->start ();
1830 Session::xrun_recovery ()
1834 Xrun (_transport_sample); /* EMIT SIGNAL */
1836 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1838 /* it didn't actually halt, but we need
1839 to handle things in the same way.
1847 Session::route_processors_changed (RouteProcessorChange c)
1849 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1853 if (c.type == RouteProcessorChange::MeterPointChange) {
1858 if (c.type == RouteProcessorChange::RealTimeChange) {
1864 update_latency_compensation (false, false);
1870 Session::allow_auto_play (bool yn)
1872 auto_play_legal = yn;
1877 Session::send_mmc_locate (samplepos_t t)
1883 if (!_engine.freewheeling()) {
1884 Timecode::Time time;
1885 timecode_time_subframes (t, time);
1886 send_immediate_mmc (MIDI::MachineControlCommand (time));
1890 /** Ask the transport to not send timecode until further notice. The suspension
1891 * will come into effect some finite time after this call, and timecode_transmission_suspended()
1892 * should be checked by the caller to find out when.
1895 Session::request_suspend_timecode_transmission ()
1897 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
1902 Session::request_resume_timecode_transmission ()
1904 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
1909 Session::timecode_transmission_suspended () const
1911 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
1914 boost::shared_ptr<TransportMaster>
1915 Session::transport_master() const
1917 return TransportMasterManager::instance().current();
1921 Session::transport_master_is_external () const
1923 return TransportMasterManager::instance().current() && config.get_external_sync();
1927 Session::transport_master_no_external_or_using_engine () const
1929 return !TransportMasterManager::instance().current() || !config.get_external_sync() || (TransportMasterManager::instance().current()->type() == Engine);
1933 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
1935 /* Runs in process() context */
1937 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
1939 if (master->can_loop()) {
1940 request_play_loop (false);
1941 } else if (master->has_loop()) {
1942 request_play_loop (true);
1945 /* slave change, reset any DiskIO block on disk output because it is no
1946 longer valid with a new slave.
1949 DiskReader::dec_no_disk_output ();
1952 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
1954 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
1957 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
1958 MTCSyncStateChanged(mtc_master->locked() );
1960 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
1961 MTCSyncStateChanged( false );
1963 mtc_status_connection.disconnect ();
1966 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
1969 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
1970 LTCSyncStateChanged (ltc_master->locked() );
1972 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
1973 LTCSyncStateChanged( false );
1975 ltc_status_connection.disconnect ();
1979 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
1981 // need to queue this for next process() cycle
1982 _send_timecode_update = true;
1984 boost::shared_ptr<RouteList> rl = routes.reader();
1985 const bool externally_slaved = transport_master_is_external();
1987 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1988 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1989 if (tr && !tr->is_private_route()) {
1990 tr->set_slaved (externally_slaved);
1998 Session::transport_stopped() const
2000 return _transport_fsm->stopped();
2004 Session::transport_stopped_or_stopping() const
2006 return _transport_fsm->stopped() || _transport_fsm->stopping();
2010 Session::transport_rolling() const
2012 return _transport_speed != 0.0 && _count_in_samples == 0 && _remaining_latency_preroll == 0;
2016 Session::locate_pending () const
2018 return _transport_fsm->locating();
2022 Session::declick_in_progress () const
2024 return _transport_fsm->declick_in_progress();