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 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
496 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
498 tr->adjust_capture_buffering ();
503 if (ptw & PostTransportCurveRealloc) {
504 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
505 (*i)->curve_reallocate();
509 if (ptw & PostTransportReverse) {
512 cumulative_rf_motion = 0;
515 /* don't seek if locate will take care of that in non_realtime_stop() */
517 if (!(ptw & PostTransportLocate)) {
518 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
519 (*i)->non_realtime_locate (_transport_sample);
521 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
522 /* new request, stop seeking, and start again */
523 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
527 VCAList v = _vca_manager->vcas ();
528 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
529 (*i)->non_realtime_locate (_transport_sample);
534 if (ptw & PostTransportLocate) {
535 DEBUG_TRACE (DEBUG::Transport, "nonrealtime locate invoked from BTW\n");
536 non_realtime_locate ();
539 if (ptw & PostTransportStop) {
540 non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
542 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
547 if (ptw & PostTransportOverWrite) {
548 non_realtime_overwrite (on_entry, finished);
550 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
555 if (ptw & PostTransportAudition) {
556 non_realtime_set_audition ();
559 g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
561 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()));
565 Session::non_realtime_overwrite (int on_entry, bool& finished)
567 boost::shared_ptr<RouteList> rl = routes.reader();
568 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
569 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
570 if (tr && tr->pending_overwrite ()) {
571 tr->overwrite_existing_buffers ();
573 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
582 Session::non_realtime_locate ()
584 DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_sample));
586 if (Config->get_loop_is_mode() && get_play_loop()) {
588 Location *loc = _locations->auto_loop_location();
590 if (!loc || (_transport_sample < loc->start() || _transport_sample >= loc->end())) {
591 /* jumped out of loop range: stop tracks from looping,
592 but leave loop (mode) enabled.
594 set_track_loop (false);
596 } else if (loc && Config->get_seamless_loop() &&
597 ((loc->start() <= _transport_sample) ||
598 (loc->end() > _transport_sample) ) ) {
600 /* jumping to start of loop. This might have been done before but it is
601 * idempotent and cheap. Doing it here ensures that when we start playback
602 * outside the loop we still flip tracks into the magic seamless mode
605 set_track_loop (true);
608 set_track_loop (false);
613 /* no more looping .. should have been noticed elsewhere */
620 boost::shared_ptr<RouteList> rl = routes.reader();
623 gint sc = g_atomic_int_get (&_seek_counter);
624 tf = _transport_sample;
626 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
627 (*i)->non_realtime_locate (tf);
628 if (sc != g_atomic_int_get (&_seek_counter)) {
635 /* VCAs are quick to locate because they have no data (except
636 automation) associated with them. Don't bother with a
637 restart mechanism here, but do use the same transport sample
638 that the Routes used.
640 VCAList v = _vca_manager->vcas ();
641 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
642 (*i)->non_realtime_locate (tf);
646 _scene_changer->locate (_transport_sample);
648 /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
649 rather than clearing them so that the RT thread has to spend time constructing
650 them (in Session::click).
655 #ifdef USE_TRACKS_CODE_FEATURES
657 Session::select_playhead_priority_target (samplepos_t& jump_to)
661 AutoReturnTarget autoreturn = Config->get_auto_return_target_list ();
667 if (Profile->get_trx() && transport_rolling() ) {
668 // We're playing, so do nothing.
669 // Next stop will put us where we need to be.
673 /* Note that the order of checking each AutoReturnTarget flag defines
674 the priority each flag.
676 Ardour/Mixbus: Last Locate
681 Tracks: Range Selection
687 if (autoreturn & RangeSelectionStart) {
688 if (!_range_selection.empty()) {
689 jump_to = _range_selection.from;
691 if (transport_rolling ()) {
692 /* Range selection no longer exists, but we're playing,
693 so do nothing. Next stop will put us where
701 if (jump_to < 0 && (autoreturn & Loop) && get_play_loop()) {
702 /* don't try to handle loop play when synced to JACK */
704 if (!synced_to_engine()) {
705 Location *location = _locations->auto_loop_location();
708 jump_to = location->start();
710 if (Config->get_seamless_loop()) {
711 /* need to get track buffers reloaded */
712 set_track_loop (true);
718 if (jump_to < 0 && (autoreturn & RegionSelectionStart)) {
719 if (!_object_selection.empty()) {
720 jump_to = _object_selection.from;
724 if (jump_to < 0 && (autoreturn & LastLocate)) {
725 jump_to = _last_roll_location;
733 Session::select_playhead_priority_target (samplepos_t& jump_to)
735 if (config.get_external_sync() || !config.get_auto_return()) {
739 jump_to = _last_roll_location;
746 Session::follow_playhead_priority ()
750 if (select_playhead_priority_target (target)) {
751 request_locate (target);
756 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
762 PostTransportWork ptw = post_transport_work();
767 boost::shared_ptr<RouteList> rl = routes.reader();
768 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
769 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
770 if (tr && tr->get_captured_samples () != 0) {
776 /* stop and locate are merged here because they share a lot of common stuff */
779 now = localtime (&xnow);
782 auditioner->cancel_audition ();
785 cumulative_rf_motion = 0;
789 begin_reversible_command (Operations::capture);
790 _have_captured = true;
793 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
795 if (abort && did_record) {
796 /* no reason to save the session file when we remove sources
798 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
801 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
802 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
804 tr->transport_stopped_wallclock (*now, xnow, abort);
808 if (abort && did_record) {
809 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
812 boost::shared_ptr<RouteList> r = routes.reader ();
815 commit_reversible_command ();
816 /* increase take name */
817 if (config.get_track_name_take () && !config.get_take_name ().empty()) {
818 string newname = config.get_take_name();
819 config.set_take_name(bump_name_number (newname));
823 if (_engine.running()) {
824 PostTransportWork ptw = post_transport_work ();
826 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
827 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
829 VCAList v = _vca_manager->vcas ();
830 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
831 (*i)->non_realtime_transport_stop (_transport_sample, !(ptw & PostTransportLocate));
834 update_latency_compensation ();
837 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
839 if (auto_return_enabled ||
840 (ptw & PostTransportLocate) ||
841 (_requested_return_sample >= 0) ||
842 synced_to_engine()) {
844 // rg: what is the logic behind this case?
845 // _requested_return_sample should be ignored when synced_to_engine/slaved.
846 // currently worked around in MTC_Slave by forcing _requested_return_sample to -1
848 if ((auto_return_enabled || synced_to_engine() || _requested_return_sample >= 0) &&
849 !(ptw & PostTransportLocate)) {
851 /* no explicit locate queued */
853 bool do_locate = false;
855 if (_requested_return_sample >= 0) {
857 /* explicit return request pre-queued in event list. overrides everything else */
859 _transport_sample = _requested_return_sample;
865 if (select_playhead_priority_target (jump_to)) {
867 _transport_sample = jump_to;
872 _transport_sample = _last_roll_location;
877 _requested_return_sample = -1;
880 _engine.transport_locate (_transport_sample);
887 unset_preroll_record_trim ();
889 /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
892 if (ptw & PostTransportClearSubstate) {
894 if (!Config->get_loop_is_mode()) {
899 /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
902 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
903 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
904 DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
905 (*i)->non_realtime_locate (_transport_sample);
907 if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
909 /* we will be back */
916 VCAList v = _vca_manager->vcas ();
917 for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
918 (*i)->non_realtime_locate (_transport_sample);
924 /* don't bother with this stuff if we're disconnected from the engine,
925 because there will be no process callbacks to deliver stuff from
928 if (_engine.connected() && !_engine.freewheeling()) {
929 // need to queue this in the next RT cycle
930 _send_timecode_update = true;
932 if (transport_master()->type() == MTC) {
933 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
935 /* This (::non_realtime_stop()) gets called by main
936 process thread, which will lead to confusion
937 when calling AsyncMIDIPort::write().
939 Something must be done. XXX
941 send_mmc_locate (_transport_sample);
945 if ((ptw & PostTransportLocate) && get_record_enabled()) {
946 /* This is scheduled by realtime_stop(), which is also done
947 * when a slave requests /locate/ for an initial sync.
948 * We can't hold up the slave for long with a save() here,
949 * without breaking its initial sync cycle.
951 * save state only if there's no slave or if it's not yet locked.
953 if (!transport_master_is_external() || !transport_master()->locked()) {
954 DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: requests save\n"));
955 SaveSessionRequested (_current_snapshot_name);
960 /* always try to get rid of this */
962 remove_pending_capture_state ();
964 /* save the current state of things if appropriate */
966 if (did_record && !saved) {
967 SaveSessionRequested (_current_snapshot_name);
970 if (ptw & PostTransportStop) {
972 if (!Config->get_loop_is_mode()) {
977 PositionChanged (_transport_sample); /* EMIT SIGNAL */
978 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
979 TransportStateChange (); /* EMIT SIGNAL */
980 AutomationWatch::instance().transport_stop_automation_watches (_transport_sample);
982 /* and start it up again if relevant */
984 if ((ptw & PostTransportLocate) && !config.get_external_sync()) {
985 request_transport_speed (1.0);
990 Session::unset_play_loop ()
994 clear_events (SessionEvent::AutoLoop);
995 set_track_loop (false);
998 if (Config->get_seamless_loop()) {
999 /* likely need to flush track buffers: this will locate us to wherever we are */
1000 add_post_transport_work (PostTransportLocate);
1001 _butler->schedule_transport_work ();
1003 TransportStateChange (); /* EMIT SIGNAL */
1008 Session::set_track_loop (bool yn)
1010 Location* loc = _locations->auto_loop_location ();
1016 boost::shared_ptr<RouteList> rl = routes.reader ();
1018 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1019 if (*i && !(*i)->is_private_route()) {
1020 (*i)->set_loop (yn ? loc : 0);
1026 Session::set_play_loop (bool yn, double speed)
1028 /* Called from event-handling context */
1032 if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
1033 /* nothing to do, or can't change loop status while recording */
1037 if (yn && Config->get_seamless_loop() && synced_to_engine()) {
1038 warning << string_compose (
1039 _("Seamless looping cannot be supported while %1 is using JACK transport.\n"
1040 "Recommend changing the configured options"), PROGRAM_NAME)
1048 have_looped = false;
1052 unset_play_range ();
1054 if (Config->get_seamless_loop()) {
1055 if (!Config->get_loop_is_mode()) {
1056 /* set all tracks to use internal looping */
1057 set_track_loop (true);
1059 /* we will do this in the locate to the start OR when we hit the end
1060 * of the loop for the first time
1064 /* set all tracks to NOT use internal looping */
1065 set_track_loop (false);
1068 /* Put the delick and loop events in into the event list. The declick event will
1069 cause a de-clicking fade-out just before the end of the loop, and it will also result
1070 in a fade-in when the loop restarts. The AutoLoop event will peform the actual loop.
1075 auto_loop_declick_range (loc, dcp, dcl);
1076 merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
1078 /* if requested to roll, locate to start of loop and
1079 * roll but ONLY if we're not already rolling.
1081 args: positition, roll=true, flush=true, with_loop=false, force buffer refill if seamless looping
1084 if (Config->get_loop_is_mode()) {
1085 /* loop IS a transport mode: if already
1086 rolling, do not locate to loop start.
1088 if (!transport_rolling() && (speed != 0.0)) {
1089 start_locate (loc->start(), true, true, false, true);
1093 start_locate (loc->start(), true, true, false, true);
1103 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
1104 TransportStateChange ();
1107 Session::flush_all_inserts ()
1109 boost::shared_ptr<RouteList> r = routes.reader ();
1111 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1112 (*i)->flush_processors ();
1117 Session::start_locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force)
1119 if (target_sample < 0) {
1120 error << _("Locate called for negative sample position - ignored") << endmsg;
1124 if (synced_to_engine()) {
1128 samplepos_t ignore1, ignore2;
1130 transport_master()->speed_and_position (sp, pos, ignore1, ignore2, 0);
1132 if (target_sample != pos) {
1134 if (config.get_jack_time_master()) {
1135 /* actually locate now, since otherwise jack_timebase_callback
1136 will use the incorrect _transport_sample and report an old
1137 and incorrect time to Jack transport
1139 locate (target_sample, with_roll, with_flush, for_loop_enabled, force);
1142 /* tell JACK to change transport position, and we will
1143 follow along later in ::follow_slave()
1146 _engine.transport_locate (target_sample);
1148 if (sp != 1.0f && with_roll) {
1149 _engine.transport_start ();
1155 locate (target_sample, with_roll, with_flush, for_loop_enabled, force);
1160 Session::worst_latency_preroll () const
1162 return _worst_output_latency + _worst_input_latency;
1166 Session::micro_locate (samplecnt_t distance)
1168 boost::shared_ptr<RouteList> rl = routes.reader();
1169 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1170 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1171 if (tr && !tr->can_internal_playback_seek (distance)) {
1176 DEBUG_TRACE (DEBUG::Transport, string_compose ("micro-locate by %1\n", distance));
1178 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1179 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1181 tr->internal_playback_seek (distance);
1185 _transport_sample += distance;
1189 /** @param with_mmc true to send a MMC locate command when the locate is done */
1191 Session::locate (samplepos_t target_sample, bool with_roll, bool with_flush, bool for_loop_enabled, bool force, bool with_mmc)
1193 bool need_butler = false;
1195 /* Locates for seamless looping are fairly different from other
1196 * locates. They assume that the diskstream buffers for each track
1197 * already have the correct data in them, and thus there is no need to
1198 * actually tell the tracks to locate. What does need to be done,
1199 * though, is all the housekeeping that is associated with non-linear
1200 * changes in the value of _transport_sample.
1203 DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 loop-enabled %4 force %5 mmc %6\n",
1204 target_sample, with_roll, with_flush, for_loop_enabled, force, with_mmc));
1206 if (!force && _transport_sample == target_sample && !loop_changing && !for_loop_enabled) {
1208 /* already at the desired position. Not forced to locate,
1209 the loop isn't changing, so unless we're told to
1210 start rolling also, there's nothing to do but
1211 tell the world where we are (again).
1215 set_transport_speed (1.0, 0, false);
1217 loop_changing = false;
1218 Located (); /* EMIT SIGNAL */
1222 cerr << "... now doing the actual locate\n";
1224 // Update Timecode time
1225 _transport_sample = target_sample;
1226 // Bump seek counter so that any in-process locate in the butler
1227 // thread(s?) can restart.
1228 g_atomic_int_inc (&_seek_counter);
1229 _last_roll_or_reversal_location = target_sample;
1230 _remaining_latency_preroll = worst_latency_preroll ();
1231 timecode_time(_transport_sample, transmitting_timecode_time); // XXX here?
1233 /* do "stopped" stuff if:
1235 * we are rolling AND
1236 * no autoplay in effect AND
1237 * we're not going to keep rolling after the locate AND
1238 * !(playing a loop with JACK sync)
1242 bool transport_was_stopped = !transport_rolling();
1244 if (!transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop) &&
1245 (!Profile->get_trx() || !(config.get_external_sync() && !synced_to_engine()))) {
1246 realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
1247 transport_was_stopped = true;
1249 /* otherwise tell the world that we located */
1253 if (force || !for_loop_enabled || loop_changing) {
1255 PostTransportWork todo = PostTransportLocate;
1257 if (with_roll && transport_was_stopped) {
1258 todo = PostTransportWork (todo | PostTransportRoll);
1261 add_post_transport_work (todo);
1266 /* this is functionally what clear_clicks() does but with a tentative lock */
1268 Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
1270 if (clickm.locked()) {
1272 for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
1281 /* switch from input if we're going to roll */
1282 if (Config->get_monitoring_model() == HardwareMonitoring) {
1283 set_track_monitor_input_status (!config.get_auto_input());
1286 /* otherwise we're going to stop, so do the opposite */
1287 if (Config->get_monitoring_model() == HardwareMonitoring) {
1288 set_track_monitor_input_status (true);
1292 /* cancel looped playback if transport pos outside of loop range */
1295 Location* al = _locations->auto_loop_location();
1298 if (_transport_sample < al->start() || _transport_sample >= al->end()) {
1300 // located outside the loop: cancel looping directly, this is called from event handling context
1302 have_looped = false;
1304 if (!Config->get_loop_is_mode()) {
1305 set_play_loop (false, _transport_speed);
1307 if (Config->get_seamless_loop()) {
1308 /* this will make the non_realtime_locate() in the butler
1309 which then causes seek() in tracks actually do the right
1312 set_track_loop (false);
1316 } else if (_transport_sample == al->start()) {
1318 // located to start of loop - this is looping, basically
1322 if (_last_roll_location != al->start()) {
1323 /* didn't start at loop start - playback must have
1324 * started before loop since we've now hit the loop
1327 add_post_transport_work (PostTransportLocate);
1333 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);
1338 if (tr && tr->rec_enable_control()->get_value()) {
1339 // tell it we've looped, so it can deal with the record state
1340 tr->transport_looped (_transport_sample);
1345 TransportLooped(); // EMIT SIGNAL
1351 _butler->schedule_transport_work ();
1354 loop_changing = false;
1356 _send_timecode_update = true;
1359 send_mmc_locate (_transport_sample);
1362 _last_roll_location = _last_roll_or_reversal_location = _transport_sample;
1363 if (!synced_to_engine () || _transport_sample == _engine.transport_sample ()) {
1364 Located (); /* EMIT SIGNAL */
1368 /** Set the transport speed.
1369 * Called from the process thread.
1370 * @param speed New speed
1373 Session::set_transport_speed (double speed, samplepos_t destination_sample, bool abort, bool clear_state, bool as_default)
1375 DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n",
1376 speed, abort, clear_state, _transport_speed, _transport_sample, as_default));
1378 /* max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
1379 and user needs. We really need CD-style "skip" playback for ffwd and rewind.
1383 speed = min (8.0, speed);
1384 } else if (speed < 0) {
1385 speed = max (-8.0, speed);
1388 double new_engine_speed = 1.0;
1390 new_engine_speed = fabs (speed);
1391 if (speed < 0) speed = -1;
1392 if (speed > 0) speed = 1;
1395 if (_transport_speed == speed && new_engine_speed == _engine_speed) {
1396 if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
1397 _default_transport_speed = 1.0;
1402 #if 0 // TODO pref: allow vari-speed recording
1403 if (actively_recording() && speed != 1.0 && speed != 0.0) {
1404 /* no varispeed during recording */
1405 DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, sample %2\n",
1406 _transport_speed, _transport_sample));
1411 _target_transport_speed = fabs(speed);
1412 _engine_speed = new_engine_speed;
1414 if (transport_rolling() && speed == 0.0) {
1416 /* we are rolling and we want to stop */
1418 if (Config->get_monitoring_model() == HardwareMonitoring) {
1419 set_track_monitor_input_status (true);
1422 if (synced_to_engine ()) {
1424 /* do this here because our response to the slave won't
1427 _play_range = false;
1428 _count_in_once = false;
1431 _engine.transport_stop ();
1433 bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort));
1435 if (!auto_return_enabled) {
1436 _requested_return_sample = destination_sample;
1439 stop_transport (abort);
1442 } else if (transport_stopped() && speed == 1.0) {
1444 _default_transport_speed = speed;
1446 /* we are stopped and we want to start rolling at speed 1 */
1448 if (Config->get_loop_is_mode() && play_loop) {
1450 Location *location = _locations->auto_loop_location();
1452 if (location != 0) {
1453 if (_transport_sample != location->start()) {
1455 if (Config->get_seamless_loop()) {
1456 /* force tracks to do their thing */
1457 set_track_loop (true);
1460 /* jump to start and then roll from there */
1462 request_locate (location->start(), true);
1468 if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
1469 set_track_monitor_input_status (false);
1472 if (synced_to_engine()) {
1473 _engine.transport_start ();
1474 _count_in_once = false;
1481 /* not zero, not 1.0 ... varispeed */
1483 // TODO handled transport start.. _remaining_latency_preroll
1484 // and reversal of playback direction.
1486 if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) {
1487 warning << string_compose (
1488 _("Global varispeed cannot be supported while %1 is connected to JACK transport control"),
1495 if (actively_recording()) {
1500 if (speed > 0.0 && _transport_sample == current_end_sample()) {
1504 if (speed < 0.0 && _transport_sample == 0) {
1510 /* if we are reversing relative to the current speed, or relative to the speed
1511 before the last stop, then we have to do extra work.
1514 PostTransportWork todo = PostTransportWork (0);
1516 if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0 && speed < 0.0)) {
1517 todo = PostTransportWork (todo | PostTransportReverse);
1518 _last_roll_or_reversal_location = _transport_sample;
1521 _last_transport_speed = _transport_speed;
1522 _transport_speed = speed;
1525 _default_transport_speed = speed;
1529 add_post_transport_work (todo);
1530 _butler->schedule_transport_work ();
1533 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
1535 /* throttle signal emissions.
1536 * when slaved [_last]_transport_speed
1537 * usually changes every cycle (tiny amounts due to DLL).
1538 * Emitting a signal every cycle is overkill and unwarranted.
1540 * Using _last_transport_speed is not acceptable,
1541 * since it allows for large changes over a long period
1542 * of time. Hence we introduce a dedicated variable to keep track
1544 * The 0.2% dead-zone is somewhat arbitrary. Main use-case
1545 * for TransportStateChange() here is the ShuttleControl display.
1547 if (fabs (_signalled_varispeed - actual_speed ()) > .002
1548 // still, signal hard changes to 1.0 and 0.0:
1549 || (actual_speed () == 1.0 && _signalled_varispeed != 1.0)
1550 || (actual_speed () == 0.0 && _signalled_varispeed != 0.0)
1553 TransportStateChange (); /* EMIT SIGNAL */
1554 _signalled_varispeed = actual_speed ();
1560 /** Stop the transport. */
1562 Session::stop_transport (bool abort, bool clear_state)
1564 _count_in_once = false;
1565 if (_transport_speed == 0.0f) {
1569 DEBUG_TRACE (DEBUG::Transport, "time to actually stop\n");
1571 realtime_stop (abort, clear_state);
1572 _butler->schedule_transport_work ();
1575 /** Called from the process thread */
1577 Session::start_transport ()
1579 DEBUG_TRACE (DEBUG::Transport, "start_transport\n");
1581 _last_roll_location = _transport_sample;
1582 _last_roll_or_reversal_location = _transport_sample;
1583 _remaining_latency_preroll = worst_latency_preroll ();
1585 have_looped = false;
1587 /* if record status is Enabled, move it to Recording. if its
1588 already Recording, move it to Disabled.
1591 switch (record_status()) {
1593 if (!config.get_punch_in()) {
1594 /* This is only for UIs (keep blinking rec-en before
1595 * punch-in, don't show rec-region etc). The UI still
1596 * depends on SessionEvent::PunchIn and ensuing signals.
1598 * The disk-writers handle punch in/out internally
1599 * in their local delay-compensated timeframe.
1607 disable_record (false);
1615 _transport_speed = _default_transport_speed;
1616 _target_transport_speed = _transport_speed;
1618 if (!_engine.freewheeling()) {
1619 Timecode::Time time;
1620 timecode_time_subframes (_transport_sample, time);
1621 if (transport_master()->type() == MTC) {
1622 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
1625 if (actively_recording() && click_data && (config.get_count_in () || _count_in_once)) {
1626 _count_in_once = false;
1627 /* calculate count-in duration (in audio samples)
1628 * - use [fixed] tempo/meter at _transport_sample
1629 * - calc duration of 1 bar + time-to-beat before or at transport_sample
1631 const Tempo& tempo = _tempo_map->tempo_at_sample (_transport_sample);
1632 const Meter& meter = _tempo_map->meter_at_sample (_transport_sample);
1634 const double num = meter.divisions_per_bar ();
1635 const double den = meter.note_divisor ();
1636 const double barbeat = _tempo_map->exact_qn_at_sample (_transport_sample, 0) * den / (4. * num);
1637 const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
1639 _count_in_samples = meter.samples_per_bar (tempo, _current_sample_rate);
1641 double dt = _count_in_samples / num;
1642 if (bar_fract == 0) {
1643 /* at bar boundary, count-in 2 bars before start. */
1644 _count_in_samples *= 2;
1646 /* beats left after full bar until roll position */
1647 _count_in_samples *= 1. + bar_fract;
1650 if (_count_in_samples > _remaining_latency_preroll) {
1651 _remaining_latency_preroll = _count_in_samples;
1655 samplepos_t cf = _transport_sample - _count_in_samples;
1656 samplecnt_t offset = _click_io->connected_latency (true);
1657 while (cf < _transport_sample + offset) {
1658 add_click (cf, clickbeat == 0);
1660 clickbeat = fmod (clickbeat + 1, num);
1663 if (_count_in_samples < _remaining_latency_preroll) {
1664 _count_in_samples = _remaining_latency_preroll;
1669 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
1670 TransportStateChange (); /* EMIT SIGNAL */
1673 /** Do any transport work in the audio thread that needs to be done after the
1674 * transport thread is finished. Audio thread, realtime safe.
1677 Session::post_transport ()
1679 PostTransportWork ptw = post_transport_work ();
1681 if (ptw & PostTransportAudition) {
1682 if (auditioner && auditioner->auditioning()) {
1683 process_function = &Session::process_audition;
1685 process_function = &Session::process_with_events;
1689 if (ptw & PostTransportStop) {
1691 transport_sub_state = 0;
1694 if (ptw & PostTransportLocate) {
1696 if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
1697 _count_in_once = false;
1700 transport_sub_state = 0;
1705 /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
1708 set_post_transport_work (PostTransportWork (0));
1712 Session::reset_rf_scale (samplecnt_t motion)
1714 cumulative_rf_motion += motion;
1716 if (cumulative_rf_motion < 4 * _current_sample_rate) {
1718 } else if (cumulative_rf_motion < 8 * _current_sample_rate) {
1720 } else if (cumulative_rf_motion < 16 * _current_sample_rate) {
1732 Session::unset_play_range ()
1734 _play_range = false;
1735 _clear_event_type (SessionEvent::RangeStop);
1736 _clear_event_type (SessionEvent::RangeLocate);
1740 Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
1744 /* Called from event-processing context */
1746 unset_play_range ();
1748 if (range.empty()) {
1749 /* _play_range set to false in unset_play_range()
1751 if (!leave_rolling) {
1752 /* stop transport */
1753 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0f, false);
1761 /* cancel loop play */
1764 list<AudioRange>::size_type sz = range.size();
1768 list<AudioRange>::iterator i = range.begin();
1769 list<AudioRange>::iterator next;
1771 while (i != range.end()) {
1776 /* locating/stopping is subject to delays for declicking.
1779 samplepos_t requested_sample = i->end;
1781 if (requested_sample > current_block_size) {
1782 requested_sample -= current_block_size;
1784 requested_sample = 0;
1787 if (next == range.end()) {
1788 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, requested_sample, 0, 0.0f);
1790 ev = new SessionEvent (SessionEvent::RangeLocate, SessionEvent::Add, requested_sample, (*next).start, 0.0f);
1798 } else if (sz == 1) {
1800 ev = new SessionEvent (SessionEvent::RangeStop, SessionEvent::Add, range.front().end, 0, 0.0f);
1805 /* save range so we can do auto-return etc. */
1807 current_audio_range = range;
1809 /* now start rolling at the right place */
1811 ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
1814 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
1815 TransportStateChange ();
1819 Session::request_bounded_roll (samplepos_t start, samplepos_t end)
1821 AudioRange ar (start, end, 0);
1822 list<AudioRange> lar;
1825 request_play_range (&lar, true);
1829 Session::set_requested_return_sample (samplepos_t return_to)
1831 _requested_return_sample = return_to;
1835 Session::request_roll_at_and_return (samplepos_t start, samplepos_t return_to)
1837 SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
1838 ev->target2_sample = start;
1843 Session::engine_halted ()
1847 /* there will be no more calls to process(), so
1848 we'd better clean up for ourselves, right now.
1850 but first, make sure the butler is out of
1858 realtime_stop (false, true);
1859 non_realtime_stop (false, 0, ignored);
1860 transport_sub_state = 0;
1862 DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC6 with speed = %1\n", _transport_speed));
1863 TransportStateChange (); /* EMIT SIGNAL */
1868 Session::xrun_recovery ()
1872 Xrun (_transport_sample); /* EMIT SIGNAL */
1874 if (Config->get_stop_recording_on_xrun() && actively_recording()) {
1876 /* it didn't actually halt, but we need
1877 to handle things in the same way.
1885 Session::route_processors_changed (RouteProcessorChange c)
1887 if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
1891 if (c.type == RouteProcessorChange::MeterPointChange) {
1896 if (c.type == RouteProcessorChange::RealTimeChange) {
1901 update_latency_compensation ();
1908 Session::allow_auto_play (bool yn)
1910 auto_play_legal = yn;
1914 Session::maybe_stop (samplepos_t limit)
1916 if ((_transport_speed > 0.0f && _transport_sample >= limit) || (_transport_speed < 0.0f && _transport_sample == 0)) {
1917 if (synced_to_engine () && config.get_jack_time_master ()) {
1918 _engine.transport_stop ();
1919 } else if (!synced_to_engine ()) {
1928 Session::send_mmc_locate (samplepos_t t)
1934 if (!_engine.freewheeling()) {
1935 Timecode::Time time;
1936 timecode_time_subframes (t, time);
1937 send_immediate_mmc (MIDI::MachineControlCommand (time));
1941 /** Ask the transport to not send timecode until further notice. The suspension
1942 * will come into effect some finite time after this call, and timecode_transmission_suspended()
1943 * should be checked by the caller to find out when.
1946 Session::request_suspend_timecode_transmission ()
1948 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
1953 Session::request_resume_timecode_transmission ()
1955 SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
1960 Session::timecode_transmission_suspended () const
1962 return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
1965 boost::shared_ptr<TransportMaster>
1966 Session::transport_master() const
1968 return TransportMasterManager::instance().current();
1972 Session::transport_master_is_external () const
1974 return config.get_external_sync();
1978 Session::sync_source_changed (SyncSource type, samplepos_t pos, pframes_t cycle_nframes)
1980 /* Runs in process() context */
1982 boost::shared_ptr<TransportMaster> master = TransportMasterManager::instance().current();
1984 /* save value of seamless from before the switch */
1985 _was_seamless = Config->get_seamless_loop ();
1987 if (type == Engine) {
1988 /* JACK cannot support seamless looping at present */
1989 Config->set_seamless_loop (false);
1991 /* reset to whatever the value was before we last switched slaves */
1992 Config->set_seamless_loop (_was_seamless);
1995 if (master->can_loop()) {
1996 request_play_loop (false);
1997 } else if (master->has_loop()) {
1998 request_play_loop (true);
2001 /* slave change, reset any DiskIO block on disk output because it is no
2002 longer valid with a new slave.
2005 DiskReader::set_no_disk_output (false);
2008 we should not be treating specific transport masters as special cases because there maybe > 1 of a particular type
2010 boost::shared_ptr<MTC_TransportMaster> mtc_master = boost::dynamic_pointer_cast<MTC_TransportMaster> (master);
2013 mtc_master->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
2014 MTCSyncStateChanged(mtc_master->locked() );
2016 if (g_atomic_int_compare_and_exchange (&_mtc_active, 1, 0)) {
2017 MTCSyncStateChanged( false );
2019 mtc_status_connection.disconnect ();
2022 boost::shared_ptr<LTC_TransportMaster> ltc_master = boost::dynamic_pointer_cast<LTC_TransportMaster> (master);
2025 ltc_master->ActiveChanged.connect_same_thread (ltc_status_connection, boost::bind (&Session::ltc_status_changed, this, _1));
2026 LTCSyncStateChanged (ltc_master->locked() );
2028 if (g_atomic_int_compare_and_exchange (&_ltc_active, 1, 0)) {
2029 LTCSyncStateChanged( false );
2031 ltc_status_connection.disconnect ();
2035 DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", master));
2037 // need to queue this for next process() cycle
2038 _send_timecode_update = true;
2040 boost::shared_ptr<RouteList> rl = routes.reader();
2041 const bool externally_slaved = transport_master_is_external();
2043 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2044 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2045 if (tr && !tr->is_private_route()) {
2046 tr->set_slaved (externally_slaved);