2 * Copyright (C) 1999-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005-2009 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2007 Jesse Chappell <jesse@essej.net>
5 * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
6 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
7 * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
8 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
10 * Copyright (C) 2015 GZharun <grygoriiz@wavesglobal.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "libardour-config.h"
35 #include <boost/algorithm/string/erase.hpp>
37 #include "pbd/error.h"
38 #include "pbd/enumwriter.h"
40 #include "pbd/memento_command.h"
41 #include "pbd/pthread_utils.h"
42 #include "pbd/stacktrace.h"
45 #include "midi++/mmc.h"
46 #include "midi++/port.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/auditioner.h"
50 #include "ardour/automation_watch.h"
51 #include "ardour/butler.h"
52 #include "ardour/click.h"
53 #include "ardour/debug.h"
54 #include "ardour/disk_reader.h"
55 #include "ardour/location.h"
56 #include "ardour/playlist.h"
57 #include "ardour/profile.h"
58 #include "ardour/scene_changer.h"
59 #include "ardour/session.h"
60 #include "ardour/transport_fsm.h"
61 #include "ardour/transport_master.h"
62 #include "ardour/transport_master_manager.h"
63 #include "ardour/tempo.h"
64 #include "ardour/operations.h"
65 #include "ardour/vca.h"
66 #include "ardour/vca_manager.h"
69 using namespace ARDOUR;
74 # define ENSURE_PROCESS_THREAD do {} while (0)
76 # define ENSURE_PROCESS_THREAD \
78 if (!AudioEngine::instance()->in_process_thread()) { \
79 PBD::stacktrace (std::cerr, 20); \
85 #define TFSM_EVENT(ev) { DEBUG_TRACE (DEBUG::TFSMEvents, string_compose ("TFSM(%1)\n", typeid(ev).name())); _transport_fsm->enqueue (ev); }
87 /* *****************************************************************************
88 * REALTIME ACTIONS (to be called on state transitions)
89 * ****************************************************************************/
92 Session::realtime_stop (bool abort, bool clear_state)
94 ENSURE_PROCESS_THREAD;
96 DEBUG_TRACE (DEBUG::Transport, string_compose ("realtime stop @ %1 speed = %2\n", _transport_sample, _transport_speed));
97 PostTransportWork todo = PostTransportWork (0);
99 if (_last_transport_speed < 0.0f) {
100 todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
101 _default_transport_speed = 1.0;
102 DiskReader::inc_no_disk_output (); // for the buffer reversal
104 todo = PostTransportWork (todo | PostTransportStop);
109 boost::shared_ptr<RouteList> r = routes.reader ();
111 for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
112 (*i)->realtime_handle_transport_stopped ();
115 DEBUG_TRACE (DEBUG::Transport, string_compose ("stop complete, auto-return scheduled for return to %1\n", _requested_return_sample));
117 /* the duration change is not guaranteed to have happened, but is likely */
119 todo = PostTransportWork (todo | PostTransportDuration);
122 todo = PostTransportWork (todo | PostTransportAbort);
126 todo = PostTransportWork (todo | PostTransportClearSubstate);
130 add_post_transport_work (todo);
133 _clear_event_type (SessionEvent::RangeStop);
134 _clear_event_type (SessionEvent::RangeLocate);
136 //clear our solo-selection, if there is one
137 if ( solo_selection_active() ) {
138 solo_selection ( _soloSelection, false );
141 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
142 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
144 if (clear_state && !Config->get_loop_is_mode()) {
148 reset_slave_state ();
150 _transport_speed = 0;
151 _target_transport_speed = 0;
154 g_atomic_int_set (&_playback_load, 100);
155 g_atomic_int_set (&_capture_load, 100);
157 if (config.get_use_video_sync()) {
158 waiting_for_sync_offset = true;
162 TFSM_EVENT (TransportFSM::butler_required());
167 Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, 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 if (synced_to_engine()) {
180 samplepos_t ignore1, ignore2;
182 transport_master()->speed_and_position (sp, pos, ignore1, ignore2, 0);
184 if (target_sample != pos) {
186 if (config.get_jack_time_master()) {
187 /* actually locate now, since otherwise jack_timebase_callback
188 will use the incorrect _transport_sample and report an old
189 and incorrect time to Jack transport
191 do_locate (target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc);
194 /* tell JACK to change transport position, and we will
195 follow along later in ::follow_slave()
198 _engine.transport_locate (target_sample);
200 if (sp != 1.0f && with_roll) {
201 _engine.transport_start ();
207 do_locate (target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc);
211 /** @param with_mmc true to send a MMC locate command when the locate is done */
213 Session::do_locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force, bool with_mmc)
215 ENSURE_PROCESS_THREAD;
217 bool need_butler = false;
219 /* Locates for seamless looping are fairly different from other
220 * locates. They assume that the diskstream buffers for each track
221 * already have the correct data in them, and thus there is no need to
222 * actually tell the tracks to locate. What does need to be done,
223 * though, is all the housekeeping that is associated with non-linear
224 * changes in the value of _transport_sample.
227 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 loop-enabled %4 force %5 mmc %6\n",
228 target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc));
230 if (!force && _transport_sample == target_sample && !loop_changing && !for_loop_enabled) {
232 /* already at the desired position. Not forced to locate,
233 the loop isn't changing, so unless we're told to
234 start rolling also, there's nothing to do but
235 tell the world where we are (again).
239 set_transport_speed (1.0, 0, false);
241 loop_changing = false;
242 TFSM_EVENT (TransportFSM::locate_done());
243 Located (); /* EMIT SIGNAL */
247 // Update Timecode time
248 _transport_sample = target_sample;
249 // Bump seek counter so that any in-process locate in the butler
250 // thread(s?) can restart.
251 g_atomic_int_inc (&_seek_counter);
252 _last_roll_or_reversal_location = target_sample;
253 _remaining_latency_preroll = worst_latency_preroll ();
254 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
256 /* do "stopped" stuff if:
259 * no autoplay in effect AND
260 * we're not going to keep rolling after the locate AND
261 * !(playing a loop with JACK sync) AND
262 * we're not synced to an external transport master
266 bool transport_was_stopped = !transport_rolling();
268 if (!transport_was_stopped &&
269 (!auto_play_legal || !config.get_auto_play()) &&
271 !(synced_to_engine() && play_loop) &&
272 (!Profile->get_trx() || !(config.get_external_sync() && !synced_to_engine()))) {
274 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
275 transport_was_stopped = true;
279 /* Tell all routes to do the RT part of locate */
281 boost::shared_ptr<RouteList> r = routes.reader ();
282 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
283 (*i)->realtime_locate ();
287 if (force || !for_loop_enabled || loop_changing) {
289 PostTransportWork todo = PostTransportLocate;
291 if (with_roll && transport_was_stopped) {
292 todo = PostTransportWork (todo | PostTransportRoll);
295 add_post_transport_work (todo);
300 /* this is functionally what clear_clicks() does but with a tentative lock */
302 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
304 if (clickm.locked()) {
306 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
315 /* switch from input if we're going to roll */
316 if (Config->get_monitoring_model() == HardwareMonitoring) {
317 set_track_monitor_input_status (!config.get_auto_input());
320 /* otherwise we're going to stop, so do the opposite */
321 if (Config->get_monitoring_model() == HardwareMonitoring) {
322 set_track_monitor_input_status (true);
326 /* cancel looped playback if transport pos outside of loop range */
329 Location* al = _locations->auto_loop_location();
332 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
334 // located outside the loop: cancel looping directly, this is called from event handling context
338 if (!Config->get_loop_is_mode()) {
339 set_play_loop (false, _transport_speed);
341 if (Config->get_seamless_loop()) {
342 /* this will make the non_realtime_locate() in the butler
343 which then causes seek() in tracks actually do the right
346 set_track_loop (false);
350 } else if (_transport_sample == al->start()) {
352 // located to start of loop - this is looping, basically
356 if (_last_roll_location != al->start()) {
357 /* didn't start at loop start - playback must have
358 * started before loop since we've now hit the loop
361 add_post_transport_work (PostTransportLocate);
367 boost::shared_ptr<RouteList> rl = routes.reader();
369 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
370 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
372 if (tr && tr->rec_enable_control()->get_value()) {
373 // tell it we've looped, so it can deal with the record state
374 tr->transport_looped (_transport_sample);
379 TransportLooped(); // EMIT SIGNAL
385 TFSM_EVENT (TransportFSM::butler_required());
387 TFSM_EVENT (TransportFSM::locate_done());
390 loop_changing = false;
392 _send_timecode_update = true;
395 send_mmc_locate (_transport_sample);
398 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
399 if (!synced_to_engine () || _transport_sample == _engine.transport_sample ()) {
400 Located (); /* EMIT SIGNAL */
405 Session::post_locate ()
407 if (transport_master_is_external() && !synced_to_engine()) {
408 const samplepos_t current_master_position = TransportMasterManager::instance().get_current_position_in_process_context();
409 if (abs (current_master_position - _transport_sample) > TransportMasterManager::instance().current()->resolution()) {
410 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
415 /** Set the transport speed.
416 * Called from the process thread.
417 * @param speed New speed
420 Session::set_transport_speed (double speed, samplepos_t destination_sample, bool abort, bool clear_state, bool as_default)
422 ENSURE_PROCESS_THREAD;
423 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
424 speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
426 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
427 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
431 speed = min ((double) Config->get_max_transport_speed(), speed);
432 } else if (speed < 0) {
433 speed = max ((double) -Config->get_max_transport_speed(), speed);
436 double new_engine_speed = 1.0;
438 new_engine_speed = fabs (speed);
439 if (speed < 0) speed = -1;
440 if (speed > 0) speed = 1;
443 if (_transport_speed == speed && new_engine_speed == _engine_speed) {
444 if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
445 _default_transport_speed = 1.0;
450 #if 0 // TODO pref: allow vari-speed recording
451 if (actively_recording() && speed != 1.0 && speed != 0.0) {
452 /* no varispeed during recording */
453 DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, sample %2\n",
454 _transport_speed, _transport_sample));
459 _target_transport_speed = fabs(speed);
460 _engine_speed = new_engine_speed;
462 if (transport_rolling() && speed == 0.0) {
464 /* we are rolling and we want to stop */
466 if (Config->get_monitoring_model() == HardwareMonitoring) {
467 set_track_monitor_input_status (true);
470 if (synced_to_engine ()) {
472 /* do this here because our response to the slave won't
476 _count_in_once = false;
479 _engine.transport_stop ();
481 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
483 if (!auto_return_enabled) {
484 _requested_return_sample = destination_sample;
487 TFSM_EVENT (TransportFSM::stop_transport (abort, false));
490 } else if (transport_stopped() && speed == 1.0) {
492 _default_transport_speed = speed;
494 /* we are stopped and we want to start rolling at speed 1 */
496 if (Config->get_loop_is_mode() && play_loop) {
498 Location *location = _locations->auto_loop_location();
501 if (_transport_sample != location->start()) {
503 if (Config->get_seamless_loop()) {
504 /* force tracks to do their thing */
505 set_track_loop (true);
508 /* jump to start and then roll from there */
510 request_locate (location->start(), true);
516 if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
517 set_track_monitor_input_status (false);
520 if (synced_to_engine()) {
521 _engine.transport_start ();
522 _count_in_once = false;
524 TFSM_EVENT (TransportFSM::start_transport());
529 /* not zero, not 1.0 ... varispeed */
531 // TODO handled transport start.. _remaining_latency_preroll
532 // and reversal of playback direction.
534 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
535 warning << string_compose (
536 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
543 if (actively_recording()) {
548 if (speed > 0.0 && _transport_sample == current_end_sample()) {
552 if (speed < 0.0 && _transport_sample == 0) {
558 /* if we are reversing relative to the current speed, or relative to the speed
559 before the last stop, then we have to do extra work.
562 PostTransportWork todo = PostTransportWork (0);
564 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
565 todo = PostTransportWork (todo | PostTransportReverse);
566 DiskReader::inc_no_disk_output (); // for the buffer reversal
567 _last_roll_or_reversal_location = _transport_sample;
570 _last_transport_speed = _transport_speed;
571 _transport_speed = speed;
574 _default_transport_speed = speed;
578 add_post_transport_work (todo);
579 TFSM_EVENT (TransportFSM::butler_required());
582 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
584 /* throttle signal emissions.
585 * when slaved [_last]_transport_speed
586 * usually changes every cycle (tiny amounts due to DLL).
587 * Emitting a signal every cycle is overkill and unwarranted.
589 * Using _last_transport_speed is not acceptable,
590 * since it allows for large changes over a long period
591 * of time. Hence we introduce a dedicated variable to keep track
593 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
594 * for TransportStateChange() here is the ShuttleControl display.
596 if (fabs (_signalled_varispeed - actual_speed ()) > .002
597 // still, signal hard changes to 1.0 and 0.0:
598 || (actual_speed () == 1.0 && _signalled_varispeed != 1.0)
599 || (actual_speed () == 0.0 && _signalled_varispeed != 0.0)
602 TransportStateChange (); /* EMIT SIGNAL */
603 _signalled_varispeed = actual_speed ();
608 /** Stop the transport. */
610 Session::stop_transport (bool abort, bool clear_state)
612 ENSURE_PROCESS_THREAD;
614 _count_in_once = false;
616 DEBUG_TRACE (DEBUG::Transport, string_compose ("time to actually stop with TS @ %1\n", _transport_sample));
618 realtime_stop (abort, clear_state);
621 /** Called from the process thread */
623 Session::start_transport ()
625 ENSURE_PROCESS_THREAD;
626 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
628 _last_roll_location = _transport_sample;
629 _last_roll_or_reversal_location = _transport_sample;
630 _remaining_latency_preroll = worst_latency_preroll ();
634 /* if record status is Enabled, move it to Recording. if its
635 already Recording, move it to Disabled.
638 switch (record_status()) {
640 if (!config.get_punch_in()) {
641 /* This is only for UIs (keep blinking rec-en before
642 * punch-in, don't show rec-region etc). The UI still
643 * depends on SessionEvent::PunchIn and ensuing signals.
645 * The disk-writers handle punch in/out internally
646 * in their local delay-compensated timeframe.
654 disable_record (false);
662 _transport_speed = _default_transport_speed;
663 _target_transport_speed = _transport_speed;
665 if (!_engine.freewheeling()) {
667 timecode_time_subframes (_transport_sample, time);
668 if (transport_master()->type() == MTC) {
669 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
672 if ((actively_recording () || (config.get_punch_in () && get_record_enabled ()))
673 && click_data && (config.get_count_in () || _count_in_once)) {
674 _count_in_once = false;
675 /* calculate count-in duration (in audio samples)
676 * - use [fixed] tempo/meter at _transport_sample
677 * - calc duration of 1 bar + time-to-beat before or at transport_sample
679 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
680 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
682 const double num = meter.divisions_per_bar ();
683 const double den = meter.note_divisor ();
684 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
685 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
687 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
689 double dt = _count_in_samples / num;
690 if (bar_fract == 0) {
691 /* at bar boundary, count-in 2 bars before start. */
692 _count_in_samples *= 2;
694 /* beats left after full bar until roll position */
695 _count_in_samples *= 1. + bar_fract;
698 if (_count_in_samples > _remaining_latency_preroll) {
699 _remaining_latency_preroll = _count_in_samples;
703 samplepos_t cf = _transport_sample - _count_in_samples;
704 samplecnt_t offset = _click_io->connected_latency (true);
705 while (cf < _transport_sample + offset) {
706 add_click (cf, clickbeat == 0);
708 clickbeat = fmod (clickbeat + 1, num);
711 if (_count_in_samples < _remaining_latency_preroll) {
712 _count_in_samples = _remaining_latency_preroll;
717 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
718 TransportStateChange (); /* EMIT SIGNAL */
722 Session::should_roll_after_locate () const
724 /* a locate must previously have been requested and completed */
726 return ((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (post_transport_work() & PostTransportRoll);
730 /** Do any transport work in the audio thread that needs to be done after the
731 * butler thread is finished. Audio thread, realtime safe.
734 Session::butler_completed_transport_work ()
736 ENSURE_PROCESS_THREAD;
737 PostTransportWork ptw = post_transport_work ();
739 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler done, RT cleanup for %1\n", enum_2_string (ptw)));
741 if (ptw & PostTransportAudition) {
742 if (auditioner && auditioner->auditioning()) {
743 process_function = &Session::process_audition;
745 process_function = &Session::process_with_events;
749 if (ptw & PostTransportLocate) {
751 TFSM_EVENT (TransportFSM::locate_done());
754 if (ptw & PostTransportAdjustPlaybackBuffering) {
755 /* we blocked output while this happened */
756 DiskReader::dec_no_disk_output ();
760 /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
763 set_post_transport_work (PostTransportWork (0));
765 if (_transport_fsm->waiting_for_butler()) {
766 TFSM_EVENT (TransportFSM::butler_done());
769 DiskReader::dec_no_disk_output ();
773 Session::schedule_butler_for_transport_work ()
775 assert (_transport_fsm->waiting_for_butler ());
776 DEBUG_TRACE (DEBUG::Butler, "summon butler for transport work\n");
777 _butler->schedule_transport_work ();
781 Session::maybe_stop (samplepos_t limit)
783 ENSURE_PROCESS_THREAD;
784 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
785 if (synced_to_engine () && config.get_jack_time_master ()) {
786 _engine.transport_stop ();
787 } else if (!synced_to_engine ()) {
788 TFSM_EVENT (TransportFSM::stop_transport ());
796 Session::micro_locate (samplecnt_t distance)
798 ENSURE_PROCESS_THREAD;
800 boost::shared_ptr<RouteList> rl = routes.reader();
801 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
802 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
803 if (tr && !tr->can_internal_playback_seek (distance)) {
808 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
810 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
811 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
813 tr->internal_playback_seek (distance);
817 _transport_sample += distance;
822 Session::flush_all_inserts ()
824 ENSURE_PROCESS_THREAD;
825 boost::shared_ptr<RouteList> r = routes.reader ();
827 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
828 (*i)->flush_processors ();
833 Session::set_play_loop (bool yn, double speed)
835 ENSURE_PROCESS_THREAD;
836 /* Called from event-handling context */
840 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
841 /* nothing to do, or can't change loop status while recording */
845 if (yn && Config->get_seamless_loop() && synced_to_engine()) {
846 warning << string_compose (
847 _("Seamless looping cannot be supported while %1 is using JACK transport.\n"
848 "Recommend changing the configured options"), PROGRAM_NAME)
862 if (Config->get_seamless_loop()) {
863 if (!Config->get_loop_is_mode()) {
864 /* set all tracks to use internal looping */
865 set_track_loop (true);
867 /* we will do this in the locate to the start OR when we hit the end
868 * of the loop for the first time
872 /* set all tracks to NOT use internal looping */
873 set_track_loop (false);
876 /* Put the delick and loop events in into the event list. The declick event will
877 cause a de-clicking fade-out just before the end of the loop, and it will also result
878 in a fade-in when the loop restarts. The AutoLoop event will peform the actual loop.
883 auto_loop_declick_range (loc, dcp, dcl);
884 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
886 /* if requested to roll, locate to start of loop and
887 * roll but ONLY if we're not already rolling.
889 args: positition, roll=true, flush=true, with_loop=false, force buffer refill if seamless looping
892 if (Config->get_loop_is_mode()) {
893 /* loop IS a transport mode: if already
894 rolling, do not locate to loop start.
896 if (!transport_rolling() && (speed != 0.0)) {
897 TFSM_EVENT (TransportFSM::locate (loc->start(), true, true, false, true));
901 TFSM_EVENT (TransportFSM::locate (loc->start(), true, true, false, true));
911 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
912 TransportStateChange ();
915 /* *****************************************************************************
916 * END REALTIME ACTIONS
917 * ****************************************************************************/
921 Session::add_post_transport_work (PostTransportWork ptw)
923 PostTransportWork oldval;
924 PostTransportWork newval;
928 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
929 newval = PostTransportWork (oldval | ptw);
930 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
936 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
940 Session::should_ignore_transport_request (TransportRequestSource src, TransportRequestType type) const
942 if (config.get_external_sync()) {
943 if (TransportMasterManager::instance().current()->allow_request (src, type)) {
953 Session::synced_to_engine() const {
954 return config.get_external_sync() && TransportMasterManager::instance().current()->type() == Engine;
958 Session::request_sync_source (boost::shared_ptr<TransportMaster> tm)
960 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportMaster, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
961 ev->transport_master = tm;
962 DEBUG_TRACE (DEBUG::Slave, "sent request for new transport master\n");
967 Session::request_transport_speed (double speed, bool as_default, TransportRequestSource origin)
969 if (should_ignore_transport_request (origin, TR_Speed)) {
972 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
973 ev->third_yes_or_no = as_default; // as_default
974 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
978 /** Request a new transport speed, but if the speed parameter is exactly zero then use
979 * a very small +ve value to prevent the transport actually stopping. This method should
980 * be used by callers who are varying transport speed but don't ever want to stop it.
983 Session::request_transport_speed_nonzero (double speed, bool as_default, TransportRequestSource origin)
985 if (should_ignore_transport_request (origin, TransportRequestType (TR_Speed|TR_Start))) {
993 request_transport_speed (speed, as_default);
997 Session::request_stop (bool abort, bool clear_state, TransportRequestSource origin)
999 if (should_ignore_transport_request (origin, TR_Stop)) {
1003 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
1004 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));
1009 Session::request_locate (samplepos_t target_sample, bool with_roll, TransportRequestSource origin)
1011 if (should_ignore_transport_request (origin, TR_Locate)) {
1015 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
1016 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_sample));
1021 Session::force_locate (samplepos_t target_sample, bool with_roll)
1023 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
1024 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_sample));
1029 Session::unset_preroll_record_trim ()
1031 _preroll_record_trim_len = 0;
1035 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
1037 if (actively_recording ()) {
1040 unset_preroll_record_trim ();
1042 config.set_punch_in (false);
1043 config.set_punch_out (false);
1045 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
1046 _preroll_record_trim_len = preroll;
1047 maybe_enable_record ();
1048 request_locate (pos, true);
1049 set_requested_return_sample (rec_in);
1053 Session::request_count_in_record ()
1055 if (actively_recording ()) {
1058 if (transport_rolling()) {
1061 maybe_enable_record ();
1062 _count_in_once = true;
1063 request_transport_speed (1.0, true);
1067 Session::request_play_loop (bool yn, bool change_transport_roll)
1069 if (transport_master_is_external() && yn) {
1070 // don't attempt to loop when not using Internal Transport
1071 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
1076 Location *location = _locations->auto_loop_location();
1077 double target_speed;
1079 if (location == 0 && yn) {
1080 error << _("Cannot loop - no loop range defined")
1085 if (change_transport_roll) {
1086 if (transport_rolling()) {
1087 /* start looping at current speed */
1088 target_speed = transport_speed ();
1090 /* currently stopped */
1092 /* start looping at normal speed */
1099 /* leave the speed alone */
1100 target_speed = transport_speed ();
1103 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn);
1104 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
1108 if (!change_transport_roll) {
1109 if (!transport_rolling()) {
1110 /* we're not changing transport state, but we do want
1111 to set up position for the new loop. Don't
1112 do this if we're rolling already.
1114 request_locate (location->start(), false);
1118 if (!change_transport_roll && Config->get_seamless_loop() && transport_rolling()) {
1119 // request an immediate locate to refresh the tracks
1120 // after disabling looping
1121 request_locate (_transport_sample-1, false);
1127 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
1129 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
1131 ev->audio_range = *range;
1133 ev->audio_range.clear ();
1135 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
1140 Session::request_cancel_play_range ()
1142 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
1148 Session::solo_selection_active ()
1150 if (_soloSelection.empty()) {
1157 Session::solo_selection (StripableList &list, bool new_state)
1159 boost::shared_ptr<ControlList> solo_list (new ControlList);
1160 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
1163 _soloSelection = list;
1165 _soloSelection.clear();
1167 boost::shared_ptr<RouteList> rl = get_routes();
1169 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1171 if ( !(*i)->is_track() ) {
1175 boost::shared_ptr<Stripable> s (*i);
1177 bool found = (std::find(list.begin(), list.end(), s) != list.end());
1178 if ( new_state && found ) {
1180 solo_list->push_back (s->solo_control());
1182 //must invalidate playlists on selected tracks, so only selected regions get heard
1183 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1185 boost::shared_ptr<Playlist> playlist = track->playlist();
1187 playlist->ContentsChanged();
1191 unsolo_list->push_back (s->solo_control());
1195 set_controls (solo_list, 1.0, Controllable::NoGroup);
1196 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
1201 Session::butler_transport_work ()
1203 /* Note: this function executes in the butler thread context */
1206 boost::shared_ptr<RouteList> r = routes.reader ();
1207 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
1208 bool finished = true;
1209 PostTransportWork ptw = post_transport_work();
1212 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));
1214 if (ptw & PostTransportLocate) {
1216 if (get_play_loop() && !Config->get_seamless_loop()) {
1218 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
1220 /* this locate might be happening while we are
1223 * Non-seamless looping will require a locate (below) that
1224 * will reset capture buffers and throw away data.
1226 * Rather than first find all tracks and see if they
1227 * have outstanding data, just do a flush anyway. It
1228 * may be cheaper this way anyway, and is certainly
1232 bool more_disk_io_to_do = false;
1233 uint32_t errors = 0;
1236 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
1242 if (more_disk_io_to_do) {
1251 if (ptw & PostTransportAdjustPlaybackBuffering) {
1252 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1253 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1255 tr->adjust_playback_buffering ();
1256 /* and refill those buffers ... */
1258 (*i)->non_realtime_locate (_transport_sample);
1260 VCAList v = _vca_manager->vcas ();
1261 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1262 (*i)->non_realtime_locate (_transport_sample);
1266 if (ptw & PostTransportAdjustCaptureBuffering) {
1267 /* need to prevent concurrency with ARDOUR::DiskWriter::run(),
1268 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
1269 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
1270 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1271 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1273 tr->adjust_capture_buffering ();
1278 if (ptw & PostTransportReverse) {
1282 /* don't seek if locate will take care of that in non_realtime_stop() */
1284 if (!(ptw & PostTransportLocate)) {
1285 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1286 (*i)->non_realtime_locate (_transport_sample);
1288 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1289 /* new request, stop seeking, and start again */
1290 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1294 VCAList v = _vca_manager->vcas ();
1295 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1296 (*i)->non_realtime_locate (_transport_sample);
1301 if (ptw & PostTransportLocate) {
1302 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
1303 non_realtime_locate ();
1306 if (ptw & PostTransportStop) {
1307 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
1309 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1314 if (ptw & PostTransportOverWrite) {
1315 non_realtime_overwrite (on_entry, finished);
1317 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1322 if (ptw & PostTransportAudition) {
1323 non_realtime_set_audition ();
1326 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
1328 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()));
1332 Session::non_realtime_overwrite (int on_entry, bool& finished)
1334 boost::shared_ptr<RouteList> rl = routes.reader();
1335 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1336 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1337 if (tr && tr->pending_overwrite ()) {
1338 tr->overwrite_existing_buffers ();
1340 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1348 Session::non_realtime_locate ()
1350 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
1352 if (Config->get_loop_is_mode() && get_play_loop()) {
1354 Location *loc = _locations->auto_loop_location();
1356 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
1357 /* jumped out of loop range: stop tracks from looping,
1358 but leave loop (mode) enabled.
1360 set_track_loop (false);
1362 } else if (loc && Config->get_seamless_loop() &&
1363 ((loc->start() <= _transport_sample) || (loc->end() > _transport_sample))) {
1365 /* jumping to start of loop. This might have been done before but it is
1366 * idempotent and cheap. Doing it here ensures that when we start playback
1367 * outside the loop we still flip tracks into the magic seamless mode
1370 set_track_loop (true);
1373 set_track_loop (false);
1378 /* no more looping .. should have been noticed elsewhere */
1385 boost::shared_ptr<RouteList> rl = routes.reader();
1388 gint sc = g_atomic_int_get (&_seek_counter);
1389 tf = _transport_sample;
1391 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1392 (*i)->non_realtime_locate (tf);
1393 if (sc != g_atomic_int_get (&_seek_counter)) {
1394 std::cerr << "\n\nLOCATE INTERRUPTED BY LOCATE!!!\n\n";
1401 /* VCAs are quick to locate because they have no data (except
1402 automation) associated with them. Don't bother with a
1403 restart mechanism here, but do use the same transport sample
1404 that the Routes used.
1406 VCAList v = _vca_manager->vcas ();
1407 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1408 (*i)->non_realtime_locate (tf);
1412 _scene_changer->locate (_transport_sample);
1414 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
1415 rather than clearing them so that the RT thread has to spend time constructing
1416 them (in Session::click).
1421 #ifdef USE_TRACKS_CODE_FEATURES
1423 Session::select_playhead_priority_target (samplepos_t& jump_to)
1427 AutoReturnTarget autoreturn = Config->get_auto_return_target_list ();
1433 if (Profile->get_trx() && transport_rolling() ) {
1434 // We're playing, so do nothing.
1435 // Next stop will put us where we need to be.
1439 /* Note that the order of checking each AutoReturnTarget flag defines
1440 the priority each flag.
1442 Ardour/Mixbus: Last Locate
1447 Tracks: Range Selection
1453 if (autoreturn & RangeSelectionStart) {
1454 if (!_range_selection.empty()) {
1455 jump_to = _range_selection.from;
1457 if (transport_rolling ()) {
1458 /* Range selection no longer exists, but we're playing,
1459 so do nothing. Next stop will put us where
1467 if (jump_to < 0 && (autoreturn & Loop) && get_play_loop()) {
1468 /* don't try to handle loop play when synced to JACK */
1470 if (!synced_to_engine()) {
1471 Location *location = _locations->auto_loop_location();
1474 jump_to = location->start();
1476 if (Config->get_seamless_loop()) {
1477 /* need to get track buffers reloaded */
1478 set_track_loop (true);
1484 if (jump_to < 0 && (autoreturn & RegionSelectionStart)) {
1485 if (!_object_selection.empty()) {
1486 jump_to = _object_selection.from;
1490 if (jump_to < 0 && (autoreturn & LastLocate)) {
1491 jump_to = _last_roll_location;
1494 return jump_to >= 0;
1499 Session::select_playhead_priority_target (samplepos_t& jump_to)
1501 if (!transport_master_no_external_or_using_engine() || !config.get_auto_return()) {
1505 jump_to = _last_roll_location;
1506 return jump_to >= 0;
1512 Session::follow_playhead_priority ()
1516 if (select_playhead_priority_target (target)) {
1517 request_locate (target);
1522 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
1528 PostTransportWork ptw = post_transport_work();
1533 boost::shared_ptr<RouteList> rl = routes.reader();
1534 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1535 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1536 if (tr && tr->get_captured_samples () != 0) {
1542 /* stop and locate are merged here because they share a lot of common stuff */
1545 now = localtime (&xnow);
1548 auditioner->cancel_audition ();
1552 begin_reversible_command (Operations::capture);
1553 _have_captured = true;
1556 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
1558 if (abort && did_record) {
1559 /* no reason to save the session file when we remove sources
1561 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
1564 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1565 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1567 tr->transport_stopped_wallclock (*now, xnow, abort);
1571 if (abort && did_record) {
1572 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1575 boost::shared_ptr<RouteList> r = routes.reader ();
1578 commit_reversible_command ();
1579 /* increase take name */
1580 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
1581 string newname = config.get_take_name();
1582 config.set_take_name(bump_name_number (newname));
1586 if (_engine.running()) {
1587 PostTransportWork ptw = post_transport_work ();
1589 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1590 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1592 VCAList v = _vca_manager->vcas ();
1593 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1594 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
1597 update_latency_compensation ();
1600 /* If we are not synced to a "true" external master, and we're not
1601 * handling an explicit locate, we should consider whether or not to
1602 * "auto-return". This could mean going to a specifically requested
1603 * location, or just back to the start of the last roll.
1606 if (transport_master_no_external_or_using_engine() && !(ptw & PostTransportLocate)) {
1608 bool do_locate = false;
1610 if (_requested_return_sample >= 0) {
1612 /* explicit return request pre-queued in event list. overrides everything else */
1614 _transport_sample = _requested_return_sample;
1616 /* cancel this request */
1617 _requested_return_sample = -1;
1620 } else if (Config->get_auto_return_target_list()) {
1622 samplepos_t jump_to;
1624 if (select_playhead_priority_target (jump_to)) {
1626 /* there's a valid target (we don't care how it
1630 _transport_sample = jump_to;
1635 /* roll aborted (typically capture) with
1636 * auto-return enabled
1639 _transport_sample = _last_roll_location;
1646 if (do_locate && synced_to_engine()) {
1648 /* We will unconditionally locate to _transport_sample
1649 * below, which will refill playback buffers based on
1650 * _transport_sample, and maximises the buffering they
1653 * But if we are synced to engine (JACK), we should
1654 * locate the engine (JACK) as well. We would follow
1655 * the engine (JACK) on the next process cycle, but
1656 * since we're going to do a locate below anyway,
1657 * it seems pointless to not use just do it ourselves
1658 * right now, rather than wait for the engine (JACK) to
1659 * provide the new position on the next cycle.
1661 * Despite the generic name of the called method
1662 * (::transport_locate()) this method only does
1663 * anything if the audio/MIDI backend is JACK.
1666 _engine.transport_locate (_transport_sample);
1672 unset_preroll_record_trim ();
1674 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
1677 if (ptw & PostTransportClearSubstate) {
1678 unset_play_range ();
1679 if (!Config->get_loop_is_mode()) {
1684 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
1687 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
1688 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1689 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
1690 (*i)->non_realtime_locate (_transport_sample);
1692 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
1694 /* we will be back */
1701 VCAList v = _vca_manager->vcas ();
1702 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
1703 (*i)->non_realtime_locate (_transport_sample);
1707 have_looped = false;
1709 /* don't bother with this stuff if we're disconnected from the engine,
1710 because there will be no process callbacks to deliver stuff from
1713 if (_engine.running() && !_engine.freewheeling()) {
1714 // need to queue this in the next RT cycle
1715 _send_timecode_update = true;
1717 if (transport_master()->type() == MTC) {
1718 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
1720 /* This (::non_realtime_stop()) gets called by main
1721 process thread, which will lead to confusion
1722 when calling AsyncMIDIPort::write().
1724 Something must be done. XXX
1726 send_mmc_locate (_transport_sample);
1730 if ((ptw & PostTransportLocate) && get_record_enabled()) {
1731 /* This is scheduled by realtime_stop(), which is also done
1732 * when a slave requests /locate/ for an initial sync.
1733 * We can't hold up the slave for long with a save() here,
1734 * without breaking its initial sync cycle.
1736 * save state only if there's no slave or if it's not yet locked.
1738 if (!transport_master_is_external() || !transport_master()->locked()) {
1739 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
1740 SaveSessionRequested (_current_snapshot_name);
1745 /* save the current state of things if appropriate */
1747 if (did_record && !saved) {
1748 SaveSessionRequested (_current_snapshot_name);
1751 if (ptw & PostTransportStop) {
1752 unset_play_range ();
1753 if (!Config->get_loop_is_mode()) {
1758 PositionChanged (_transport_sample); /* EMIT SIGNAL */
1759 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
1760 TransportStateChange (); /* EMIT SIGNAL */
1761 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
1763 /* and start it up again if relevant */
1765 if ((ptw & PostTransportLocate) && !config.get_external_sync()) {
1766 request_transport_speed (1.0);
1771 Session::unset_play_loop ()
1775 clear_events (SessionEvent::AutoLoop);
1776 set_track_loop (false);
1779 if (Config->get_seamless_loop()) {
1780 /* likely need to flush track buffers: this will locate us to wherever we are */
1781 add_post_transport_work (PostTransportLocate);
1782 TFSM_EVENT (TransportFSM::butler_required());
1784 TransportStateChange (); /* EMIT SIGNAL */
1789 Session::set_track_loop (bool yn)
1791 Location* loc = _locations->auto_loop_location ();
1797 boost::shared_ptr<RouteList> rl = routes.reader ();
1799 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1800 if (*i && !(*i)->is_private_route()) {
1801 (*i)->set_loop (yn ? loc : 0);
1807 Session::worst_latency_preroll () const
1809 return _worst_output_latency + _worst_input_latency;
1813 Session::unset_play_range ()
1815 _play_range = false;
1816 _clear_event_type (SessionEvent::RangeStop);
1817 _clear_event_type (SessionEvent::RangeLocate);
1821 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1825 /* Called from event-processing context */
1827 unset_play_range ();
1829 if (range.empty()) {
1830 /* _play_range set to false in unset_play_range()
1832 if (!leave_rolling) {
1833 /* stop transport */
1834 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1842 /* cancel loop play */
1845 list<AudioRange>::size_type sz = range.size();
1849 list<AudioRange>::iterator i = range.begin();
1850 list<AudioRange>::iterator next;
1852 while (i != range.end()) {
1857 /* locating/stopping is subject to delays for declicking.
1860 samplepos_t requested_sample = i->end;
1862 if (requested_sample > current_block_size) {
1863 requested_sample -= current_block_size;
1865 requested_sample = 0;
1868 if (next == range.end()) {
1869 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1871 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1879 } else if (sz == 1) {
1881 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1886 /* save range so we can do auto-return etc. */
1888 current_audio_range = range;
1890 /* now start rolling at the right place */
1892 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1895 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1896 TransportStateChange ();
1900 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1902 AudioRange ar (start, end, 0);
1903 list<AudioRange> lar;
1906 request_play_range (&lar, true);
1910 Session::set_requested_return_sample (samplepos_t return_to)
1912 _requested_return_sample = return_to;
1916 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1918 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1919 ev->target2_sample = start;
1924 Session::engine_halted ()
1926 /* there will be no more calls to process(), so
1927 we'd better clean up for ourselves, right now.
1929 We can't queue SessionEvents because they only get
1930 handled from within a process callback.
1933 /* this just stops the FSM engine ... it doesn't change the state of
1934 * the FSM directly or anything else ... but the FSM will be
1935 * reinitialized when we call its ::start() method from
1936 * ::engine_running() (if we ever get there)
1939 _transport_fsm->backend()->stop ();
1941 /* Synchronously do the realtime part of a transport stop.
1943 * Calling this will cause the butler to asynchronously run
1944 * ::non_realtime_stop() where the rest of the "stop" work will be
1948 realtime_stop (false, true);
1952 Session::engine_running ()
1954 initialize_latencies ();
1955 _transport_fsm->backend()->start ();
1959 Session::xrun_recovery ()
1963 Xrun (_transport_sample); /* EMIT SIGNAL */
1965 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1967 /* it didn't actually halt, but we need
1968 to handle things in the same way.
1976 Session::route_processors_changed (RouteProcessorChange c)
1978 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1982 if (c.type == RouteProcessorChange::MeterPointChange) {
1987 if (c.type == RouteProcessorChange::RealTimeChange) {
1992 update_latency_compensation ();
1999 Session::allow_auto_play (bool yn)
2001 auto_play_legal = yn;
2006 Session::send_mmc_locate (samplepos_t t)
2012 if (!_engine.freewheeling()) {
2013 Timecode::Time time;
2014 timecode_time_subframes (t, time);
2015 send_immediate_mmc (MIDI::MachineControlCommand (time));
2019 /** Ask the transport to not send timecode until further notice. The suspension
2020 * will come into effect some finite time after this call, and timecode_transmission_suspended()
2021 * should be checked by the caller to find out when.
2024 Session::request_suspend_timecode_transmission ()
2026 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
2031 Session::request_resume_timecode_transmission ()
2033 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
2038 Session::timecode_transmission_suspended () const
2040 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
2043 boost::shared_ptr<TransportMaster>
2044 Session::transport_master() const
2046 return TransportMasterManager::instance().current();
2050 Session::transport_master_is_external () const
2052 return TransportMasterManager::instance().current() && config.get_external_sync();
2056 Session::transport_master_no_external_or_using_engine () const
2058 return !TransportMasterManager::instance().current() || !config.get_external_sync() || (TransportMasterManager::instance().current()->type() == Engine);
2062 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
2064 /* Runs in process() context */
2066 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
2068 /* save value of seamless from before the switch */
2069 _was_seamless = Config->get_seamless_loop ();
2071 if (type == Engine) {
2072 /* JACK cannot support seamless looping at present */
2073 Config->set_seamless_loop (false);
2075 /* reset to whatever the value was before we last switched slaves */
2076 Config->set_seamless_loop (_was_seamless);
2079 if (master->can_loop()) {
2080 request_play_loop (false);
2081 } else if (master->has_loop()) {
2082 request_play_loop (true);
2085 /* slave change, reset any DiskIO block on disk output because it is no
2086 longer valid with a new slave.
2089 DiskReader::dec_no_disk_output ();
2092 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
2094 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
2097 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
2098 MTCSyncStateChanged(mtc_master->locked() );
2100 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
2101 MTCSyncStateChanged( false );
2103 mtc_status_connection.disconnect ();
2106 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
2109 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
2110 LTCSyncStateChanged (ltc_master->locked() );
2112 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
2113 LTCSyncStateChanged( false );
2115 ltc_status_connection.disconnect ();
2119 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
2121 // need to queue this for next process() cycle
2122 _send_timecode_update = true;
2124 boost::shared_ptr<RouteList> rl = routes.reader();
2125 const bool externally_slaved = transport_master_is_external();
2127 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2128 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2129 if (tr && !tr->is_private_route()) {
2130 tr->set_slaved (externally_slaved);
2138 Session::transport_stopped() const
2140 return _transport_fsm->stopped();
2144 Session::transport_rolling() const
2146 return _transport_speed != 0.0 && _count_in_samples == 0 && _remaining_latency_preroll == 0;
2150 Session::locate_pending () const
2152 return _transport_fsm->locating();
2156 Session::declick_in_progress () const
2158 return _transport_fsm->declick_in_progress();