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 ();
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 ();
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 if (ptw & PostTransportAdjustPlaybackBuffering) {
720 /* we blocked output while this happened */
721 DiskReader::dec_no_disk_output ();
722 ptw = PostTransportWork (ptw & ~PostTransportAdjustPlaybackBuffering);
723 set_post_transport_work (ptw);
726 bool start_after_butler_done_msg = false;
728 if ((ptw & (PostTransportReverse|PostTransportRoll))) {
729 start_after_butler_done_msg = true;
732 ptw = PostTransportWork (ptw & ~(PostTransportAdjustCaptureBuffering|PostTransportOverWrite|PostTransportReverse|PostTransportRoll));
733 set_post_transport_work (ptw);
737 if (_transport_fsm->waiting_for_butler()) {
738 TFSM_EVENT (TransportFSM::ButlerDone);
741 DiskReader::dec_no_disk_output ();
743 if (start_after_butler_done_msg) {
744 if (_transport_speed) {
745 /* reversal is done ... tell TFSM that it is time to start*/
746 TFSM_EVENT (TransportFSM::StartTransport);
752 Session::schedule_butler_for_transport_work ()
754 assert (_transport_fsm->waiting_for_butler ());
755 DEBUG_TRACE (DEBUG::Butler, "summon butler for transport work\n");
756 _butler->schedule_transport_work ();
760 Session::maybe_stop (samplepos_t limit)
762 ENSURE_PROCESS_THREAD;
763 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
764 if (synced_to_engine ()) {
765 _engine.transport_stop ();
767 TFSM_EVENT (TransportFSM::StopTransport);
775 Session::micro_locate (samplecnt_t distance)
777 ENSURE_PROCESS_THREAD;
779 boost::shared_ptr<RouteList> rl = routes.reader();
780 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
781 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
782 if (tr && !tr->can_internal_playback_seek (distance)) {
787 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
789 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
790 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
792 tr->internal_playback_seek (distance);
796 _transport_sample += distance;
801 Session::flush_all_inserts ()
803 ENSURE_PROCESS_THREAD;
804 boost::shared_ptr<RouteList> r = routes.reader ();
806 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
807 (*i)->flush_processors ();
811 /* *****************************************************************************
812 * END REALTIME ACTIONS
813 * ****************************************************************************/
816 Session::add_post_transport_work (PostTransportWork ptw)
818 PostTransportWork oldval;
819 PostTransportWork newval;
823 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
824 newval = PostTransportWork (oldval | ptw);
825 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
831 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
835 Session::should_ignore_transport_request (TransportRequestSource src, TransportRequestType type) const
837 if (config.get_external_sync()) {
838 if (TransportMasterManager::instance().current()->allow_request (src, type)) {
848 Session::synced_to_engine() const
850 return config.get_external_sync() && TransportMasterManager::instance().current()->type() == Engine;
854 Session::request_sync_source (boost::shared_ptr<TransportMaster> tm)
856 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportMaster, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
857 ev->transport_master = tm;
858 DEBUG_TRACE (DEBUG::Slave, "sent request for new transport master\n");
863 Session::request_transport_speed (double speed, bool as_default, TransportRequestSource origin)
865 if (synced_to_engine()) {
867 _engine.transport_start ();
869 _engine.transport_stop ();
874 if (should_ignore_transport_request (origin, TR_Speed)) {
878 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
879 ev->third_yes_or_no = as_default; // as_default
880 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
884 /** Request a new transport speed, but if the speed parameter is exactly zero then use
885 * a very small +ve value to prevent the transport actually stopping. This method should
886 * be used by callers who are varying transport speed but don't ever want to stop it.
889 Session::request_transport_speed_nonzero (double speed, bool as_default, TransportRequestSource origin)
891 if (should_ignore_transport_request (origin, TransportRequestType (TR_Speed|TR_Start))) {
899 request_transport_speed (speed, as_default);
903 Session::request_stop (bool abort, bool clear_state, TransportRequestSource origin)
905 if (synced_to_engine()) {
906 _engine.transport_stop ();
910 if (should_ignore_transport_request (origin, TR_Stop)) {
914 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
915 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));
920 Session::request_locate (samplepos_t target_sample, bool with_roll, TransportRequestSource origin)
922 if (synced_to_engine()) {
923 _engine.transport_locate (target_sample);
927 if (should_ignore_transport_request (origin, TR_Locate)) {
931 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
932 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_sample));
937 Session::force_locate (samplepos_t target_sample, bool with_roll)
939 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
940 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_sample));
945 Session::unset_preroll_record_trim ()
947 _preroll_record_trim_len = 0;
951 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
953 if (actively_recording ()) {
956 unset_preroll_record_trim ();
958 config.set_punch_in (false);
959 config.set_punch_out (false);
961 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
962 _preroll_record_trim_len = preroll;
963 maybe_enable_record ();
964 request_locate (pos, true);
965 set_requested_return_sample (rec_in);
969 Session::request_count_in_record ()
971 if (actively_recording ()) {
974 if (transport_rolling()) {
977 maybe_enable_record ();
978 _count_in_once = true;
979 request_transport_speed (1.0, true);
983 Session::request_play_loop (bool yn, bool change_transport_roll)
985 if (transport_master_is_external() && yn) {
986 // don't attempt to loop when not using Internal Transport
987 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
992 Location *location = _locations->auto_loop_location();
995 if (location == 0 && yn) {
996 error << _("Cannot loop - no loop range defined")
1001 if (change_transport_roll) {
1002 if (transport_rolling()) {
1003 /* start looping at current speed */
1004 target_speed = transport_speed ();
1006 /* currently stopped */
1008 /* start looping at normal speed */
1015 /* leave the speed alone */
1016 target_speed = transport_speed ();
1019 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn, change_transport_roll);
1020 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
1025 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
1027 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
1029 ev->audio_range = *range;
1031 ev->audio_range.clear ();
1033 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
1038 Session::request_cancel_play_range ()
1040 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
1046 Session::solo_selection_active ()
1048 if (_soloSelection.empty()) {
1055 Session::solo_selection (StripableList &list, bool new_state)
1057 boost::shared_ptr<ControlList> solo_list (new ControlList);
1058 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
1061 _soloSelection = list;
1063 _soloSelection.clear();
1065 boost::shared_ptr<RouteList> rl = get_routes();
1067 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1069 if ( !(*i)->is_track() ) {
1073 boost::shared_ptr<Stripable> s (*i);
1075 bool found = (std::find(list.begin(), list.end(), s) != list.end());
1076 if ( new_state && found ) {
1078 solo_list->push_back (s->solo_control());
1080 //must invalidate playlists on selected tracks, so only selected regions get heard
1081 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1083 boost::shared_ptr<Playlist> playlist = track->playlist();
1085 playlist->ContentsChanged();
1089 unsolo_list->push_back (s->solo_control());
1093 set_controls (solo_list, 1.0, Controllable::NoGroup);
1094 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
1099 Session::butler_transport_work ()
1101 /* Note: this function executes in the butler thread context */
1104 boost::shared_ptr<RouteList> r = routes.reader ();
1105 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
1106 bool finished = true;
1107 PostTransportWork ptw = post_transport_work();
1110 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));
1112 if (ptw & PostTransportLocate) {
1114 if (get_play_loop()) {
1116 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
1118 /* this locate might be happening while we are
1121 * Non-seamless looping will require a locate (below) that
1122 * will reset capture buffers and throw away data.
1124 * Rather than first find all tracks and see if they
1125 * have outstanding data, just do a flush anyway. It
1126 * may be cheaper this way anyway, and is certainly
1130 bool more_disk_io_to_do = false;
1131 uint32_t errors = 0;
1134 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
1140 if (more_disk_io_to_do) {
1149 if (ptw & PostTransportAdjustPlaybackBuffering) {
1150 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1151 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1153 tr->adjust_playback_buffering ();
1154 /* and refill those buffers ... */
1156 (*i)->non_realtime_locate (_transport_sample);
1158 VCAList v = _vca_manager->vcas ();
1159 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1160 (*i)->non_realtime_locate (_transport_sample);
1164 if (ptw & PostTransportAdjustCaptureBuffering) {
1165 /* need to prevent concurrency with ARDOUR::DiskWriter::run(),
1166 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1167 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
1168 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1169 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1171 tr->adjust_capture_buffering ();
1176 if (ptw & PostTransportReverse) {
1180 /* don't seek if locate will take care of that in non_realtime_stop() */
1182 if (!(ptw & PostTransportLocate)) {
1183 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1184 (*i)->non_realtime_locate (_transport_sample);
1186 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1187 /* new request, stop seeking, and start again */
1188 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1192 VCAList v = _vca_manager->vcas ();
1193 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1194 (*i)->non_realtime_locate (_transport_sample);
1199 if (ptw & PostTransportLocate) {
1200 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
1201 non_realtime_locate ();
1204 if (ptw & PostTransportStop) {
1205 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
1207 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1212 if (ptw & PostTransportOverWrite) {
1213 non_realtime_overwrite (on_entry, finished);
1215 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1220 if (ptw & PostTransportAudition) {
1221 non_realtime_set_audition ();
1224 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1226 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()));
1230 Session::non_realtime_overwrite (int on_entry, bool& finished)
1232 boost::shared_ptr<RouteList> rl = routes.reader();
1233 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1234 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1235 if (tr && tr->pending_overwrite ()) {
1236 tr->overwrite_existing_buffers ();
1238 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1246 Session::non_realtime_locate ()
1248 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
1250 if (Config->get_loop_is_mode() && get_play_loop()) {
1252 Location *loc = _locations->auto_loop_location();
1254 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
1255 /* jumped out of loop range: stop tracks from looping,
1256 but leave loop (mode) enabled.
1258 set_track_loop (false);
1260 } else if (loc && ((loc->start() <= _transport_sample) || (loc->end() > _transport_sample))) {
1262 /* jumping to start of loop. This might have been done before but it is
1263 * idempotent and cheap. Doing it here ensures that when we start playback
1264 * outside the loop we still flip tracks into the magic seamless mode
1267 set_track_loop (true);
1270 set_track_loop (false);
1275 /* no more looping .. should have been noticed elsewhere */
1282 boost::shared_ptr<RouteList> rl = routes.reader();
1285 gint sc = g_atomic_int_get (&_seek_counter);
1286 tf = _transport_sample;
1288 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1289 (*i)->non_realtime_locate (tf);
1290 if (sc != g_atomic_int_get (&_seek_counter)) {
1291 std::cerr << "\n\nLOCATE INTERRUPTED BY LOCATE!!!\n\n";
1298 /* VCAs are quick to locate because they have no data (except
1299 automation) associated with them. Don't bother with a
1300 restart mechanism here, but do use the same transport sample
1301 that the Routes used.
1303 VCAList v = _vca_manager->vcas ();
1304 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1305 (*i)->non_realtime_locate (tf);
1309 _scene_changer->locate (_transport_sample);
1311 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
1312 rather than clearing them so that the RT thread has to spend time constructing
1313 them (in Session::click).
1319 Session::select_playhead_priority_target (samplepos_t& jump_to)
1321 if (!transport_master_no_external_or_using_engine() || !config.get_auto_return()) {
1325 jump_to = _last_roll_location;
1326 return jump_to >= 0;
1330 Session::follow_playhead_priority ()
1334 if (select_playhead_priority_target (target)) {
1335 request_locate (target);
1340 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
1346 PostTransportWork ptw = post_transport_work();
1351 boost::shared_ptr<RouteList> rl = routes.reader();
1352 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1353 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1354 if (tr && tr->get_captured_samples () != 0) {
1360 /* stop and locate are merged here because they share a lot of common stuff */
1363 now = localtime (&xnow);
1366 auditioner->cancel_audition ();
1370 begin_reversible_command (Operations::capture);
1371 _have_captured = true;
1374 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
1376 if (abort && did_record) {
1377 /* no reason to save the session file when we remove sources
1379 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
1382 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1383 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1385 tr->transport_stopped_wallclock (*now, xnow, abort);
1389 if (abort && did_record) {
1390 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1393 boost::shared_ptr<RouteList> r = routes.reader ();
1396 commit_reversible_command ();
1397 /* increase take name */
1398 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
1399 string newname = config.get_take_name();
1400 config.set_take_name(bump_name_number (newname));
1404 if (_engine.running()) {
1405 PostTransportWork ptw = post_transport_work ();
1407 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1408 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1410 VCAList v = _vca_manager->vcas ();
1411 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1412 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1416 /* If we are not synced to a "true" external master, and we're not
1417 * handling an explicit locate, we should consider whether or not to
1418 * "auto-return". This could mean going to a specifically requested
1419 * location, or just back to the start of the last roll.
1422 if (transport_master_no_external_or_using_engine() && !(ptw & PostTransportLocate)) {
1424 bool do_locate = false;
1426 if (_requested_return_sample >= 0) {
1428 /* explicit return request pre-queued in event list. overrides everything else */
1430 _transport_sample = _requested_return_sample;
1432 /* cancel this request */
1433 _requested_return_sample = -1;
1436 } else if (Config->get_auto_return_target_list()) {
1438 samplepos_t jump_to;
1440 if (select_playhead_priority_target (jump_to)) {
1442 /* there's a valid target (we don't care how it
1446 _transport_sample = jump_to;
1451 /* roll aborted (typically capture) with
1452 * auto-return enabled
1455 _transport_sample = _last_roll_location;
1462 if (do_locate && synced_to_engine()) {
1464 /* We will unconditionally locate to _transport_sample
1465 * below, which will refill playback buffers based on
1466 * _transport_sample, and maximises the buffering they
1469 * But if we are synced to engine (JACK), we should
1470 * locate the engine (JACK) as well. We would follow
1471 * the engine (JACK) on the next process cycle, but
1472 * since we're going to do a locate below anyway,
1473 * it seems pointless to not use just do it ourselves
1474 * right now, rather than wait for the engine (JACK) to
1475 * provide the new position on the next cycle.
1477 * Despite the generic name of the called method
1478 * (::transport_locate()) this method only does
1479 * anything if the audio/MIDI backend is JACK.
1482 _engine.transport_locate (_transport_sample);
1488 unset_preroll_record_trim ();
1490 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
1493 if (ptw & (PostTransportClearSubstate|PostTransportStop)) {
1494 unset_play_range ();
1495 if (!loop_changing && !Config->get_loop_is_mode()) {
1500 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
1503 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
1504 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1505 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
1506 (*i)->non_realtime_locate (_transport_sample);
1508 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1510 /* we will be back */
1517 VCAList v = _vca_manager->vcas ();
1518 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1519 (*i)->non_realtime_locate (_transport_sample);
1523 have_looped = false;
1525 /* don't bother with this stuff if we're disconnected from the engine,
1526 because there will be no process callbacks to deliver stuff from
1529 if (_engine.running() && !_engine.freewheeling()) {
1530 // need to queue this in the next RT cycle
1531 _send_timecode_update = true;
1533 if (transport_master()->type() == MTC) {
1534 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
1536 /* This (::non_realtime_stop()) gets called by main
1537 process thread, which will lead to confusion
1538 when calling AsyncMIDIPort::write().
1540 Something must be done. XXX
1542 send_mmc_locate (_transport_sample);
1546 if ((ptw & PostTransportLocate) && get_record_enabled()) {
1547 /* This is scheduled by realtime_stop(), which is also done
1548 * when a slave requests /locate/ for an initial sync.
1549 * We can't hold up the slave for long with a save() here,
1550 * without breaking its initial sync cycle.
1552 * save state only if there's no slave or if it's not yet locked.
1554 if (!transport_master_is_external() || !transport_master()->locked()) {
1555 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
1556 SaveSessionRequested (_current_snapshot_name);
1561 /* save the current state of things if appropriate */
1563 if (did_record && !saved) {
1564 SaveSessionRequested (_current_snapshot_name);
1567 PositionChanged (_transport_sample); /* EMIT SIGNAL */
1568 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
1569 TransportStateChange (); /* EMIT SIGNAL */
1570 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
1572 ptw = PostTransportWork (ptw & ~(PostTransportAbort|PostTransportStop|PostTransportClearSubstate));
1573 set_post_transport_work (ptw);
1577 Session::set_play_loop (bool yn, bool change_transport_state)
1579 ENSURE_PROCESS_THREAD;
1580 /* Called from event-handling context */
1582 DEBUG_TRACE (DEBUG::Transport, string_compose ("set_play_loop (%1)\n", yn));
1586 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
1587 /* nothing to do, or can't change loop status while recording */
1591 if (yn && synced_to_engine()) {
1592 warning << string_compose (
1593 _("Looping cannot be supported while %1 is using JACK transport.\n"
1594 "Recommend changing the configured options"), PROGRAM_NAME)
1602 have_looped = false;
1606 unset_play_range ();
1607 /* set all tracks to use internal looping */
1608 set_track_loop (true);
1610 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
1612 if (!Config->get_loop_is_mode()) {
1613 /* args: positition, roll=true, flush=true, for_loop_end=false, force buffer, refill looping */
1614 /* set this so that when/if we stop for locate,
1615 we do not call unset_play_loop(). This is a
1616 crude mechanism. Got a better idea?
1618 loop_changing = true;
1619 TFSM_LOCATE (loc->start(), true, true, false, true);
1620 } else if (!transport_rolling()) {
1621 /* loop-is-mode: not rolling, just locate to loop start */
1622 TFSM_LOCATE (loc->start(), false, true, false, true);
1631 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
1632 TransportStateChange ();
1636 Session::unset_play_loop (bool change_transport_state)
1641 clear_events (SessionEvent::AutoLoop);
1642 set_track_loop (false);
1644 /* likely need to flush track buffers: this will locate us to wherever we are */
1646 if (change_transport_state && transport_rolling ()) {
1647 TFSM_EVENT (TransportFSM::StopTransport);
1650 overwrite_some_buffers (boost::shared_ptr<Route>(), LoopDisabled);
1652 TransportStateChange (); /* EMIT SIGNAL */
1657 Session::set_track_loop (bool yn)
1659 Location* loc = _locations->auto_loop_location ();
1665 boost::shared_ptr<RouteList> rl = routes.reader ();
1667 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1668 if (*i && !(*i)->is_private_route()) {
1669 (*i)->set_loop (yn ? loc : 0);
1673 DiskReader::reset_loop_declick (loc, nominal_sample_rate());
1677 Session::worst_latency_preroll () const
1679 return _worst_output_latency + _worst_input_latency;
1683 Session::unset_play_range ()
1685 _play_range = false;
1686 _clear_event_type (SessionEvent::RangeStop);
1687 _clear_event_type (SessionEvent::RangeLocate);
1691 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1695 /* Called from event-processing context */
1697 unset_play_range ();
1699 if (range.empty()) {
1700 /* _play_range set to false in unset_play_range()
1702 if (!leave_rolling) {
1703 /* stop transport */
1704 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1712 /* cancel loop play */
1715 list<AudioRange>::size_type sz = range.size();
1719 list<AudioRange>::iterator i = range.begin();
1720 list<AudioRange>::iterator next;
1722 while (i != range.end()) {
1727 /* locating/stopping is subject to delays for declicking.
1730 samplepos_t requested_sample = i->end;
1732 if (requested_sample > current_block_size) {
1733 requested_sample -= current_block_size;
1735 requested_sample = 0;
1738 if (next == range.end()) {
1739 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1741 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1749 } else if (sz == 1) {
1751 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1756 /* save range so we can do auto-return etc. */
1758 current_audio_range = range;
1760 /* now start rolling at the right place */
1762 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1765 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1766 TransportStateChange ();
1770 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1772 AudioRange ar (start, end, 0);
1773 list<AudioRange> lar;
1776 request_play_range (&lar, true);
1780 Session::set_requested_return_sample (samplepos_t return_to)
1782 _requested_return_sample = return_to;
1786 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1788 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1789 ev->target2_sample = start;
1794 Session::engine_halted ()
1796 /* there will be no more calls to process(), so
1797 we'd better clean up for ourselves, right now.
1799 We can't queue SessionEvents because they only get
1800 handled from within a process callback.
1803 /* this just stops the FSM engine ... it doesn't change the state of
1804 * the FSM directly or anything else ... but the FSM will be
1805 * reinitialized when we call its ::start() method from
1806 * ::engine_running() (if we ever get there)
1809 _transport_fsm->stop ();
1811 /* Synchronously do the realtime part of a transport stop.
1813 * Calling this will cause the butler to asynchronously run
1814 * ::non_realtime_stop() where the rest of the "stop" work will be
1818 realtime_stop (false, true);
1822 Session::engine_running ()
1824 _transport_fsm->start ();
1828 Session::xrun_recovery ()
1832 Xrun (_transport_sample); /* EMIT SIGNAL */
1834 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1836 /* it didn't actually halt, but we need
1837 to handle things in the same way.
1845 Session::route_processors_changed (RouteProcessorChange c)
1847 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1851 if (c.type == RouteProcessorChange::MeterPointChange) {
1856 if (c.type == RouteProcessorChange::RealTimeChange) {
1862 update_latency_compensation (false, false);
1868 Session::allow_auto_play (bool yn)
1870 auto_play_legal = yn;
1875 Session::send_mmc_locate (samplepos_t t)
1881 if (!_engine.freewheeling()) {
1882 Timecode::Time time;
1883 timecode_time_subframes (t, time);
1884 send_immediate_mmc (MIDI::MachineControlCommand (time));
1888 /** Ask the transport to not send timecode until further notice. The suspension
1889 * will come into effect some finite time after this call, and timecode_transmission_suspended()
1890 * should be checked by the caller to find out when.
1893 Session::request_suspend_timecode_transmission ()
1895 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
1900 Session::request_resume_timecode_transmission ()
1902 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
1907 Session::timecode_transmission_suspended () const
1909 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
1912 boost::shared_ptr<TransportMaster>
1913 Session::transport_master() const
1915 return TransportMasterManager::instance().current();
1919 Session::transport_master_is_external () const
1921 return TransportMasterManager::instance().current() && config.get_external_sync();
1925 Session::transport_master_no_external_or_using_engine () const
1927 return !TransportMasterManager::instance().current() || !config.get_external_sync() || (TransportMasterManager::instance().current()->type() == Engine);
1931 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
1933 /* Runs in process() context */
1935 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
1937 if (master->can_loop()) {
1938 request_play_loop (false);
1939 } else if (master->has_loop()) {
1940 request_play_loop (true);
1943 /* slave change, reset any DiskIO block on disk output because it is no
1944 longer valid with a new slave.
1947 DiskReader::dec_no_disk_output ();
1950 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
1952 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
1955 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
1956 MTCSyncStateChanged(mtc_master->locked() );
1958 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
1959 MTCSyncStateChanged( false );
1961 mtc_status_connection.disconnect ();
1964 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
1967 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
1968 LTCSyncStateChanged (ltc_master->locked() );
1970 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
1971 LTCSyncStateChanged( false );
1973 ltc_status_connection.disconnect ();
1977 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
1979 // need to queue this for next process() cycle
1980 _send_timecode_update = true;
1982 boost::shared_ptr<RouteList> rl = routes.reader();
1983 const bool externally_slaved = transport_master_is_external();
1985 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1986 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1987 if (tr && !tr->is_private_route()) {
1988 tr->set_slaved (externally_slaved);
1996 Session::transport_stopped() const
1998 return _transport_fsm->stopped();
2002 Session::transport_rolling() const
2004 return _transport_speed != 0.0 && _count_in_samples == 0 && _remaining_latency_preroll == 0;
2008 Session::locate_pending () const
2010 return _transport_fsm->locating();
2014 Session::declick_in_progress () const
2016 return _transport_fsm->declick_in_progress();