2 Copyright (C) 1999-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "libardour-config.h"
29 #include "pbd/error.h"
30 #include "pbd/enumwriter.h"
31 #include "pbd/pthread_utils.h"
32 #include "pbd/memento_command.h"
33 #include "pbd/stacktrace.h"
35 #include "midi++/mmc.h"
36 #include "midi++/port.h"
38 #include "ardour/audioengine.h"
39 #include "ardour/auditioner.h"
40 #include "ardour/automation_watch.h"
41 #include "ardour/butler.h"
42 #include "ardour/click.h"
43 #include "ardour/debug.h"
44 #include "ardour/disk_reader.h"
45 #include "ardour/location.h"
46 #include "ardour/playlist.h"
47 #include "ardour/profile.h"
48 #include "ardour/scene_changer.h"
49 #include "ardour/session.h"
50 #include "ardour/transport_master.h"
51 #include "ardour/transport_master_manager.h"
52 #include "ardour/tempo.h"
53 #include "ardour/operations.h"
54 #include "ardour/vca.h"
55 #include "ardour/vca_manager.h"
60 using namespace ARDOUR;
64 Session::add_post_transport_work (PostTransportWork ptw)
66 PostTransportWork oldval;
67 PostTransportWork newval;
71 oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work);
72 newval = PostTransportWork (oldval | ptw);
73 if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) {
79 error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
83 Session::should_ignore_transport_request (TransportRequestSource src, TransportRequestType type) const
85 if (config.get_external_sync()) {
86 if (TransportMasterManager::instance().current()->allow_request (src, type)) {
96 Session::synced_to_engine() const {
97 return config.get_external_sync() && TransportMasterManager::instance().current()->type() == Engine;
101 Session::request_sync_source (boost::shared_ptr<TransportMaster> tm)
103 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportMaster, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
104 ev->transport_master = tm;
105 DEBUG_TRACE (DEBUG::Slave, "sent request for new transport master\n");
110 Session::request_transport_speed (double speed, bool as_default, TransportRequestSource origin)
112 if (should_ignore_transport_request (origin, TR_Speed)) {
115 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
116 ev->third_yes_or_no = as_default; // as_default
117 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
121 /** Request a new transport speed, but if the speed parameter is exactly zero then use
122 * a very small +ve value to prevent the transport actually stopping. This method should
123 * be used by callers who are varying transport speed but don't ever want to stop it.
126 Session::request_transport_speed_nonzero (double speed, bool as_default, TransportRequestSource origin)
128 if (should_ignore_transport_request (origin, TransportRequestType (TR_Speed|TR_Start))) {
136 request_transport_speed (speed, as_default);
140 Session::request_stop (bool abort, bool clear_state, TransportRequestSource origin)
142 if (should_ignore_transport_request (origin, TR_Stop)) {
146 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, audible_sample(), 0.0, abort, clear_state);
147 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));
152 Session::request_locate (samplepos_t target_sample, bool with_roll, TransportRequestSource origin)
154 if (should_ignore_transport_request (origin, TR_Locate)) {
158 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, false);
159 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_sample));
164 Session::force_locate (samplepos_t target_sample, bool with_roll)
166 SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_sample, 0, true);
167 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_sample));
172 Session::unset_preroll_record_trim ()
174 _preroll_record_trim_len = 0;
178 Session::request_preroll_record_trim (samplepos_t rec_in, samplecnt_t preroll)
180 if (actively_recording ()) {
183 unset_preroll_record_trim ();
185 config.set_punch_in (false);
186 config.set_punch_out (false);
188 samplepos_t pos = std::max ((samplepos_t)0, rec_in - preroll);
189 _preroll_record_trim_len = preroll;
190 maybe_enable_record ();
191 request_locate (pos, true);
192 set_requested_return_sample (rec_in);
196 Session::request_count_in_record ()
198 if (actively_recording ()) {
201 if (transport_rolling()) {
204 maybe_enable_record ();
205 _count_in_once = true;
206 request_transport_speed (1.0, true);
210 Session::request_play_loop (bool yn, bool change_transport_roll)
212 if (transport_master_is_external() && yn) {
213 // don't attempt to loop when not using Internal Transport
214 // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
219 Location *location = _locations->auto_loop_location();
222 if (location == 0 && yn) {
223 error << _("Cannot loop - no loop range defined")
228 if (change_transport_roll) {
229 if (transport_rolling()) {
230 /* start looping at current speed */
231 target_speed = transport_speed ();
233 /* currently stopped */
235 /* start looping at normal speed */
242 /* leave the speed alone */
243 target_speed = transport_speed ();
246 ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn);
247 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll));
251 if (!change_transport_roll) {
252 if (!transport_rolling()) {
253 /* we're not changing transport state, but we do want
254 to set up position for the new loop. Don't
255 do this if we're rolling already.
257 request_locate (location->start(), false);
261 if (!change_transport_roll && Config->get_seamless_loop() && transport_rolling()) {
262 // request an immediate locate to refresh the tracks
263 // after disabling looping
264 request_locate (_transport_sample-1, false);
270 Session::request_play_range (list<AudioRange>* range, bool leave_rolling)
272 SessionEvent* ev = new SessionEvent (SessionEvent::SetPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0));
274 ev->audio_range = *range;
276 ev->audio_range.clear ();
278 DEBUG_TRACE (DEBUG::Transport, string_compose ("Request play range, leave rolling ? %1\n", leave_rolling));
283 Session::request_cancel_play_range ()
285 SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0);
291 Session::solo_selection_active ()
293 if ( _soloSelection.empty() ) {
300 Session::solo_selection ( StripableList &list, bool new_state )
302 boost::shared_ptr<ControlList> solo_list (new ControlList);
303 boost::shared_ptr<ControlList> unsolo_list (new ControlList);
306 _soloSelection = list;
308 _soloSelection.clear();
310 boost::shared_ptr<RouteList> rl = get_routes();
312 for (ARDOUR::RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
314 if ( !(*i)->is_track() ) {
318 boost::shared_ptr<Stripable> s (*i);
320 bool found = (std::find(list.begin(), list.end(), s) != list.end());
321 if ( new_state && found ) {
323 solo_list->push_back (s->solo_control());
325 //must invalidate playlists on selected tracks, so only selected regions get heard
326 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
328 boost::shared_ptr<Playlist> playlist = track->playlist();
330 playlist->ContentsChanged();
334 unsolo_list->push_back (s->solo_control());
338 set_controls (solo_list, 1.0, Controllable::NoGroup);
339 set_controls (unsolo_list, 0.0, Controllable::NoGroup);
343 Session::realtime_stop (bool abort, bool clear_state)
345 DEBUG_TRACE (DEBUG::Transport, string_compose ("realtime stop @ %1\n", _transport_sample));
346 PostTransportWork todo = PostTransportWork (0);
348 /* assume that when we start, we'll be moving forwards */
350 if (_transport_speed < 0.0f) {
351 todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
352 _default_transport_speed = 1.0;
354 todo = PostTransportWork (todo | PostTransportStop);
359 boost::shared_ptr<RouteList> r = routes.reader ();
361 for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
362 (*i)->realtime_handle_transport_stopped ();
365 DEBUG_TRACE (DEBUG::Transport, string_compose ("stop complete, auto-return scheduled for return to %1\n", _requested_return_sample));
367 /* the duration change is not guaranteed to have happened, but is likely */
369 todo = PostTransportWork (todo | PostTransportDuration);
372 todo = PostTransportWork (todo | PostTransportAbort);
376 todo = PostTransportWork (todo | PostTransportClearSubstate);
380 add_post_transport_work (todo);
383 _clear_event_type (SessionEvent::StopOnce);
384 _clear_event_type (SessionEvent::RangeStop);
385 _clear_event_type (SessionEvent::RangeLocate);
387 //clear our solo-selection, if there is one
388 if ( solo_selection_active() ) {
389 solo_selection ( _soloSelection, false );
392 /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
393 disable_record (true, (!Config->get_latched_record_enable() && clear_state));
395 if (clear_state && !Config->get_loop_is_mode()) {
399 reset_slave_state ();
401 _transport_speed = 0;
402 _target_transport_speed = 0;
405 g_atomic_int_set (&_playback_load, 100);
406 g_atomic_int_set (&_capture_load, 100);
408 if (config.get_use_video_sync()) {
409 waiting_for_sync_offset = true;
412 transport_sub_state = 0;
416 Session::realtime_locate ()
418 boost::shared_ptr<RouteList> r = routes.reader ();
419 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
420 (*i)->realtime_locate ();
425 Session::butler_transport_work ()
427 /* Note: this function executes in the butler thread context */
431 PostTransportWork ptw;
432 boost::shared_ptr<RouteList> r = routes.reader ();
435 int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
437 ptw = post_transport_work();
439 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1 at %2\n", enum_2_string (ptw), (before = g_get_monotonic_time())));
442 if (ptw & PostTransportLocate) {
444 if (get_play_loop() && !Config->get_seamless_loop()) {
446 DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
448 /* this locate might be happening while we are
451 * Non-seamless looping will require a locate (below) that
452 * will reset capture buffers and throw away data.
454 * Rather than first find all tracks and see if they
455 * have outstanding data, just do a flush anyway. It
456 * may be cheaper this way anyway, and is certainly
460 bool more_disk_io_to_do = false;
464 more_disk_io_to_do = _butler->flush_tracks_to_disk_after_locate (r, errors);
470 if (more_disk_io_to_do) {
479 if (ptw & PostTransportAdjustPlaybackBuffering) {
480 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
481 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
483 tr->adjust_playback_buffering ();
484 /* and refill those buffers ... */
486 (*i)->non_realtime_locate (_transport_sample);
488 VCAList v = _vca_manager->vcas ();
489 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
490 (*i)->non_realtime_locate (_transport_sample);
494 if (ptw & PostTransportAdjustCaptureBuffering) {
495 /* need to prevent concurrency with ARDOUR::DiskWriter::run(),
496 * DiskWriter::adjust_buffering() re-allocates the ringbuffer */
497 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
498 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
499 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
501 tr->adjust_capture_buffering ();
506 if (ptw & PostTransportCurveRealloc) {
507 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
508 (*i)->curve_reallocate();
512 if (ptw & PostTransportReverse) {
515 cumulative_rf_motion = 0;
518 /* don't seek if locate will take care of that in non_realtime_stop() */
520 if (!(ptw & PostTransportLocate)) {
521 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
522 (*i)->non_realtime_locate (_transport_sample);
524 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
525 /* new request, stop seeking, and start again */
526 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
530 VCAList v = _vca_manager->vcas ();
531 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
532 (*i)->non_realtime_locate (_transport_sample);
537 if (ptw & PostTransportLocate) {
538 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
539 non_realtime_locate ();
542 if (ptw & PostTransportStop) {
543 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
545 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
550 if (ptw & PostTransportOverWrite) {
551 non_realtime_overwrite (on_entry, finished);
553 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
558 if (ptw & PostTransportAudition) {
559 non_realtime_set_audition ();
562 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
564 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()));
568 Session::non_realtime_overwrite (int on_entry, bool& finished)
570 boost::shared_ptr<RouteList> rl = routes.reader();
571 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
572 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
573 if (tr && tr->pending_overwrite ()) {
574 tr->overwrite_existing_buffers ();
576 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
585 Session::non_realtime_locate ()
587 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
589 if (Config->get_loop_is_mode() && get_play_loop()) {
591 Location *loc = _locations->auto_loop_location();
593 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
594 /* jumped out of loop range: stop tracks from looping,
595 but leave loop (mode) enabled.
597 set_track_loop (false);
599 } else if (loc && Config->get_seamless_loop() &&
600 ((loc->start() <= _transport_sample) ||
601 (loc->end() > _transport_sample) ) ) {
603 /* jumping to start of loop. This might have been done before but it is
604 * idempotent and cheap. Doing it here ensures that when we start playback
605 * outside the loop we still flip tracks into the magic seamless mode
608 set_track_loop (true);
611 set_track_loop (false);
616 /* no more looping .. should have been noticed elsewhere */
623 boost::shared_ptr<RouteList> rl = routes.reader();
626 gint sc = g_atomic_int_get (&_seek_counter);
627 tf = _transport_sample;
629 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
630 (*i)->non_realtime_locate (tf);
631 if (sc != g_atomic_int_get (&_seek_counter)) {
638 /* VCAs are quick to locate because they have no data (except
639 automation) associated with them. Don't bother with a
640 restart mechanism here, but do use the same transport sample
641 that the Routes used.
643 VCAList v = _vca_manager->vcas ();
644 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
645 (*i)->non_realtime_locate (tf);
649 _scene_changer->locate (_transport_sample);
651 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
652 rather than clearing them so that the RT thread has to spend time constructing
653 them (in Session::click).
658 #ifdef USE_TRACKS_CODE_FEATURES
660 Session::select_playhead_priority_target (samplepos_t& jump_to)
664 AutoReturnTarget autoreturn = Config->get_auto_return_target_list ();
670 if (Profile->get_trx() && transport_rolling() ) {
671 // We're playing, so do nothing.
672 // Next stop will put us where we need to be.
676 /* Note that the order of checking each AutoReturnTarget flag defines
677 the priority each flag.
679 Ardour/Mixbus: Last Locate
684 Tracks: Range Selection
690 if (autoreturn & RangeSelectionStart) {
691 if (!_range_selection.empty()) {
692 jump_to = _range_selection.from;
694 if (transport_rolling ()) {
695 /* Range selection no longer exists, but we're playing,
696 so do nothing. Next stop will put us where
704 if (jump_to < 0 && (autoreturn & Loop) && get_play_loop()) {
705 /* don't try to handle loop play when synced to JACK */
707 if (!synced_to_engine()) {
708 Location *location = _locations->auto_loop_location();
711 jump_to = location->start();
713 if (Config->get_seamless_loop()) {
714 /* need to get track buffers reloaded */
715 set_track_loop (true);
721 if (jump_to < 0 && (autoreturn & RegionSelectionStart)) {
722 if (!_object_selection.empty()) {
723 jump_to = _object_selection.from;
727 if (jump_to < 0 && (autoreturn & LastLocate)) {
728 jump_to = _last_roll_location;
736 Session::select_playhead_priority_target (samplepos_t& jump_to)
738 if (config.get_external_sync() || !config.get_auto_return()) {
742 jump_to = _last_roll_location;
749 Session::follow_playhead_priority ()
753 if (select_playhead_priority_target (target)) {
754 request_locate (target);
759 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
765 PostTransportWork ptw = post_transport_work();
770 boost::shared_ptr<RouteList> rl = routes.reader();
771 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
772 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
773 if (tr && tr->get_captured_samples () != 0) {
779 /* stop and locate are merged here because they share a lot of common stuff */
782 now = localtime (&xnow);
785 auditioner->cancel_audition ();
788 cumulative_rf_motion = 0;
792 begin_reversible_command (Operations::capture);
793 _have_captured = true;
796 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
798 if (abort && did_record) {
799 /* no reason to save the session file when we remove sources
801 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
804 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
805 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
807 tr->transport_stopped_wallclock (*now, xnow, abort);
811 if (abort && did_record) {
812 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
815 boost::shared_ptr<RouteList> r = routes.reader ();
818 commit_reversible_command ();
819 /* increase take name */
820 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
821 string newname = config.get_take_name();
822 config.set_take_name(bump_name_number (newname));
826 if (_engine.running()) {
827 PostTransportWork ptw = post_transport_work ();
829 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
830 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
832 VCAList v = _vca_manager->vcas ();
833 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
834 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
837 update_latency_compensation ();
840 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
842 if (auto_return_enabled ||
843 (ptw & PostTransportLocate) ||
844 (_requested_return_sample >= 0) ||
845 synced_to_engine()) {
847 // rg: what is the logic behind this case?
848 // _requested_return_sample should be ignored when synced_to_engine/slaved.
849 // currently worked around in MTC_Slave by forcing _requested_return_sample to -1
851 if ((auto_return_enabled || synced_to_engine() || _requested_return_sample >= 0) &&
852 !(ptw & PostTransportLocate)) {
854 /* no explicit locate queued */
856 bool do_locate = false;
858 if (_requested_return_sample >= 0) {
860 /* explicit return request pre-queued in event list. overrides everything else */
862 _transport_sample = _requested_return_sample;
868 if (select_playhead_priority_target (jump_to)) {
870 _transport_sample = jump_to;
875 _transport_sample = _last_roll_location;
880 _requested_return_sample = -1;
883 _engine.transport_locate (_transport_sample);
890 unset_preroll_record_trim ();
892 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
895 if (ptw & PostTransportClearSubstate) {
897 if (!Config->get_loop_is_mode()) {
902 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
905 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
906 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
907 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
908 (*i)->non_realtime_locate (_transport_sample);
910 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
912 /* we will be back */
919 VCAList v = _vca_manager->vcas ();
920 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
921 (*i)->non_realtime_locate (_transport_sample);
927 /* don't bother with this stuff if we're disconnected from the engine,
928 because there will be no process callbacks to deliver stuff from
931 if (_engine.running() && !_engine.freewheeling()) {
932 // need to queue this in the next RT cycle
933 _send_timecode_update = true;
935 if (transport_master()->type() == MTC) {
936 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
938 /* This (::non_realtime_stop()) gets called by main
939 process thread, which will lead to confusion
940 when calling AsyncMIDIPort::write().
942 Something must be done. XXX
944 send_mmc_locate (_transport_sample);
948 if ((ptw & PostTransportLocate) && get_record_enabled()) {
949 /* This is scheduled by realtime_stop(), which is also done
950 * when a slave requests /locate/ for an initial sync.
951 * We can't hold up the slave for long with a save() here,
952 * without breaking its initial sync cycle.
954 * save state only if there's no slave or if it's not yet locked.
956 if (!transport_master_is_external() || !transport_master()->locked()) {
957 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
958 SaveSessionRequested (_current_snapshot_name);
963 /* always try to get rid of this */
965 remove_pending_capture_state ();
967 /* save the current state of things if appropriate */
969 if (did_record && !saved) {
970 SaveSessionRequested (_current_snapshot_name);
973 if (ptw & PostTransportStop) {
975 if (!Config->get_loop_is_mode()) {
980 PositionChanged (_transport_sample); /* EMIT SIGNAL */
981 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
982 TransportStateChange (); /* EMIT SIGNAL */
983 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
985 /* and start it up again if relevant */
987 if ((ptw & PostTransportLocate) && !config.get_external_sync()) {
988 request_transport_speed (1.0);
993 Session::unset_play_loop ()
997 clear_events (SessionEvent::AutoLoop);
998 set_track_loop (false);
1001 if (Config->get_seamless_loop()) {
1002 /* likely need to flush track buffers: this will locate us to wherever we are */
1003 add_post_transport_work (PostTransportLocate);
1004 _butler->schedule_transport_work ();
1006 TransportStateChange (); /* EMIT SIGNAL */
1011 Session::set_track_loop (bool yn)
1013 Location* loc = _locations->auto_loop_location ();
1019 boost::shared_ptr<RouteList> rl = routes.reader ();
1021 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1022 if (*i && !(*i)->is_private_route()) {
1023 (*i)->set_loop (yn ? loc : 0);
1029 Session::set_play_loop (bool yn, double speed)
1031 /* Called from event-handling context */
1035 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
1036 /* nothing to do, or can't change loop status while recording */
1040 if (yn && Config->get_seamless_loop() && synced_to_engine()) {
1041 warning << string_compose (
1042 _("Seamless looping cannot be supported while %1 is using JACK transport.\n"
1043 "Recommend changing the configured options"), PROGRAM_NAME)
1051 have_looped = false;
1055 unset_play_range ();
1057 if (Config->get_seamless_loop()) {
1058 if (!Config->get_loop_is_mode()) {
1059 /* set all tracks to use internal looping */
1060 set_track_loop (true);
1062 /* we will do this in the locate to the start OR when we hit the end
1063 * of the loop for the first time
1067 /* set all tracks to NOT use internal looping */
1068 set_track_loop (false);
1071 /* Put the delick and loop events in into the event list. The declick event will
1072 cause a de-clicking fade-out just before the end of the loop, and it will also result
1073 in a fade-in when the loop restarts. The AutoLoop event will peform the actual loop.
1078 auto_loop_declick_range (loc, dcp, dcl);
1079 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
1081 /* if requested to roll, locate to start of loop and
1082 * roll but ONLY if we're not already rolling.
1084 args: positition, roll=true, flush=true, with_loop=false, force buffer refill if seamless looping
1087 if (Config->get_loop_is_mode()) {
1088 /* loop IS a transport mode: if already
1089 rolling, do not locate to loop start.
1091 if (!transport_rolling() && (speed != 0.0)) {
1092 start_locate (loc->start(), true, true, false, true);
1096 start_locate (loc->start(), true, true, false, true);
1106 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
1107 TransportStateChange ();
1110 Session::flush_all_inserts ()
1112 boost::shared_ptr<RouteList> r = routes.reader ();
1114 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1115 (*i)->flush_processors ();
1120 Session::start_locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force)
1122 if (target_sample < 0) {
1123 error << _("Locate called for negative sample position - ignored") << endmsg;
1127 if (synced_to_engine()) {
1131 samplepos_t ignore1, ignore2;
1133 transport_master()->speed_and_position (sp, pos, ignore1, ignore2, 0);
1135 if (target_sample != pos) {
1137 if (config.get_jack_time_master()) {
1138 /* actually locate now, since otherwise jack_timebase_callback
1139 will use the incorrect _transport_sample and report an old
1140 and incorrect time to Jack transport
1142 locate (target_sample, with_roll, with_flush, for_loop_enabled, force);
1145 /* tell JACK to change transport position, and we will
1146 follow along later in ::follow_slave()
1149 _engine.transport_locate (target_sample);
1151 if (sp != 1.0f && with_roll) {
1152 _engine.transport_start ();
1158 locate (target_sample, with_roll, with_flush, for_loop_enabled, force);
1163 Session::worst_latency_preroll () const
1165 return _worst_output_latency + _worst_input_latency;
1169 Session::micro_locate (samplecnt_t distance)
1171 boost::shared_ptr<RouteList> rl = routes.reader();
1172 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1173 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1174 if (tr && !tr->can_internal_playback_seek (distance)) {
1179 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
1181 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1182 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1184 tr->internal_playback_seek (distance);
1188 _transport_sample += distance;
1192 /** @param with_mmc true to send a MMC locate command when the locate is done */
1194 Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force, bool with_mmc)
1196 bool need_butler = false;
1198 /* Locates for seamless looping are fairly different from other
1199 * locates. They assume that the diskstream buffers for each track
1200 * already have the correct data in them, and thus there is no need to
1201 * actually tell the tracks to locate. What does need to be done,
1202 * though, is all the housekeeping that is associated with non-linear
1203 * changes in the value of _transport_sample.
1206 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 loop-enabled %4 force %5 mmc %6\n",
1207 target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc));
1209 if (!force && _transport_sample == target_sample && !loop_changing && !for_loop_enabled) {
1211 /* already at the desired position. Not forced to locate,
1212 the loop isn't changing, so unless we're told to
1213 start rolling also, there's nothing to do but
1214 tell the world where we are (again).
1218 set_transport_speed (1.0, 0, false);
1220 loop_changing = false;
1221 Located (); /* EMIT SIGNAL */
1225 cerr << "... now doing the actual locate\n";
1227 // Update Timecode time
1228 _transport_sample = target_sample;
1229 // Bump seek counter so that any in-process locate in the butler
1230 // thread(s?) can restart.
1231 g_atomic_int_inc (&_seek_counter);
1232 _last_roll_or_reversal_location = target_sample;
1233 _remaining_latency_preroll = worst_latency_preroll ();
1234 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
1236 /* do "stopped" stuff if:
1238 * we are rolling AND
1239 * no autoplay in effect AND
1240 * we're not going to keep rolling after the locate AND
1241 * !(playing a loop with JACK sync)
1245 bool transport_was_stopped = !transport_rolling();
1247 if (!transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop) &&
1248 (!Profile->get_trx() || !(config.get_external_sync() && !synced_to_engine()))) {
1249 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
1250 transport_was_stopped = true;
1252 /* otherwise tell the world that we located */
1256 if (force || !for_loop_enabled || loop_changing) {
1258 PostTransportWork todo = PostTransportLocate;
1260 if (with_roll && transport_was_stopped) {
1261 todo = PostTransportWork (todo | PostTransportRoll);
1264 add_post_transport_work (todo);
1269 /* this is functionally what clear_clicks() does but with a tentative lock */
1271 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
1273 if (clickm.locked()) {
1275 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
1284 /* switch from input if we're going to roll */
1285 if (Config->get_monitoring_model() == HardwareMonitoring) {
1286 set_track_monitor_input_status (!config.get_auto_input());
1289 /* otherwise we're going to stop, so do the opposite */
1290 if (Config->get_monitoring_model() == HardwareMonitoring) {
1291 set_track_monitor_input_status (true);
1295 /* cancel looped playback if transport pos outside of loop range */
1298 Location* al = _locations->auto_loop_location();
1301 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
1303 // located outside the loop: cancel looping directly, this is called from event handling context
1305 have_looped = false;
1307 if (!Config->get_loop_is_mode()) {
1308 set_play_loop (false, _transport_speed);
1310 if (Config->get_seamless_loop()) {
1311 /* this will make the non_realtime_locate() in the butler
1312 which then causes seek() in tracks actually do the right
1315 set_track_loop (false);
1319 } else if (_transport_sample == al->start()) {
1321 // located to start of loop - this is looping, basically
1325 if (_last_roll_location != al->start()) {
1326 /* didn't start at loop start - playback must have
1327 * started before loop since we've now hit the loop
1330 add_post_transport_work (PostTransportLocate);
1336 boost::shared_ptr<RouteList> rl = routes.reader();
1338 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1339 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1341 if (tr && tr->rec_enable_control()->get_value()) {
1342 // tell it we've looped, so it can deal with the record state
1343 tr->transport_looped (_transport_sample);
1348 TransportLooped(); // EMIT SIGNAL
1354 _butler->schedule_transport_work ();
1357 loop_changing = false;
1359 _send_timecode_update = true;
1362 send_mmc_locate (_transport_sample);
1365 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
1366 if (!synced_to_engine () || _transport_sample == _engine.transport_sample ()) {
1367 Located (); /* EMIT SIGNAL */
1371 /** Set the transport speed.
1372 * Called from the process thread.
1373 * @param speed New speed
1376 Session::set_transport_speed (double speed, samplepos_t destination_sample, bool abort, bool clear_state, bool as_default)
1378 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
1379 speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
1381 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
1382 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
1386 speed = min (8.0, speed);
1387 } else if (speed < 0) {
1388 speed = max (-8.0, speed);
1391 double new_engine_speed = 1.0;
1393 new_engine_speed = fabs (speed);
1394 if (speed < 0) speed = -1;
1395 if (speed > 0) speed = 1;
1398 if (_transport_speed == speed && new_engine_speed == _engine_speed) {
1399 if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
1400 _default_transport_speed = 1.0;
1405 #if 0 // TODO pref: allow vari-speed recording
1406 if (actively_recording() && speed != 1.0 && speed != 0.0) {
1407 /* no varispeed during recording */
1408 DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, sample %2\n",
1409 _transport_speed, _transport_sample));
1414 _target_transport_speed = fabs(speed);
1415 _engine_speed = new_engine_speed;
1417 if (transport_rolling() && speed == 0.0) {
1419 /* we are rolling and we want to stop */
1421 if (Config->get_monitoring_model() == HardwareMonitoring) {
1422 set_track_monitor_input_status (true);
1425 if (synced_to_engine ()) {
1427 /* do this here because our response to the slave won't
1430 _play_range = false;
1431 _count_in_once = false;
1434 _engine.transport_stop ();
1436 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
1438 if (!auto_return_enabled) {
1439 _requested_return_sample = destination_sample;
1442 stop_transport (abort);
1445 } else if (transport_stopped() && speed == 1.0) {
1447 _default_transport_speed = speed;
1449 /* we are stopped and we want to start rolling at speed 1 */
1451 if (Config->get_loop_is_mode() && play_loop) {
1453 Location *location = _locations->auto_loop_location();
1455 if (location != 0) {
1456 if (_transport_sample != location->start()) {
1458 if (Config->get_seamless_loop()) {
1459 /* force tracks to do their thing */
1460 set_track_loop (true);
1463 /* jump to start and then roll from there */
1465 request_locate (location->start(), true);
1471 if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
1472 set_track_monitor_input_status (false);
1475 if (synced_to_engine()) {
1476 _engine.transport_start ();
1477 _count_in_once = false;
1484 /* not zero, not 1.0 ... varispeed */
1486 // TODO handled transport start.. _remaining_latency_preroll
1487 // and reversal of playback direction.
1489 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
1490 warning << string_compose (
1491 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
1498 if (actively_recording()) {
1503 if (speed > 0.0 && _transport_sample == current_end_sample()) {
1507 if (speed < 0.0 && _transport_sample == 0) {
1513 /* if we are reversing relative to the current speed, or relative to the speed
1514 before the last stop, then we have to do extra work.
1517 PostTransportWork todo = PostTransportWork (0);
1519 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
1520 todo = PostTransportWork (todo | PostTransportReverse);
1521 _last_roll_or_reversal_location = _transport_sample;
1524 _last_transport_speed = _transport_speed;
1525 _transport_speed = speed;
1528 _default_transport_speed = speed;
1532 add_post_transport_work (todo);
1533 _butler->schedule_transport_work ();
1536 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
1538 /* throttle signal emissions.
1539 * when slaved [_last]_transport_speed
1540 * usually changes every cycle (tiny amounts due to DLL).
1541 * Emitting a signal every cycle is overkill and unwarranted.
1543 * Using _last_transport_speed is not acceptable,
1544 * since it allows for large changes over a long period
1545 * of time. Hence we introduce a dedicated variable to keep track
1547 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
1548 * for TransportStateChange() here is the ShuttleControl display.
1550 if (fabs (_signalled_varispeed - actual_speed ()) > .002
1551 // still, signal hard changes to 1.0 and 0.0:
1552 || (actual_speed () == 1.0 && _signalled_varispeed != 1.0)
1553 || (actual_speed () == 0.0 && _signalled_varispeed != 0.0)
1556 TransportStateChange (); /* EMIT SIGNAL */
1557 _signalled_varispeed = actual_speed ();
1563 /** Stop the transport. */
1565 Session::stop_transport (bool abort, bool clear_state)
1567 _count_in_once = false;
1568 if (_transport_speed == 0.0f) {
1572 DEBUG_TRACE (DEBUG::Transport, "time to actually stop\n");
1574 realtime_stop (abort, clear_state);
1575 _butler->schedule_transport_work ();
1578 /** Called from the process thread */
1580 Session::start_transport ()
1582 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
1584 _last_roll_location = _transport_sample;
1585 _last_roll_or_reversal_location = _transport_sample;
1586 _remaining_latency_preroll = worst_latency_preroll ();
1588 have_looped = false;
1590 /* if record status is Enabled, move it to Recording. if its
1591 already Recording, move it to Disabled.
1594 switch (record_status()) {
1596 if (!config.get_punch_in()) {
1597 /* This is only for UIs (keep blinking rec-en before
1598 * punch-in, don't show rec-region etc). The UI still
1599 * depends on SessionEvent::PunchIn and ensuing signals.
1601 * The disk-writers handle punch in/out internally
1602 * in their local delay-compensated timeframe.
1610 disable_record (false);
1618 _transport_speed = _default_transport_speed;
1619 _target_transport_speed = _transport_speed;
1621 if (!_engine.freewheeling()) {
1622 Timecode::Time time;
1623 timecode_time_subframes (_transport_sample, time);
1624 if (transport_master()->type() == MTC) {
1625 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
1628 if (actively_recording() && click_data && (config.get_count_in () || _count_in_once)) {
1629 _count_in_once = false;
1630 /* calculate count-in duration (in audio samples)
1631 * - use [fixed] tempo/meter at _transport_sample
1632 * - calc duration of 1 bar + time-to-beat before or at transport_sample
1634 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
1635 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
1637 const double num = meter.divisions_per_bar ();
1638 const double den = meter.note_divisor ();
1639 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
1640 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
1642 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
1644 double dt = _count_in_samples / num;
1645 if (bar_fract == 0) {
1646 /* at bar boundary, count-in 2 bars before start. */
1647 _count_in_samples *= 2;
1649 /* beats left after full bar until roll position */
1650 _count_in_samples *= 1. + bar_fract;
1653 if (_count_in_samples > _remaining_latency_preroll) {
1654 _remaining_latency_preroll = _count_in_samples;
1658 samplepos_t cf = _transport_sample - _count_in_samples;
1659 samplecnt_t offset = _click_io->connected_latency (true);
1660 while (cf < _transport_sample + offset) {
1661 add_click (cf, clickbeat == 0);
1663 clickbeat = fmod (clickbeat + 1, num);
1666 if (_count_in_samples < _remaining_latency_preroll) {
1667 _count_in_samples = _remaining_latency_preroll;
1672 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
1673 TransportStateChange (); /* EMIT SIGNAL */
1676 /** Do any transport work in the audio thread that needs to be done after the
1677 * transport thread is finished. Audio thread, realtime safe.
1680 Session::post_transport ()
1682 PostTransportWork ptw = post_transport_work ();
1684 if (ptw & PostTransportAudition) {
1685 if (auditioner && auditioner->auditioning()) {
1686 process_function = &Session::process_audition;
1688 process_function = &Session::process_with_events;
1692 if (ptw & PostTransportStop) {
1694 transport_sub_state = 0;
1697 if (ptw & PostTransportLocate) {
1699 if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
1700 _count_in_once = false;
1703 transport_sub_state = 0;
1708 /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
1711 set_post_transport_work (PostTransportWork (0));
1715 Session::reset_rf_scale (samplecnt_t motion)
1717 cumulative_rf_motion += motion;
1719 if (cumulative_rf_motion < 4 * _current_sample_rate) {
1721 } else if (cumulative_rf_motion < 8 * _current_sample_rate) {
1723 } else if (cumulative_rf_motion < 16 * _current_sample_rate) {
1735 Session::unset_play_range ()
1737 _play_range = false;
1738 _clear_event_type (SessionEvent::RangeStop);
1739 _clear_event_type (SessionEvent::RangeLocate);
1743 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1747 /* Called from event-processing context */
1749 unset_play_range ();
1751 if (range.empty()) {
1752 /* _play_range set to false in unset_play_range()
1754 if (!leave_rolling) {
1755 /* stop transport */
1756 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1764 /* cancel loop play */
1767 list<AudioRange>::size_type sz = range.size();
1771 list<AudioRange>::iterator i = range.begin();
1772 list<AudioRange>::iterator next;
1774 while (i != range.end()) {
1779 /* locating/stopping is subject to delays for declicking.
1782 samplepos_t requested_sample = i->end;
1784 if (requested_sample > current_block_size) {
1785 requested_sample -= current_block_size;
1787 requested_sample = 0;
1790 if (next == range.end()) {
1791 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1793 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1801 } else if (sz == 1) {
1803 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1808 /* save range so we can do auto-return etc. */
1810 current_audio_range = range;
1812 /* now start rolling at the right place */
1814 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1817 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1818 TransportStateChange ();
1822 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1824 AudioRange ar (start, end, 0);
1825 list<AudioRange> lar;
1828 request_play_range (&lar, true);
1832 Session::set_requested_return_sample (samplepos_t return_to)
1834 _requested_return_sample = return_to;
1838 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1840 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1841 ev->target2_sample = start;
1846 Session::engine_halted ()
1850 /* there will be no more calls to process(), so
1851 we'd better clean up for ourselves, right now.
1853 but first, make sure the butler is out of
1861 realtime_stop (false, true);
1862 non_realtime_stop (false, 0, ignored);
1863 transport_sub_state = 0;
1865 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC6 with speed = %1\n", _transport_speed));
1866 TransportStateChange (); /* EMIT SIGNAL */
1871 Session::xrun_recovery ()
1875 Xrun (_transport_sample); /* EMIT SIGNAL */
1877 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1879 /* it didn't actually halt, but we need
1880 to handle things in the same way.
1888 Session::route_processors_changed (RouteProcessorChange c)
1890 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1894 if (c.type == RouteProcessorChange::MeterPointChange) {
1899 if (c.type == RouteProcessorChange::RealTimeChange) {
1904 update_latency_compensation ();
1911 Session::allow_auto_play (bool yn)
1913 auto_play_legal = yn;
1917 Session::maybe_stop (samplepos_t limit)
1919 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
1920 if (synced_to_engine () && config.get_jack_time_master ()) {
1921 _engine.transport_stop ();
1922 } else if (!synced_to_engine ()) {
1931 Session::send_mmc_locate (samplepos_t t)
1937 if (!_engine.freewheeling()) {
1938 Timecode::Time time;
1939 timecode_time_subframes (t, time);
1940 send_immediate_mmc (MIDI::MachineControlCommand (time));
1944 /** Ask the transport to not send timecode until further notice. The suspension
1945 * will come into effect some finite time after this call, and timecode_transmission_suspended()
1946 * should be checked by the caller to find out when.
1949 Session::request_suspend_timecode_transmission ()
1951 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
1956 Session::request_resume_timecode_transmission ()
1958 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
1963 Session::timecode_transmission_suspended () const
1965 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
1968 boost::shared_ptr<TransportMaster>
1969 Session::transport_master() const
1971 return TransportMasterManager::instance().current();
1975 Session::transport_master_is_external () const
1977 return config.get_external_sync();
1981 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
1983 /* Runs in process() context */
1985 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
1987 /* save value of seamless from before the switch */
1988 _was_seamless = Config->get_seamless_loop ();
1990 if (type == Engine) {
1991 /* JACK cannot support seamless looping at present */
1992 Config->set_seamless_loop (false);
1994 /* reset to whatever the value was before we last switched slaves */
1995 Config->set_seamless_loop (_was_seamless);
1998 if (master->can_loop()) {
1999 request_play_loop (false);
2000 } else if (master->has_loop()) {
2001 request_play_loop (true);
2004 /* slave change, reset any DiskIO block on disk output because it is no
2005 longer valid with a new slave.
2008 DiskReader::set_no_disk_output (false);
2011 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
2013 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
2016 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
2017 MTCSyncStateChanged(mtc_master->locked() );
2019 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
2020 MTCSyncStateChanged( false );
2022 mtc_status_connection.disconnect ();
2025 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
2028 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
2029 LTCSyncStateChanged (ltc_master->locked() );
2031 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
2032 LTCSyncStateChanged( false );
2034 ltc_status_connection.disconnect ();
2038 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
2040 // need to queue this for next process() cycle
2041 _send_timecode_update = true;
2043 boost::shared_ptr<RouteList> rl = routes.reader();
2044 const bool externally_slaved = transport_master_is_external();
2046 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2047 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2048 if (tr && !tr->is_private_route()) {
2049 tr->set_slaved (externally_slaved);